Eclipse SUMO - Simulation of Urban MObility
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-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 /****************************************************************************/
20 // A logging window for the gui
21 /****************************************************************************/
22 #include <config.h>
23 
24 #include <cassert>
30 #include <fxkeys.h>
31 #include "GUIMessageWindow.h"
32 
33 
34 // ===========================================================================
35 // static members
36 // ===========================================================================
37 
40 FXHiliteStyle* GUIMessageWindow::myStyles = new FXHiliteStyle[8];
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 
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;
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) {
161  std::vector<std::string> viewIDs = main->getViewIDs();
162  if (viewIDs.empty()) {
163  return;
164  }
165  GUIGlChildWindow* const child = main->getViewByID(viewIDs[0]);
166  const FXString text = getText();
167  const GUIGlObject* const glObj = getActiveStringObject(text, pos, lineStart(pos), lineEnd(pos));
168  if (glObj != nullptr) {
169  child->setView(glObj->getGlID());
171  if (getApp()->getKeyState(KEY_Control_L)) {
173  }
174  } else {
175  const int lookback = MIN2(pos, 20);
176  const int start = MAX2(lineStart(pos), pos - lookback);
177  const FXString candidate = text.mid(start, lineEnd(pos) - start);
178  FXint timePos = candidate.find(myTimeText.c_str());
179  if (timePos > -1) {
180  timePos += (int)myTimeText.size() + 1;
181  SUMOTime t = -1;
182  if (pos >= 0 && pos > start + timePos) {
183  t = getTimeString(candidate, timePos);
184  if (t >= 0) {
185  t += myBreakPointOffset;
186  std::vector<SUMOTime> breakpoints = myMainWindow->retrieveBreakpoints();
187  if (std::find(breakpoints.begin(), breakpoints.end(), t) == breakpoints.end()) {
188  breakpoints.push_back(t);
189  std::sort(breakpoints.begin(), breakpoints.end());
190  myMainWindow->setBreakpoints(breakpoints);
191  myMainWindow->setStatusBarText(TLF("Set breakpoint at %", time2string(t)));
192  }
193  }
194  }
195  }
196  }
197  }
198 }
199 
200 
201 void
202 GUIMessageWindow::appendMsg(GUIEventType eType, const std::string& msg) {
203  if (!isEnabled()) {
204  show();
205  }
206  // build the styled message
207  FXint style = 1;
208  switch (eType) {
210  // color: blue
211  style = 0;
212  break;
214  // color: fuchsia
215  style = 7;
216  break;
218  // color: red
219  style = 2;
220  break;
222  // color: yellow
223  style = 3;
224  break;
226  // color: green
227  style = 1;
228  break;
229  default:
230  assert(false);
231  }
232  FXString text(msg.c_str());
233  if (myLocateLinks) {
234  FXint pos = text.find("'");
235  while (pos >= 0) {
236  const GUIGlObject* const glObj = getActiveStringObject(text, pos + 1, 0, text.length());
237  if (glObj != nullptr) {
239  FXString insText = text.left(pos + 1);
240  FXText::appendStyledText(insText, style + 1);
241  text.erase(0, pos + 1);
242  pos = text.find("'");
243  insText = text.left(pos);
244  FXText::appendStyledText(insText, style + 4);
245  text.erase(0, pos);
246  }
247  pos = text.find("'", pos + 1);
248  }
249  // find time links
250  pos = text.find(myTimeText.c_str());
251  const int timeTerm = (int)myTimeText.size() + 1;
252  SUMOTime t = -1;
253  if (pos >= 0) {
254  t = getTimeString(text, pos + timeTerm);
255  }
256  if (t >= 0) {
257  FXString insText = text.left(pos + timeTerm);
258  FXText::appendStyledText(insText, style + 1);
259  text.erase(0, pos + timeTerm);
260  pos = text.find(" ");
261  if (pos < 0) {
262  pos = text.rfind(".");
263  }
264  insText = text.left(pos);
265  FXText::appendStyledText(insText, style + 4);
266  text.erase(0, pos);
267  }
268  }
269  // insert rest of the message
270  FXText::appendStyledText(text, style + 1, true);
271  FXText::setCursorPos(getLength() - 1);
272  FXText::setBottomLine(getLength() - 1);
273  if (isEnabled()) {
274  layout();
275  update();
276  }
277 }
278 
279 
280 void
282  std::string msg = "----------------------------------------------------------------------------------------\n";
283  FXText::appendStyledText(msg.c_str(), (FXint) msg.length(), 1, true);
284  FXText::setCursorPos(getLength() - 1);
285  FXText::setBottomLine(getLength() - 1);
286  if (isEnabled()) {
287  layout();
288  update();
289  }
290 }
291 
292 
293 void
295  if (getLength() == 0) {
296  return;
297  }
298  FXText::removeText(0, getLength() - 1, true);
299  if (isEnabled()) {
300  layout();
301  update();
302  }
303 }
304 
305 
306 void
308  if (myMessageRetriever == nullptr) {
309  // initialize only if registration is requested
315  }
321 }
322 
323 
324 void
331 }
332 
333 
334 long
335 GUIMessageWindow::onKeyPress(FXObject* o, FXSelector sel, void* ptr) {
336  FXEvent* e = (FXEvent*) ptr;
337  // permit ctrl+a, ctrl+c
338  if (e->state & CONTROLMASK) {
339  return FXText::onKeyPress(o, sel, ptr);
340  }
341  return 0;
342 }
343 
344 
345 FXHiliteStyle*
347  return myStyles;
348 }
349 
350 
351 void
353  const FXColor white = FXRGB(0xff, 0xff, 0xff);
354  const FXColor blue = FXRGB(0x00, 0x00, 0x88);
355  const FXColor green = FXRGB(0x00, 0x88, 0x00);
356  const FXColor red = FXRGB(0x88, 0x00, 0x00);
357  const FXColor yellow = FXRGB(0xe6, 0x98, 0x00);
358  const FXColor fuchsia = FXRGB(0x88, 0x00, 0x88);
359  // set separator style
360  myStyles[0].normalForeColor = blue;
361  myStyles[0].normalBackColor = white;
362  myStyles[0].selectForeColor = white;
363  myStyles[0].selectBackColor = blue;
364  myStyles[0].hiliteForeColor = blue;
365  myStyles[0].hiliteBackColor = white;
366  myStyles[0].activeBackColor = white;
367  myStyles[0].style = 0;
368  // set message text style
369  myStyles[1] = myStyles[0];
370  myStyles[1].normalForeColor = green;
371  myStyles[1].selectBackColor = green;
372  myStyles[1].hiliteForeColor = green;
373  myStyles[4] = myStyles[1];
374  myStyles[4].style = STYLE_UNDERLINE;
375  // set error text style
376  myStyles[2] = myStyles[0];
377  myStyles[2].normalForeColor = red;
378  myStyles[2].selectBackColor = red;
379  myStyles[2].hiliteForeColor = red;
380  myStyles[5] = myStyles[2];
381  myStyles[5].style = STYLE_UNDERLINE;
382  // set warning text style
383  myStyles[3] = myStyles[0];
384  myStyles[3].normalForeColor = yellow;
385  myStyles[3].selectBackColor = yellow;
386  myStyles[3].hiliteForeColor = yellow;
387  myStyles[6] = myStyles[3];
388  myStyles[6].style = STYLE_UNDERLINE;
389  // set GLDebug text style
390  myStyles[7] = myStyles[0];
391  myStyles[7].normalForeColor = fuchsia;
392  myStyles[7].selectBackColor = fuchsia;
393  myStyles[7].hiliteForeColor = fuchsia;
394 }
395 
396 /****************************************************************************/
long long int SUMOTime
Definition: GUI.h:35
GUIEventType
Definition: GUIEvent.h:32
@ MESSAGE_OCCURRED
send when a message occured
@ GLDEBUG_OCCURRED
send when a gldebug occured
@ ERROR_OCCURRED
send when a error occured
@ DEBUG_OCCURRED
send when a debug occured
@ WARNING_OCCURRED
send when a warning occured
GUISelectedStorage gSelected
A global holder of selected objects.
FXDEFMAP(GUIMessageWindow) GUIMessageWindowMap[]
#define TL(string)
Definition: MsgHandler.h:315
#define TLF(string,...)
Definition: MsgHandler.h:317
SUMOTime string2time(const std::string &r)
convert string to SUMOTime
Definition: SUMOTime.cpp:46
std::string time2string(SUMOTime t, bool humanReadable)
convert SUMOTime to string (independently of global format setting)
Definition: SUMOTime.cpp:69
#define TIME2STEPS(x)
Definition: SUMOTime.h:57
T MIN2(T a, T b)
Definition: StdDefs.h:76
T MAX2(T a, T b)
Definition: StdDefs.h:82
int main(int argc, char *argv[])
void setView(GUIGlID id)
Centers the view onto the given artifact.
GUIGlID getGlID() const
Returns the numerical id of the object.
Definition: GUIGlObject.h:104
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.
virtual const std::vector< SUMOTime > retrieveBreakpoints() const
retrieve breakpoints if provided by the application
virtual void setBreakpoints(const std::vector< SUMOTime > &)
Sets the breakpoints of the parent application.
virtual void setStatusBarText(const std::string &)
get status bar text (can be implemented in children)
static GUIMainWindow * getInstance()
get instance
A logging window for the gui.
GUIMainWindow * myMainWindow
main window
OutputDevice * myGLDebugRetriever
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
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
OutputDevice * myDebugRetriever
~GUIMessageWindow()
Destructor.
long onKeyPress(FXObject *o, FXSelector sel, void *data)
handle keys
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.
Definition: MsgHandler.cpp:237
static MsgHandler * getGLDebugInstance()
Returns the instance to add GLdebug to.
Definition: MsgHandler.cpp:110
static MsgHandler * getErrorInstance()
Returns the instance to add errors to.
Definition: MsgHandler.cpp:92
static MsgHandler * getDebugInstance()
Returns the instance to add debug to.
Definition: MsgHandler.cpp:101
static MsgHandler * getWarningInstance()
Returns the instance to add warnings to.
Definition: MsgHandler.cpp:79
virtual void removeRetriever(OutputDevice *retriever)
Removes the retriever from the handler.
Definition: MsgHandler.cpp:245
static MsgHandler * getMessageInstance()
Returns the instance to add normal messages to.
Definition: MsgHandler.cpp:66
static std::string to_lower_case(const std::string &str)
Transfers the content to lower case.
Definition: StringUtils.cpp:79