Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
eclipse
GitHub Repository: eclipse/sumo
Path: blob/main/src/utils/gui/div/GUIMessageWindow.cpp
169684 views
1
/****************************************************************************/
2
// Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3
// Copyright (C) 2003-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 GUIMessageWindow.cpp
15
/// @author Daniel Krajzewicz
16
/// @author Michael Behrisch
17
/// @author Jakob Erdmann
18
/// @date Tue, 25 Nov 2003
19
///
20
// A logging window for the gui
21
/****************************************************************************/
22
#include <config.h>
23
24
#include <cassert>
25
#include <utils/common/MsgHandler.h>
26
#include <utils/gui/globjects/GUIGlObjectStorage.h>
27
#include <utils/gui/windows/GUIGlChildWindow.h>
28
#include <utils/gui/windows/GUIMainWindow.h>
29
#include <utils/gui/div/GUIGlobalSelection.h>
30
#include <fxkeys.h>
31
#include "GUIMessageWindow.h"
32
33
34
// ===========================================================================
35
// static members
36
// ===========================================================================
37
38
bool GUIMessageWindow::myLocateLinks = true;
39
SUMOTime GUIMessageWindow::myBreakPointOffset = TIME2STEPS(-5);
40
FXHiliteStyle* GUIMessageWindow::myStyles = new FXHiliteStyle[8];
41
std::string GUIMessageWindow::myTimeText;
42
std::map<std::string, std::string> GUIMessageWindow::myTypeStrings;
43
44
// ===========================================================================
45
// FOX callback mapping
46
// ===========================================================================
47
48
FXDEFMAP(GUIMessageWindow) GUIMessageWindowMap[] = {
49
FXMAPFUNC(SEL_KEYPRESS, 0, GUIMessageWindow::onKeyPress),
50
};
51
52
FXIMPLEMENT_ABSTRACT(GUIMessageWindow, FXText, GUIMessageWindowMap, ARRAYNUMBER(GUIMessageWindowMap))
53
54
// ===========================================================================
55
// method definitions
56
// ===========================================================================
57
GUIMessageWindow::GUIMessageWindow(FXComposite* parent, GUIMainWindow* mainWindow) :
58
FXText(parent, nullptr, 0, 0, 0, 0, 0, 50),
59
myMainWindow(mainWindow),
60
myErrorRetriever(nullptr),
61
myMessageRetriever(nullptr),
62
myWarningRetriever(nullptr) {
63
setStyled(true);
64
setEditable(false);
65
// fill styles
66
fillStyles();
67
// set styles
68
setHiliteStyles(myStyles);
69
myTimeText = TL(" time");
70
// see GUIGlObject.cpp
71
myTypeStrings[StringUtils::to_lower_case(TL("edge"))] = "edge";
72
myTypeStrings[StringUtils::to_lower_case(TL("lane"))] = "lane";
73
myTypeStrings[StringUtils::to_lower_case(TL("junction"))] = "junction";
74
myTypeStrings[StringUtils::to_lower_case(TL("vehicle"))] = "vehicle";
75
myTypeStrings[StringUtils::to_lower_case(TL("person"))] = "person";
76
myTypeStrings[StringUtils::to_lower_case(TL("tlLogic"))] = "tlLogic";
77
myTypeStrings[StringUtils::to_lower_case(TL("busStop"))] = "busStop";
78
myTypeStrings[StringUtils::to_lower_case(TL("trainStop"))] = "busStop";
79
myTypeStrings[StringUtils::to_lower_case(TL("containerStop"))] = "containerStop";
80
myTypeStrings[StringUtils::to_lower_case(TL("chargingStation"))] = "chargingStation";
81
myTypeStrings[StringUtils::to_lower_case(TL("overheadWireSegment"))] = "overheadWireSegment";
82
myTypeStrings[StringUtils::to_lower_case(TL("parkingArea"))] = "parkingArea";
83
}
84
85
86
GUIMessageWindow::~GUIMessageWindow() {
87
delete[] myStyles;
88
delete myMessageRetriever;
89
delete myErrorRetriever;
90
delete myWarningRetriever;
91
}
92
93
94
const GUIGlObject*
95
GUIMessageWindow::getActiveStringObject(const FXString& text, const FXint pos, const FXint lineS, const FXint lineE) const {
96
const FXint idS = MAX2(text.rfind(" '", pos), text.rfind("='", pos));
97
const FXint idE = text.find("'", pos);
98
if (idS >= 0 && idE >= 0 && idS >= lineS && idE <= lineE) {
99
FXint typeS = text.rfind(" ", idS - 1);
100
if (typeS >= 0) {
101
if (text.at(typeS + 1) == '(') {
102
typeS++;
103
}
104
std::string type(text.mid(typeS + 1, idS - typeS - 1).lower().text());
105
const auto& tsIt = myTypeStrings.find(type);
106
if (tsIt != myTypeStrings.end()) {
107
type = tsIt->second;
108
}
109
const std::string id(text.mid(idS + 2, idE - idS - 2).text());
110
const std::string typedID = type + ":" + id;
111
const GUIGlObject* o = GUIGlObjectStorage::gIDStorage.getObjectBlocking(typedID);
112
//std::cout << " getActiveStringObject '" << typedID << "' o=" << (o == nullptr ? "NULL" : o->getMicrosimID()) << "\n";
113
return o;
114
}
115
}
116
return nullptr;
117
}
118
119
SUMOTime
120
GUIMessageWindow::getTimeString(const FXString& text, const FXint pos) const {
121
const FXint end = text.find_first_of(" ,", pos + 1);
122
std::string time;
123
if (end >= 0) {
124
time = text.mid(pos, end - pos).text();
125
} else {
126
time = text.mid(pos, text.length() - pos).text();
127
if (time.empty()) {
128
return -1;
129
}
130
if (time.back() == '\n') {
131
time.pop_back();
132
}
133
if (time.empty()) {
134
return -1;
135
}
136
if (time.back() == '.') {
137
time.pop_back();
138
}
139
}
140
if (time.empty()) {
141
return -1;
142
}
143
if (time.front() == ' ') {
144
time = time.substr(1);
145
}
146
//std::cout << "text='" << text.text() << "' pos=" << pos << " time='" << time << "'\n";
147
try {
148
//std::cout << " SUMOTime=" << string2time(time) << "\n";
149
return string2time(time);
150
} catch (...) {
151
return -1;
152
}
153
}
154
155
156
void
157
GUIMessageWindow::setCursorPos(FXint pos, FXbool notify) {
158
FXText::setCursorPos(pos, notify);
159
if (myLocateLinks) {
160
std::vector<std::string> viewIDs = myMainWindow->getViewIDs();
161
if (viewIDs.empty()) {
162
return;
163
}
164
GUIGlChildWindow* const child = myMainWindow->getViewByID(viewIDs[0]);
165
const FXString text = getText();
166
const GUIGlObject* const glObj = getActiveStringObject(text, pos, lineStart(pos), lineEnd(pos));
167
if (glObj != nullptr) {
168
child->setView(glObj->getGlID());
169
GUIGlObjectStorage::gIDStorage.unblockObject(glObj->getGlID());
170
if (getApp()->getKeyState(KEY_Control_L)) {
171
gSelected.toggleSelection(glObj->getGlID());
172
}
173
} else if (gSimulation) {
174
const int lookback = MIN2(pos, 20);
175
const int start = MAX2(lineStart(pos), pos - lookback);
176
const FXString candidate = text.mid(start, lineEnd(pos) - start);
177
FXint timePos = candidate.find(myTimeText.c_str());
178
if (timePos > -1) {
179
timePos += (int)myTimeText.size() + 1;
180
if (pos >= 0 && pos > start + timePos) {
181
const SUMOTime t = getTimeString(candidate, timePos);
182
if (t >= 0) {
183
myMainWindow->addBreakpoint(t + myBreakPointOffset);
184
}
185
}
186
}
187
}
188
}
189
}
190
191
192
void
193
GUIMessageWindow::appendMsg(GUIEventType eType, const std::string& msg) {
194
if (!isEnabled()) {
195
show();
196
}
197
// build the styled message
198
FXint style = 1;
199
switch (eType) {
200
case GUIEventType::DEBUG_OCCURRED:
201
// color: blue
202
style = 0;
203
break;
204
case GUIEventType::GLDEBUG_OCCURRED:
205
// color: fuchsia
206
style = 7;
207
break;
208
case GUIEventType::ERROR_OCCURRED:
209
// color: red
210
style = 2;
211
break;
212
case GUIEventType::WARNING_OCCURRED:
213
// color: yellow
214
style = 3;
215
break;
216
case GUIEventType::MESSAGE_OCCURRED:
217
// color: green
218
style = 1;
219
break;
220
default:
221
assert(false);
222
}
223
FXString text(msg.c_str());
224
if (myLocateLinks) {
225
FXint pos = text.find("'");
226
while (pos >= 0) {
227
const GUIGlObject* const glObj = getActiveStringObject(text, pos + 1, 0, text.length());
228
if (glObj != nullptr) {
229
GUIGlObjectStorage::gIDStorage.unblockObject(glObj->getGlID());
230
FXString insText = text.left(pos + 1);
231
FXText::appendStyledText(insText, style + 1);
232
text.erase(0, pos + 1);
233
pos = text.find("'");
234
insText = text.left(pos);
235
FXText::appendStyledText(insText, style + 4);
236
text.erase(0, pos);
237
}
238
pos = text.find("'", pos + 1);
239
}
240
// find time links
241
pos = text.find(myTimeText.c_str());
242
const int timeTerm = (int)myTimeText.size() + 1;
243
SUMOTime t = -1;
244
if (pos >= 0) {
245
t = getTimeString(text, pos + timeTerm);
246
}
247
if (t >= 0) {
248
FXString insText = text.left(pos + timeTerm);
249
FXText::appendStyledText(insText, style + 1);
250
text.erase(0, pos + timeTerm);
251
pos = text.find(" ");
252
if (pos < 0) {
253
pos = text.rfind(".");
254
}
255
insText = text.left(pos);
256
FXText::appendStyledText(insText, style + 4);
257
text.erase(0, pos);
258
}
259
}
260
// insert rest of the message
261
FXText::appendStyledText(text, style + 1, true);
262
FXText::setCursorPos(getLength() - 1);
263
FXText::setBottomLine(getLength() - 1);
264
if (isEnabled()) {
265
layout();
266
update();
267
}
268
}
269
270
271
void
272
GUIMessageWindow::addSeparator() {
273
std::string msg = std::string(100, '-') + "\n";
274
FXText::appendStyledText(msg.c_str(), (FXint) msg.length(), 1, true);
275
FXText::setCursorPos(getLength() - 1);
276
FXText::setBottomLine(getLength() - 1);
277
if (isEnabled()) {
278
layout();
279
update();
280
}
281
}
282
283
284
void
285
GUIMessageWindow::clear() {
286
if (getLength() == 0) {
287
return;
288
}
289
FXText::removeText(0, getLength() - 1, true);
290
if (isEnabled()) {
291
layout();
292
update();
293
}
294
}
295
296
297
void
298
GUIMessageWindow::registerMsgHandlers() {
299
if (myMessageRetriever == nullptr) {
300
// initialize only if registration is requested
301
myMessageRetriever = new MsgOutputDevice(this, GUIEventType::MESSAGE_OCCURRED);
302
myErrorRetriever = new MsgOutputDevice(this, GUIEventType::ERROR_OCCURRED);
303
myWarningRetriever = new MsgOutputDevice(this, GUIEventType::WARNING_OCCURRED);
304
}
305
MsgHandler::getMessageInstance()->addRetriever(myMessageRetriever);
306
MsgHandler::getErrorInstance()->addRetriever(myErrorRetriever);
307
MsgHandler::getWarningInstance()->addRetriever(myWarningRetriever);
308
}
309
310
311
void
312
GUIMessageWindow::unregisterMsgHandlers() {
313
MsgHandler::getMessageInstance()->removeRetriever(myMessageRetriever);
314
MsgHandler::getErrorInstance()->removeRetriever(myErrorRetriever);
315
MsgHandler::getWarningInstance()->removeRetriever(myWarningRetriever);
316
}
317
318
319
long
320
GUIMessageWindow::onKeyPress(FXObject* o, FXSelector sel, void* ptr) {
321
FXEvent* e = (FXEvent*) ptr;
322
// permit ctrl+a, ctrl+c
323
if (e->state & CONTROLMASK) {
324
return FXText::onKeyPress(o, sel, ptr);
325
}
326
return 0;
327
}
328
329
330
FXHiliteStyle*
331
GUIMessageWindow::getStyles() {
332
return myStyles;
333
}
334
335
336
void
337
GUIMessageWindow::fillStyles() {
338
const FXColor white = FXRGB(0xff, 0xff, 0xff);
339
const FXColor blue = FXRGB(0x00, 0x00, 0x88);
340
const FXColor green = FXRGB(0x00, 0x88, 0x00);
341
const FXColor red = FXRGB(0x88, 0x00, 0x00);
342
const FXColor yellow = FXRGB(0xe6, 0x98, 0x00);
343
const FXColor fuchsia = FXRGB(0x88, 0x00, 0x88);
344
// set separator style
345
myStyles[0].normalForeColor = blue;
346
myStyles[0].normalBackColor = white;
347
myStyles[0].selectForeColor = white;
348
myStyles[0].selectBackColor = blue;
349
myStyles[0].hiliteForeColor = blue;
350
myStyles[0].hiliteBackColor = white;
351
myStyles[0].activeBackColor = white;
352
myStyles[0].style = 0;
353
// set message text style
354
myStyles[1] = myStyles[0];
355
myStyles[1].normalForeColor = green;
356
myStyles[1].selectBackColor = green;
357
myStyles[1].hiliteForeColor = green;
358
myStyles[4] = myStyles[1];
359
myStyles[4].style = STYLE_UNDERLINE;
360
// set error text style
361
myStyles[2] = myStyles[0];
362
myStyles[2].normalForeColor = red;
363
myStyles[2].selectBackColor = red;
364
myStyles[2].hiliteForeColor = red;
365
myStyles[5] = myStyles[2];
366
myStyles[5].style = STYLE_UNDERLINE;
367
// set warning text style
368
myStyles[3] = myStyles[0];
369
myStyles[3].normalForeColor = yellow;
370
myStyles[3].selectBackColor = yellow;
371
myStyles[3].hiliteForeColor = yellow;
372
myStyles[6] = myStyles[3];
373
myStyles[6].style = STYLE_UNDERLINE;
374
// set GLDebug text style
375
myStyles[7] = myStyles[0];
376
myStyles[7].normalForeColor = fuchsia;
377
myStyles[7].selectBackColor = fuchsia;
378
myStyles[7].hiliteForeColor = fuchsia;
379
}
380
381
/****************************************************************************/
382
383