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
100bool
101GUIMessageWindow::findObjectTypeID(const FXString& text, const FXint pos, const FXint lineS, const FXint lineE, std::string& id, std::string& type) {
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 type = std::string(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 id = std::string(text.mid(idS + 2, idE - idS - 2).text());
116 return true;
117 }
118 }
119 return false;
120}
121
122
123const GUIGlObject*
124GUIMessageWindow::getActiveStringObject(const FXString& text, const FXint pos, const FXint lineS, const FXint lineE) const {
125 std::string id, type;
126 if (findObjectTypeID(text, pos, lineS, lineE, id, type)) {
127 const std::string typedID = type + ":" + id;
129 //std::cout << " getActiveStringObject '" << typedID << "' o=" << (o == nullptr ? "NULL" : o->getMicrosimID()) << "\n";
130 return o;
131 }
132 return nullptr;
133}
134
135
136bool
137GUIMessageWindow::hasActiveStringObject(const FXString& text, const FXint pos) const {
138 std::string id, type;
139 if (findObjectTypeID(text, pos, 0, text.length(), id, type)) {
140 const std::string typedID = type + ":" + id;
142 if (o != nullptr) {
144 return true;
145 } else if (type == "junction") {
146 // some messages may occur before junction GUIGlObjects are built
147 return true;
148 }
149 }
150 return false;
151}
152
153
155GUIMessageWindow::getTimeString(const FXString& text, const FXint pos) const {
156 const FXint end = text.find_first_of(" ,", pos + 1);
157 std::string time;
158 if (end >= 0) {
159 time = text.mid(pos, end - pos).text();
160 } else {
161 time = text.mid(pos, text.length() - pos).text();
162 if (time.empty()) {
163 return -1;
164 }
165 if (time.back() == '\n') {
166 time.pop_back();
167 }
168 if (time.empty()) {
169 return -1;
170 }
171 if (time.back() == '.') {
172 time.pop_back();
173 }
174 }
175 if (time.empty()) {
176 return -1;
177 }
178 if (time.front() == ' ') {
179 time = time.substr(1);
180 }
181 //std::cout << "text='" << text.text() << "' pos=" << pos << " time='" << time << "'\n";
182 try {
183 //std::cout << " SUMOTime=" << string2time(time) << "\n";
184 return string2time(time);
185 } catch (...) {
186 return -1;
187 }
188}
189
190
191void
192GUIMessageWindow::setCursorPos(FXint pos, FXbool notify) {
193 FXText::setCursorPos(pos, notify);
194 if (myLocateLinks) {
195 std::vector<std::string> viewIDs = myMainWindow->getViewIDs();
196 if (viewIDs.empty()) {
197 return;
198 }
199 GUIGlChildWindow* const child = myMainWindow->getViewByID(viewIDs[0]);
200 const FXString text = getText();
201 const GUIGlObject* const glObj = getActiveStringObject(text, pos, lineStart(pos), lineEnd(pos));
202 if (glObj != nullptr) {
203 child->setView(glObj->getGlID());
205 if (getApp()->getKeyState(KEY_Control_L)) {
207 }
208 } else if (gSimulation) {
209 const int lookback = MIN2(pos, 20);
210 const int start = MAX2(lineStart(pos), pos - lookback);
211 const FXString candidate = text.mid(start, lineEnd(pos) - start);
212 FXint timePos = candidate.find(myTimeText.c_str());
213 if (timePos > -1) {
214 timePos += (int)myTimeText.size() + 1;
215 if (pos >= 0 && pos > start + timePos) {
216 const SUMOTime t = getTimeString(candidate, timePos);
217 if (t >= 0) {
219 }
220 }
221 }
222 }
223 }
224}
225
226
227void
228GUIMessageWindow::appendMsg(GUIEventType eType, const std::string& msg) {
229 if (!isEnabled()) {
230 show();
231 }
232 // build the styled message
233 FXint style = 1;
234 switch (eType) {
236 // color: blue
237 style = 0;
238 break;
240 // color: fuchsia
241 style = 7;
242 break;
244 // color: red
245 style = 2;
246 break;
248 // color: yellow
249 style = 3;
250 break;
252 // color: green
253 style = 1;
254 break;
255 default:
256 assert(false);
257 }
258 FXString text(msg.c_str());
259 if (myLocateLinks) {
260 FXint pos = text.find("'");
261 while (pos >= 0) {
262 if (hasActiveStringObject(text, pos + 1)) {
263 FXString insText = text.left(pos + 1);
264 FXText::appendStyledText(insText, style + 1);
265 text.erase(0, pos + 1);
266 pos = text.find("'");
267 insText = text.left(pos);
268 FXText::appendStyledText(insText, style + 4);
269 text.erase(0, pos);
270 }
271 pos = text.find("'", pos + 1);
272 }
273 // find time links
274 pos = text.find(myTimeText.c_str());
275 const int timeTerm = (int)myTimeText.size() + 1;
276 SUMOTime t = -1;
277 if (pos >= 0) {
278 t = getTimeString(text, pos + timeTerm);
279 }
280 if (t >= 0) {
281 FXString insText = text.left(pos + timeTerm);
282 FXText::appendStyledText(insText, style + 1);
283 text.erase(0, pos + timeTerm);
284 pos = text.find(" ");
285 if (pos < 0) {
286 pos = text.rfind(".");
287 }
288 insText = text.left(pos);
289 FXText::appendStyledText(insText, style + 4);
290 text.erase(0, pos);
291 }
292 }
293 // insert rest of the message
294 FXText::appendStyledText(text, style + 1, true);
295 FXText::setCursorPos(getLength() - 1);
296 FXText::setBottomLine(getLength() - 1);
297 if (isEnabled()) {
298 layout();
299 update();
300 }
301}
302
303
304void
306 std::string msg = std::string(100, '-') + "\n";
307 FXText::appendStyledText(msg.c_str(), (FXint) msg.length(), 1, true);
308 FXText::setCursorPos(getLength() - 1);
309 FXText::setBottomLine(getLength() - 1);
310 if (isEnabled()) {
311 layout();
312 update();
313 }
314}
315
316
317void
319 if (getLength() == 0) {
320 return;
321 }
322 FXText::removeText(0, getLength(), true);
323 if (isEnabled()) {
324 layout();
325 update();
326 }
327}
328
329
330void
342
343
344void
350
351
352long
353GUIMessageWindow::onKeyPress(FXObject* o, FXSelector sel, void* ptr) {
354 FXEvent* e = (FXEvent*) ptr;
355 // permit ctrl+a, ctrl+c
356 if (e->state & CONTROLMASK) {
357 return FXText::onKeyPress(o, sel, ptr);
358 }
359 return 0;
360}
361
362
363long
364GUIMessageWindow::onRightBtnRelease(FXObject* o, FXSelector sel, void* ptr) {
365 FXText::onRightBtnRelease(o, sel, ptr);
366 if (!isEnabled()) {
367 return 0;
368 }
369 FXEvent* event = (FXEvent*)ptr;
370 if (event->moved) {
371 return 1;
372 }
373 setFocus();
374 FXMenuPane contextMenu(this);
375 FXMenuCommand* copyCmd = GUIDesigns::buildFXMenuCommandShortcut(&contextMenu, TL("Copy"), "Ctrl+C", TL("Copy selection to clipboard"),
376 GUIIconSubSys::getIcon(GUIIcon::COPY), this, FXText::ID_COPY_SEL);
377 FXMenuCommand* selAllCmd = GUIDesigns::buildFXMenuCommandShortcut(&contextMenu, TL("Select all"), "Ctrl+A", TL("Select all text"),
378 nullptr, this, FXText::ID_SELECT_ALL);
379 if (getSelStartPos() >= getSelEndPos()) {
380 copyCmd->disable();
381 }
382 if (getLength() == 0) {
383 selAllCmd->disable();
384 }
385 new FXMenuSeparator(&contextMenu);
386 FXMenuCommand* clearCmd = GUIDesigns::buildFXMenuCommand(&contextMenu, TL("Clear"), TL("Clear message window"),
388 if (getLength() == 0) {
389 clearCmd->disable();
390 }
391 contextMenu.create();
392 contextMenu.popup(nullptr, event->root_x, event->root_y);
393 getApp()->runModalWhileShown(&contextMenu);
394 return 1;
395}
396
397
398long
399GUIMessageWindow::onCmdClear(FXObject*, FXSelector, void*) {
400 clear();
401 return 1;
402}
403
404
405long
406GUIMessageWindow::onUpdClear(FXObject* sender, FXSelector, void* ptr) {
407 sender->handle(this, getLength() > 0 ? FXSEL(SEL_COMMAND, ID_ENABLE) : FXSEL(SEL_COMMAND, ID_DISABLE), ptr);
408 return 1;
409}
410
411
412FXHiliteStyle*
416
417
418void
420 const FXColor white = FXRGB(0xff, 0xff, 0xff);
421 const FXColor blue = FXRGB(0x00, 0x00, 0x88);
422 const FXColor green = FXRGB(0x00, 0x88, 0x00);
423 const FXColor red = FXRGB(0x88, 0x00, 0x00);
424 const FXColor yellow = FXRGB(0xe6, 0x98, 0x00);
425 const FXColor fuchsia = FXRGB(0x88, 0x00, 0x88);
426 // set separator style
427 myStyles[0].normalForeColor = blue;
428 myStyles[0].normalBackColor = white;
429 myStyles[0].selectForeColor = white;
430 myStyles[0].selectBackColor = blue;
431 myStyles[0].hiliteForeColor = blue;
432 myStyles[0].hiliteBackColor = white;
433 myStyles[0].activeBackColor = white;
434 myStyles[0].style = 0;
435 // set message text style
436 myStyles[1] = myStyles[0];
437 myStyles[1].normalForeColor = green;
438 myStyles[1].selectBackColor = green;
439 myStyles[1].hiliteForeColor = green;
440 myStyles[4] = myStyles[1];
441 myStyles[4].style = STYLE_UNDERLINE;
442 // set error text style
443 myStyles[2] = myStyles[0];
444 myStyles[2].normalForeColor = red;
445 myStyles[2].selectBackColor = red;
446 myStyles[2].hiliteForeColor = red;
447 myStyles[5] = myStyles[2];
448 myStyles[5].style = STYLE_UNDERLINE;
449 // set warning text style
450 myStyles[3] = myStyles[0];
451 myStyles[3].normalForeColor = yellow;
452 myStyles[3].selectBackColor = yellow;
453 myStyles[3].hiliteForeColor = yellow;
454 myStyles[6] = myStyles[3];
455 myStyles[6].style = STYLE_UNDERLINE;
456 // set GLDebug text style
457 myStyles[7] = myStyles[0];
458 myStyles[7].normalForeColor = fuchsia;
459 myStyles[7].selectBackColor = fuchsia;
460 myStyles[7].hiliteForeColor = fuchsia;
461}
462
463/****************************************************************************/
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
static bool findObjectTypeID(const FXString &text, const FXint pos, const FXint lineS, const FXint lineE, std::string &id, std::string &type)
get active string object
~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
bool hasActiveStringObject(const FXString &text, const FXint pos) const
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.