Eclipse SUMO - Simulation of Urban MObility
Loading...
Searching...
No Matches
GUIMessageWindow.cpp
Go to the documentation of this file.
1/****************************************************************************/
2// Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3// Copyright (C) 2003-2026 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/****************************************************************************/
20// A logging window for the gui
21/****************************************************************************/
22#include <config.h>
23
24#include <cassert>
33#include <fxkeys.h>
34#include "GUIMessageWindow.h"
35
36
37// ===========================================================================
38// static members
39// ===========================================================================
40
43FXHiliteStyle* GUIMessageWindow::myStyles = new FXHiliteStyle[8];
45std::map<std::string, std::string> GUIMessageWindow::myTypeStrings;
46
47// ===========================================================================
48// FOX callback mapping
49// ===========================================================================
50
51FXDEFMAP(GUIMessageWindow) GUIMessageWindowMap[] = {
52 FXMAPFUNC(SEL_KEYPRESS, 0, GUIMessageWindow::onKeyPress),
53 FXMAPFUNC(SEL_RIGHTBUTTONRELEASE, 0, GUIMessageWindow::onRightBtnRelease),
56};
57
58FXIMPLEMENT_ABSTRACT(GUIMessageWindow, FXText, GUIMessageWindowMap, ARRAYNUMBER(GUIMessageWindowMap))
59
60// ===========================================================================
61// method definitions
62// ===========================================================================
63GUIMessageWindow::GUIMessageWindow(FXComposite* parent, GUIMainWindow* mainWindow) :
64 FXText(parent, nullptr, 0, 0, 0, 0, 0, 50),
65 myMainWindow(mainWindow),
66 myErrorRetriever(nullptr),
67 myMessageRetriever(nullptr),
68 myWarningRetriever(nullptr) {
69 setStyled(true);
70 setEditable(false);
71 // fill styles
72 fillStyles();
73 // set styles
74 setHiliteStyles(myStyles);
75 myTimeText = TL(" time");
76 // see GUIGlObject.cpp
77 myTypeStrings[StringUtils::to_lower_case(TL("edge"))] = "edge";
78 myTypeStrings[StringUtils::to_lower_case(TL("lane"))] = "lane";
79 myTypeStrings[StringUtils::to_lower_case(TL("junction"))] = "junction";
80 myTypeStrings[StringUtils::to_lower_case(TL("vehicle"))] = "vehicle";
81 myTypeStrings[StringUtils::to_lower_case(TL("person"))] = "person";
82 myTypeStrings[StringUtils::to_lower_case(TL("tlLogic"))] = "tlLogic";
83 myTypeStrings[StringUtils::to_lower_case(TL("busStop"))] = "busStop";
84 myTypeStrings[StringUtils::to_lower_case(TL("trainStop"))] = "busStop";
85 myTypeStrings[StringUtils::to_lower_case(TL("containerStop"))] = "containerStop";
86 myTypeStrings[StringUtils::to_lower_case(TL("chargingStation"))] = "chargingStation";
87 myTypeStrings[StringUtils::to_lower_case(TL("overheadWireSegment"))] = "overheadWireSegment";
88 myTypeStrings[StringUtils::to_lower_case(TL("parkingArea"))] = "parkingArea";
89}
90
91
98
99
100const GUIGlObject*
101GUIMessageWindow::getActiveStringObject(const FXString& text, const FXint pos, const FXint lineS, const FXint lineE) const {
102 const FXint idS = MAX2(text.rfind(" '", pos), text.rfind("='", pos));
103 const FXint idE = text.find("'", pos);
104 if (idS >= 0 && idE >= 0 && idS >= lineS && idE <= lineE) {
105 FXint typeS = text.rfind(" ", idS - 1);
106 if (typeS >= 0) {
107 if (text.at(typeS + 1) == '(') {
108 typeS++;
109 }
110 std::string type(text.mid(typeS + 1, idS - typeS - 1).lower().text());
111 const auto& tsIt = myTypeStrings.find(type);
112 if (tsIt != myTypeStrings.end()) {
113 type = tsIt->second;
114 }
115 const std::string id(text.mid(idS + 2, idE - idS - 2).text());
116 const std::string typedID = type + ":" + id;
118 //std::cout << " getActiveStringObject '" << typedID << "' o=" << (o == nullptr ? "NULL" : o->getMicrosimID()) << "\n";
119 return o;
120 }
121 }
122 return nullptr;
123}
124
126GUIMessageWindow::getTimeString(const FXString& text, const FXint pos) const {
127 const FXint end = text.find_first_of(" ,", pos + 1);
128 std::string time;
129 if (end >= 0) {
130 time = text.mid(pos, end - pos).text();
131 } else {
132 time = text.mid(pos, text.length() - pos).text();
133 if (time.empty()) {
134 return -1;
135 }
136 if (time.back() == '\n') {
137 time.pop_back();
138 }
139 if (time.empty()) {
140 return -1;
141 }
142 if (time.back() == '.') {
143 time.pop_back();
144 }
145 }
146 if (time.empty()) {
147 return -1;
148 }
149 if (time.front() == ' ') {
150 time = time.substr(1);
151 }
152 //std::cout << "text='" << text.text() << "' pos=" << pos << " time='" << time << "'\n";
153 try {
154 //std::cout << " SUMOTime=" << string2time(time) << "\n";
155 return string2time(time);
156 } catch (...) {
157 return -1;
158 }
159}
160
161
162void
163GUIMessageWindow::setCursorPos(FXint pos, FXbool notify) {
164 FXText::setCursorPos(pos, notify);
165 if (myLocateLinks) {
166 std::vector<std::string> viewIDs = myMainWindow->getViewIDs();
167 if (viewIDs.empty()) {
168 return;
169 }
170 GUIGlChildWindow* const child = myMainWindow->getViewByID(viewIDs[0]);
171 const FXString text = getText();
172 const GUIGlObject* const glObj = getActiveStringObject(text, pos, lineStart(pos), lineEnd(pos));
173 if (glObj != nullptr) {
174 child->setView(glObj->getGlID());
176 if (getApp()->getKeyState(KEY_Control_L)) {
178 }
179 } else if (gSimulation) {
180 const int lookback = MIN2(pos, 20);
181 const int start = MAX2(lineStart(pos), pos - lookback);
182 const FXString candidate = text.mid(start, lineEnd(pos) - start);
183 FXint timePos = candidate.find(myTimeText.c_str());
184 if (timePos > -1) {
185 timePos += (int)myTimeText.size() + 1;
186 if (pos >= 0 && pos > start + timePos) {
187 const SUMOTime t = getTimeString(candidate, timePos);
188 if (t >= 0) {
190 }
191 }
192 }
193 }
194 }
195}
196
197
198void
199GUIMessageWindow::appendMsg(GUIEventType eType, const std::string& msg) {
200 if (!isEnabled()) {
201 show();
202 }
203 // build the styled message
204 FXint style = 1;
205 switch (eType) {
207 // color: blue
208 style = 0;
209 break;
211 // color: fuchsia
212 style = 7;
213 break;
215 // color: red
216 style = 2;
217 break;
219 // color: yellow
220 style = 3;
221 break;
223 // color: green
224 style = 1;
225 break;
226 default:
227 assert(false);
228 }
229 FXString text(msg.c_str());
230 if (myLocateLinks) {
231 FXint pos = text.find("'");
232 while (pos >= 0) {
233 const GUIGlObject* const glObj = getActiveStringObject(text, pos + 1, 0, text.length());
234 if (glObj != nullptr) {
236 FXString insText = text.left(pos + 1);
237 FXText::appendStyledText(insText, style + 1);
238 text.erase(0, pos + 1);
239 pos = text.find("'");
240 insText = text.left(pos);
241 FXText::appendStyledText(insText, style + 4);
242 text.erase(0, pos);
243 }
244 pos = text.find("'", pos + 1);
245 }
246 // find time links
247 pos = text.find(myTimeText.c_str());
248 const int timeTerm = (int)myTimeText.size() + 1;
249 SUMOTime t = -1;
250 if (pos >= 0) {
251 t = getTimeString(text, pos + timeTerm);
252 }
253 if (t >= 0) {
254 FXString insText = text.left(pos + timeTerm);
255 FXText::appendStyledText(insText, style + 1);
256 text.erase(0, pos + timeTerm);
257 pos = text.find(" ");
258 if (pos < 0) {
259 pos = text.rfind(".");
260 }
261 insText = text.left(pos);
262 FXText::appendStyledText(insText, style + 4);
263 text.erase(0, pos);
264 }
265 }
266 // insert rest of the message
267 FXText::appendStyledText(text, style + 1, true);
268 FXText::setCursorPos(getLength() - 1);
269 FXText::setBottomLine(getLength() - 1);
270 if (isEnabled()) {
271 layout();
272 update();
273 }
274}
275
276
277void
279 std::string msg = std::string(100, '-') + "\n";
280 FXText::appendStyledText(msg.c_str(), (FXint) msg.length(), 1, true);
281 FXText::setCursorPos(getLength() - 1);
282 FXText::setBottomLine(getLength() - 1);
283 if (isEnabled()) {
284 layout();
285 update();
286 }
287}
288
289
290void
292 if (getLength() == 0) {
293 return;
294 }
295 FXText::removeText(0, getLength(), true);
296 if (isEnabled()) {
297 layout();
298 update();
299 }
300}
301
302
303void
315
316
317void
323
324
325long
326GUIMessageWindow::onKeyPress(FXObject* o, FXSelector sel, void* ptr) {
327 FXEvent* e = (FXEvent*) ptr;
328 // permit ctrl+a, ctrl+c
329 if (e->state & CONTROLMASK) {
330 return FXText::onKeyPress(o, sel, ptr);
331 }
332 return 0;
333}
334
335
336long
337GUIMessageWindow::onRightBtnRelease(FXObject* o, FXSelector sel, void* ptr) {
338 FXText::onRightBtnRelease(o, sel, ptr);
339 if (!isEnabled()) {
340 return 0;
341 }
342 FXEvent* event = (FXEvent*)ptr;
343 if (event->moved) {
344 return 1;
345 }
346 setFocus();
347 FXMenuPane contextMenu(this);
348 FXMenuCommand* copyCmd = GUIDesigns::buildFXMenuCommandShortcut(&contextMenu, TL("Copy"), "Ctrl+C", TL("Copy selection to clipboard"),
349 GUIIconSubSys::getIcon(GUIIcon::COPY), this, FXText::ID_COPY_SEL);
350 FXMenuCommand* selAllCmd = GUIDesigns::buildFXMenuCommandShortcut(&contextMenu, TL("Select all"), "Ctrl+A", TL("Select all text"),
351 nullptr, this, FXText::ID_SELECT_ALL);
352 if (getSelStartPos() >= getSelEndPos()) {
353 copyCmd->disable();
354 }
355 if (getLength() == 0) {
356 selAllCmd->disable();
357 }
358 new FXMenuSeparator(&contextMenu);
359 FXMenuCommand* clearCmd = GUIDesigns::buildFXMenuCommand(&contextMenu, TL("Clear"), TL("Clear message window"),
361 if (getLength() == 0) {
362 clearCmd->disable();
363 }
364 contextMenu.create();
365 contextMenu.popup(nullptr, event->root_x, event->root_y);
366 getApp()->runModalWhileShown(&contextMenu);
367 return 1;
368}
369
370
371long
372GUIMessageWindow::onCmdClear(FXObject*, FXSelector, void*) {
373 clear();
374 return 1;
375}
376
377
378long
379GUIMessageWindow::onUpdClear(FXObject* sender, FXSelector, void* ptr) {
380 sender->handle(this, getLength() > 0 ? FXSEL(SEL_COMMAND, ID_ENABLE) : FXSEL(SEL_COMMAND, ID_DISABLE), ptr);
381 return 1;
382}
383
384
385FXHiliteStyle*
389
390
391void
393 const FXColor white = FXRGB(0xff, 0xff, 0xff);
394 const FXColor blue = FXRGB(0x00, 0x00, 0x88);
395 const FXColor green = FXRGB(0x00, 0x88, 0x00);
396 const FXColor red = FXRGB(0x88, 0x00, 0x00);
397 const FXColor yellow = FXRGB(0xe6, 0x98, 0x00);
398 const FXColor fuchsia = FXRGB(0x88, 0x00, 0x88);
399 // set separator style
400 myStyles[0].normalForeColor = blue;
401 myStyles[0].normalBackColor = white;
402 myStyles[0].selectForeColor = white;
403 myStyles[0].selectBackColor = blue;
404 myStyles[0].hiliteForeColor = blue;
405 myStyles[0].hiliteBackColor = white;
406 myStyles[0].activeBackColor = white;
407 myStyles[0].style = 0;
408 // set message text style
409 myStyles[1] = myStyles[0];
410 myStyles[1].normalForeColor = green;
411 myStyles[1].selectBackColor = green;
412 myStyles[1].hiliteForeColor = green;
413 myStyles[4] = myStyles[1];
414 myStyles[4].style = STYLE_UNDERLINE;
415 // set error text style
416 myStyles[2] = myStyles[0];
417 myStyles[2].normalForeColor = red;
418 myStyles[2].selectBackColor = red;
419 myStyles[2].hiliteForeColor = red;
420 myStyles[5] = myStyles[2];
421 myStyles[5].style = STYLE_UNDERLINE;
422 // set warning text style
423 myStyles[3] = myStyles[0];
424 myStyles[3].normalForeColor = yellow;
425 myStyles[3].selectBackColor = yellow;
426 myStyles[3].hiliteForeColor = yellow;
427 myStyles[6] = myStyles[3];
428 myStyles[6].style = STYLE_UNDERLINE;
429 // set GLDebug text style
430 myStyles[7] = myStyles[0];
431 myStyles[7].normalForeColor = fuchsia;
432 myStyles[7].selectBackColor = fuchsia;
433 myStyles[7].hiliteForeColor = fuchsia;
434}
435
436/****************************************************************************/
long long int SUMOTime
Definition GUI.h:36
@ MID_CLEARMESSAGEWINDOW
Clear simulation output.
Definition GUIAppEnum.h:369
GUIEventType
Definition GUIEvent.h:32
@ MESSAGE_OCCURRED
send when a message occurred
@ GLDEBUG_OCCURRED
send when a gldebug occurred
@ ERROR_OCCURRED
send when a error occurred
@ DEBUG_OCCURRED
send when a debug occurred
@ WARNING_OCCURRED
send when a warning occurred
GUISelectedStorage gSelected
A global holder of selected objects.
@ CLEARMESSAGEWINDOW
FXDEFMAP(GUIMessageWindow) GUIMessageWindowMap[]
#define TL(string)
Definition MsgHandler.h:304
SUMOTime string2time(const std::string &r)
convert string to SUMOTime
Definition SUMOTime.cpp:46
constexpr SUMOTime TIME2STEPS(double x)
Definition SUMOTime.h:60
bool gSimulation
Definition StdDefs.cpp:32
T MIN2(T a, T b)
Definition StdDefs.h:80
T MAX2(T a, T b)
Definition StdDefs.h:86
static FXMenuCommand * buildFXMenuCommand(FXComposite *p, const std::string &text, FXIcon *icon, FXObject *tgt, FXSelector sel, const bool disable=false)
build menu command
static FXMenuCommand * buildFXMenuCommandShortcut(FXComposite *p, const std::string &text, const std::string &shortcut, const std::string &info, FXIcon *icon, FXObject *tgt, FXSelector sel)
build menu command
void setView(GUIGlID id)
Centers the view onto the given artifact.
GUIGlID getGlID() const
Returns the numerical id of the object.
void unblockObject(GUIGlID id)
Marks an object as unblocked.
GUIGlObject * getObjectBlocking(GUIGlID id) const
Returns the object from the container locking it.
static GUIGlObjectStorage gIDStorage
A single static instance of this class.
static FXIcon * getIcon(const GUIIcon which)
returns a icon previously defined in the enum GUIIcon
virtual void addBreakpoint(SUMOTime)
add breakpoint to the application
GUIGlChildWindow * getViewByID(const std::string &id) const
get specific view by ID
std::vector< std::string > getViewIDs() const
get view IDs
A logging window for the gui.
GUIMainWindow * myMainWindow
main window
void addSeparator()
Adds a a separator to this log window.
OutputDevice * myErrorRetriever
The instances of message retriever encapsulations.
void unregisterMsgHandlers()
unregister message handlers
static SUMOTime myBreakPointOffset
Offset when creating breakpoint by clicking on time links.
void clear()
Clears the window.
void fillStyles()
fill styles
static std::string myTimeText
The time text to look for.
static FXHiliteStyle * myStyles
The text colors used.
static bool myLocateLinks
whether messages are linked to the GUI elements
long onRightBtnRelease(FXObject *o, FXSelector sel, void *data)
handle right button release
long onUpdClear(FXObject *sender, FXSelector, void *data)
handle update of clear command
void appendMsg(GUIEventType eType, const std::string &msg)
Adds new text to the window.
static FXHiliteStyle * getStyles()
The text colors used.
virtual void setCursorPos(FXint pos, FXbool notify=FALSE)
set cursor position over a certain line
SUMOTime getTimeString(const FXString &text, const FXint pos) const
get time string object
static std::map< std::string, std::string > myTypeStrings
The translated type strings text to look for.
OutputDevice * myWarningRetriever
OutputDevice * myMessageRetriever
~GUIMessageWindow()
Destructor.
long onKeyPress(FXObject *o, FXSelector sel, void *data)
handle keys
long onCmdClear(FXObject *, FXSelector, void *)
handle clear command
const GUIGlObject * getActiveStringObject(const FXString &text, const FXint pos, const FXint lineS, const FXint lineE) const
get active string object
void registerMsgHandlers()
register message handlers
void toggleSelection(GUIGlID id)
Toggles selection of an object.
virtual void addRetriever(OutputDevice *retriever)
Adds a further retriever to the instance responsible for a certain msg type.
static MsgHandler * getErrorInstance()
Returns the instance to add errors to.
static MsgHandler * getWarningInstance()
Returns the instance to add warnings to.
virtual void removeRetriever(OutputDevice *retriever)
Removes the retriever from the handler.
static MsgHandler * getMessageInstance()
Returns the instance to add normal messages to.
static std::string to_lower_case(const std::string &str)
Transfers the content to lower case.