Lumiera  0.pre.03
»edit your freedom«
error-log-display.hpp
Go to the documentation of this file.
1 /*
2  ERROR-LOG-DISPLAY.hpp - display of error messages in a text box
3 
4  Copyright (C)
5  2017, Hermann Vosseler <Ichthyostega@web.de>
6 
7   **Lumiera** is free software; you can redistribute it and/or modify it
8   under the terms of the GNU General Public License as published by the
9   Free Software Foundation; either version 2 of the License, or (at your
10   option) any later version. See the file COPYING for further details.
11 
12 */
13 
14 
50 #ifndef STAGE_WIDGET_ERROR_LOG_DISPLAY_H
51 #define STAGE_WIDGET_ERROR_LOG_DISPLAY_H
52 
53 #include "stage/gtk-base.hpp"
54 #include "stage/style-scheme.hpp"
58 #include "lib/format-string.hpp"
59 #include "lib/symbol.hpp"
60 #include "lib/util.hpp"
61 
62 #include <utility>
63 #include <vector>
64 
65 
66 
67 namespace stage {
68 namespace widget {
69 
70  using util::max;
71  using util::_Fmt;
72  using lib::Literal;
73  using std::make_pair;
74  using std::vector;
75  using std::move;
76 
77  namespace {
78 
79  using Tag = Glib::RefPtr<Gtk::TextBuffer::Tag>;
80 
86  inline void
87  populateStandardTextTags (Glib::RefPtr<TextBuffer::TagTable> tagTable)
88  {
89  Tag errorTag = Gtk::TextBuffer::Tag::create (cuString{TAG_ERROR});
90  errorTag->property_background() = "Yellow";
91  errorTag->property_weight() = PANGO_WEIGHT_BOLD;
92  tagTable->add (errorTag);
93 
94  Tag warnTag = Gtk::TextBuffer::Tag::create (cuString{TAG_WARN});
95  warnTag->property_background() = "LightYellow";
96  tagTable->add (warnTag);
97  }
98  }
99 
100 
101 
102  /*********************************************************************/
115  : public Gtk::ScrolledWindow
116  {
117 
118  using Mark = Glib::RefPtr<Gtk::TextBuffer::Mark>;
119  using Entry = std::pair<Mark,Mark>;
121 
122  using SignalErrorChanged = sigc::signal<void, bool>;
123 
124  vector<Entry> errorMarks_;
125  TextWidget textLog_;
126 
127  SignalErrorChanged errorChangedSignal_;
128 
129 
130  public:
131  ~ErrorLogDisplay() { };
132 
134  : Gtk::ScrolledWindow()
135  , errorMarks_{}
136  , textLog_{}
137  {
138  set_size_request (200, 80); // must be > 50 for the scrollbar to work properly
139  property_expand() = true; // always grab any available additional space
140  set_border_width (10);
141  set_shadow_type (Gtk::SHADOW_NONE);
142 
143  // the vertical scrollbar will always be necessary....
144  set_policy (Gtk::POLICY_AUTOMATIC, Gtk::POLICY_ALWAYS);
145  textLog_.set_editable (false);
146  this->add (textLog_);
147 
148  populateStandardTextTags (textLog_.get_buffer()->get_tag_table());
149  }
150 
151  model::Expander expand;
152  model::Revealer reveal;
153 
154 
156  void
158  {
159  bool shallNotify = this->isError();
160 
161  errorMarks_.clear();
162  size_t lineCnt = max (0, textLog_.get_buffer()->get_line_count() - 1);
163  string placeholder;
164  if (lineCnt > 0)
165  placeholder = _Fmt{_("───════ %d preceding lines removed ════───\n")} % lineCnt;
166  textLog_.get_buffer()->set_text (placeholder); // discard existing content
167 
168  if (shallNotify)
169  errorChangedSignal_.emit (false);
170  }
171 
172 
175  void
176  addInfo (string text)
177  {
178  addEntry (text);
179  }
180 
182  void
183  addWarn (string text)
184  {
185  addEntry ("WARNING: "+text, TAG_WARN);
186  }
187 
195  void
196  addError (string text)
197  {
198  bool shallNotify = not this->isError();
199 
200  errorMarks_.emplace_back(
201  addEntry ("ERROR: "+text, TAG_ERROR));
202  if (not expand.isExpanded())
203  expand (true);
204 
205  if (shallNotify)
206  errorChangedSignal_.emit (true);
207  }
208 
214  void
216  {
217  auto newBuff = Gtk::TextBuffer::create (textLog_.get_buffer()->get_tag_table());
218  vector<Entry> newMarks;
219  for (Entry& entry : errorMarks_)
220  {
221  newBuff->insert (newBuff->end(), "\n");
222  auto pos = newBuff->end();
223  --pos;
224  newMarks.emplace_back(
225  make_pair (
226  newBuff->create_mark (pos, true), // "left gravity" : stays to the left of inserted text
227  newBuff->create_mark (pos, false))); // "right gravity": sticks right behind the inserted text))
228 
229  newBuff->insert (pos // copy from old to new buffer, complete with formatting tag
230  ,entry.first->get_iter()
231  ,entry.second->get_iter()
232  );
233  }
234  // install the reduced new buffer
235  auto oldBuff = textLog_.get_buffer();
236  textLog_.set_buffer(newBuff);
237  swap (errorMarks_, newMarks);
238 
239  // add a marker line to indicate the removed old log contents
240  int oldLines = oldBuff->get_line_count();
241  int newLines = newBuff->get_line_count();
242  ASSERT (oldLines >= newLines);
243  addInfo (_Fmt{_("───════ %d old log lines removed ════───\n")} % (oldLines-newLines));
244  }
245 
246 
248  void
250  {
251  if (not isError()) return;
252 
253  auto buff = textLog_.get_buffer();
254  for (Entry& entry : errorMarks_)
255  {
256  auto begin = entry.first->get_iter();
257  auto end = entry.second->get_iter();
258 
259  buff->remove_tag_by_name(uString{TAG_ERROR}, begin,end);
260  buff->apply_tag_by_name (uString{TAG_WARN}, begin,end);
261  }
262  errorMarks_.clear();
263  errorChangedSignal_.emit (false);
264  }
265 
266 
271  void
273  {
274  textLog_.flash();
275  }
276 
277 
278  /* ======= Error-State ======= */
279 
280  bool
281  isError() const
282  {
283  return not errorMarks_.empty();
284  }
285 
287  SignalErrorChanged
289  {
290  return errorChangedSignal_;
291  }
292 
293 
294 
295  private:/* ===== Internals ===== */
296 
310  Entry
311  addEntry (string const& text, Literal markupTagName =nullptr)
312  {
313  auto buff = textLog_.get_buffer();
314  buff->insert (buff->end(), "\n");
315  auto pos = buff->end();
316  --pos;
317  auto begin = buff->create_mark (pos, true); // "left gravity" : stays to the left of inserted text
318  auto after = buff->create_mark (pos, false); // "right gravity": sticks right behind the inserted text
319  if (markupTagName)
320  buff->insert_with_tag(pos, text, cuString{markupTagName});
321  else
322  buff->insert (pos, text);
323  textLog_.scroll_to (begin);
324  return make_pair (move(begin), move(after));
325  }
326  };
327 
328 
329 }}// namespace stage::widget
330 #endif /*STAGE_WIDGET_ERROR_LOG_DISPLAY_H*/
void addError(string text)
present an error notification prominently.
Major public Interface of the Lumiera GUI.
SignalErrorChanged signalErrorChanged()
signal fired when error state changes
void addInfo(string text)
just add normal information message to buffer, without special markup and without expanding the widge...
Entry addEntry(string const &text, Literal markupTagName=nullptr)
add message entry to the (ever growing) text buffer.
void addWarn(string text)
add an information message, formatted more prominent as warning
AnyPair entry(Query< TY > const &query, typename WrapReturn< TY >::Wrapper &obj)
helper to simplify creating mock table entries, wrapped correctly
inline string literal This is a marker type to indicate that
Definition: symbol.hpp:76
Front-end for printf-style string template interpolation.
A front-end for using printf-style formatting.
Helper components to implement some standard UI-element actions by installing a functor.
Functor component to support the default implementation of revealing an UI-Element.
Decorator to add the ability to display a visual flash action to a GTK widget.
Marker types to indicate a literal string and a Symbol.
Lumiera GTK UI implementation root.
Definition: guifacade.cpp:37
Tiny helper functions and shortcuts to be used everywhere Consider this header to be effectively incl...
void clearInfoMsg()
clear all mere information messages; retain just the previously tagged errors
void clearAll()
empty text buffer and discard all error bookmarks
Functor component to support the default implementation of expanding/collapsing.
void triggerFlash()
temporarily change display style to prompt for attention; set callback-timeout for return to normal s...
Widget to display log and error messages.
void turnError_into_InfoMsg()
visit all errors and downgrade the markup; discard all bookmarks
Definition of access keys for uniform UI styling.
A set of basic GTK includes for the UI.
void populateStandardTextTags(Glib::RefPtr< TextBuffer::TagTable > tagTable)