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) Lumiera.org
5  2017, Hermann Vosseler <Ichthyostega@web.de>
6 
7  This program is free software; you can redistribute it and/or
8  modify it under the terms of the GNU General Public License as
9  published by the Free Software Foundation; either version 2 of
10  the License, or (at your option) any later version.
11 
12  This program is distributed in the hope that it will be useful,
13  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  GNU General Public License for more details.
16 
17  You should have received a copy of the GNU General Public License
18  along with this program; if not, write to the Free Software
19  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 
21 */
22 
23 
59 #ifndef STAGE_WIDGET_ERROR_LOG_DISPLAY_H
60 #define STAGE_WIDGET_ERROR_LOG_DISPLAY_H
61 
62 #include "stage/gtk-base.hpp"
63 #include "stage/style-scheme.hpp"
67 #include "lib/format-string.hpp"
68 #include "lib/symbol.hpp"
69 #include "lib/util.hpp"
70 
71 #include <utility>
72 #include <vector>
73 
74 
75 
76 namespace stage {
77 namespace widget {
78 
79  using util::max;
80  using util::_Fmt;
81  using lib::Literal;
82  using std::make_pair;
83  using std::vector;
84  using std::move;
85 
86  namespace {
87 
88  using Tag = Glib::RefPtr<Gtk::TextBuffer::Tag>;
89 
95  inline void
96  populateStandardTextTags (Glib::RefPtr<TextBuffer::TagTable> tagTable)
97  {
98  Tag errorTag = Gtk::TextBuffer::Tag::create (cuString{TAG_ERROR});
99  errorTag->property_background() = "Yellow";
100  errorTag->property_weight() = PANGO_WEIGHT_BOLD;
101  tagTable->add (errorTag);
102 
103  Tag warnTag = Gtk::TextBuffer::Tag::create (cuString{TAG_WARN});
104  warnTag->property_background() = "LightYellow";
105  tagTable->add (warnTag);
106  }
107  }
108 
109 
110 
111  /*********************************************************************/
124  : public Gtk::ScrolledWindow
125  {
126 
127  using Mark = Glib::RefPtr<Gtk::TextBuffer::Mark>;
128  using Entry = std::pair<Mark,Mark>;
130 
131  using SignalErrorChanged = sigc::signal<void, bool>;
132 
133  vector<Entry> errorMarks_;
134  TextWidget textLog_;
135 
136  SignalErrorChanged errorChangedSignal_;
137 
138 
139  public:
140  ~ErrorLogDisplay() { };
141 
143  : Gtk::ScrolledWindow()
144  , errorMarks_{}
145  , textLog_{}
146  {
147  set_size_request (200, 80); // must be > 50 for the scrollbar to work properly
148  property_expand() = true; // always grab any available additional space
149  set_border_width (10);
150  set_shadow_type (Gtk::SHADOW_NONE);
151 
152  // the vertical scrollbar will always be necessary....
153  set_policy (Gtk::POLICY_AUTOMATIC, Gtk::POLICY_ALWAYS);
154  textLog_.set_editable (false);
155  this->add (textLog_);
156 
157  populateStandardTextTags (textLog_.get_buffer()->get_tag_table());
158  }
159 
160  model::Expander expand;
161  model::Revealer reveal;
162 
163 
165  void
167  {
168  bool shallNotify = this->isError();
169 
170  errorMarks_.clear();
171  size_t lineCnt = max (0, textLog_.get_buffer()->get_line_count() - 1);
172  string placeholder;
173  if (lineCnt > 0)
174  placeholder = _Fmt{_("───════ %d preceding lines removed ════───\n")} % lineCnt;
175  textLog_.get_buffer()->set_text (placeholder); // discard existing content
176 
177  if (shallNotify)
178  errorChangedSignal_.emit (false);
179  }
180 
181 
184  void
185  addInfo (string text)
186  {
187  addEntry (text);
188  }
189 
191  void
192  addWarn (string text)
193  {
194  addEntry ("WARNING: "+text, TAG_WARN);
195  }
196 
204  void
205  addError (string text)
206  {
207  bool shallNotify = not this->isError();
208 
209  errorMarks_.emplace_back(
210  addEntry ("ERROR: "+text, TAG_ERROR));
211  if (not expand.isExpanded())
212  expand (true);
213 
214  if (shallNotify)
215  errorChangedSignal_.emit (true);
216  }
217 
223  void
225  {
226  auto newBuff = Gtk::TextBuffer::create (textLog_.get_buffer()->get_tag_table());
227  vector<Entry> newMarks;
228  for (Entry& entry : errorMarks_)
229  {
230  newBuff->insert (newBuff->end(), "\n");
231  auto pos = newBuff->end();
232  --pos;
233  newMarks.emplace_back(
234  make_pair (
235  newBuff->create_mark (pos, true), // "left gravity" : stays to the left of inserted text
236  newBuff->create_mark (pos, false))); // "right gravity": sticks right behind the inserted text))
237 
238  newBuff->insert (pos // copy from old to new buffer, complete with formatting tag
239  ,entry.first->get_iter()
240  ,entry.second->get_iter()
241  );
242  }
243  // install the reduced new buffer
244  auto oldBuff = textLog_.get_buffer();
245  textLog_.set_buffer(newBuff);
246  swap (errorMarks_, newMarks);
247 
248  // add a marker line to indicate the removed old log contents
249  int oldLines = oldBuff->get_line_count();
250  int newLines = newBuff->get_line_count();
251  ASSERT (oldLines >= newLines);
252  addInfo (_Fmt{_("───════ %d old log lines removed ════───\n")} % (oldLines-newLines));
253  }
254 
255 
257  void
259  {
260  if (not isError()) return;
261 
262  auto buff = textLog_.get_buffer();
263  for (Entry& entry : errorMarks_)
264  {
265  auto begin = entry.first->get_iter();
266  auto end = entry.second->get_iter();
267 
268  buff->remove_tag_by_name(uString{TAG_ERROR}, begin,end);
269  buff->apply_tag_by_name (uString{TAG_WARN}, begin,end);
270  }
271  errorMarks_.clear();
272  errorChangedSignal_.emit (false);
273  }
274 
275 
280  void
282  {
283  textLog_.flash();
284  }
285 
286 
287  /* ======= Error-State ======= */
288 
289  bool
290  isError() const
291  {
292  return not errorMarks_.empty();
293  }
294 
296  SignalErrorChanged
298  {
299  return errorChangedSignal_;
300  }
301 
302 
303 
304  private:/* ===== Internals ===== */
305 
319  Entry
320  addEntry (string const& text, Literal markupTagName =nullptr)
321  {
322  auto buff = textLog_.get_buffer();
323  buff->insert (buff->end(), "\n");
324  auto pos = buff->end();
325  --pos;
326  auto begin = buff->create_mark (pos, true); // "left gravity" : stays to the left of inserted text
327  auto after = buff->create_mark (pos, false); // "right gravity": sticks right behind the inserted text
328  if (markupTagName)
329  buff->insert_with_tag(pos, text, cuString{markupTagName});
330  else
331  buff->insert (pos, text);
332  textLog_.scroll_to (begin);
333  return make_pair (move(begin), move(after));
334  }
335  };
336 
337 
338 }}// namespace stage::widget
339 #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:85
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:46
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)