source: trunk/FACT++/src/WindowLog.cc@ 10454

Last change on this file since 10454 was 10429, checked in by tbretz, 14 years ago
Moved the tools function into their own namespace to get rid of problems whenlinking with root.
File size: 9.9 KB
Line 
1// **************************************************************************
2/** @class WindowLog
3
4@brief A C++ ostream to an ncurses window supporting attributes and colors
5
6@section References
7
8 - <A HREF="http://www.gnu.org/software/ncurses">GNU Ncurses</A>
9
10@todo
11 improve docu
12
13
14**/
15// **************************************************************************
16#include "WindowLog.h"
17
18#include <iostream>
19#include <algorithm>
20
21#include <curses.h>
22
23#include "tools.h"
24
25using namespace std;
26
27// --------------------------------------------------------------------------
28//
29//! Delete the contents of the backlog
30//
31void WindowLog::EmptyBacklog()
32{
33 fMuxBacklog.lock();
34 fBacklog.clear();
35 fMuxBacklog.unlock();
36}
37
38// --------------------------------------------------------------------------
39//
40//! Display the backlog. If fWindow is NULL then it is flushed to cout
41//! otherwise to the window (including the colors and attributes)
42//!
43//! Access to cout, the backlog and the window is encapsulated in mutices.
44//
45void WindowLog::Display(bool empty)
46{
47 if (!fWindow)
48 {
49 fMuxBacklog.lock();
50 fMuxCout.lock();
51
52 for (unsigned int i=0; i<fBacklog.size(); i++)
53 cout << fBacklog[i];
54 cout.flush();
55
56 if (empty)
57 fBacklog.clear();
58
59 fMuxCout.unlock();
60 fMuxBacklog.unlock();
61 return;
62 }
63
64 int w, h;
65 getmaxyx(fWindow, h, w);
66
67 fMuxBacklog.lock();
68 fMuxWindow.lock();
69 vector<char>::iterator p0 = fBacklog.begin();
70
71 int lines = 0;
72 int x = 0;
73
74 for (unsigned int i=0; i<fBacklog.size(); i++)
75 {
76 if (fAttributes.find(i)!=fAttributes.end())
77 fAttributes[i]==-1 ? wattrset(fWindow, 0) : wattron(fWindow, fAttributes[i]);
78
79 if (fBacklog[i]=='\n')
80 {
81 // The attribute is added to the backlog in WriteBuffer
82 //wattrset(fWindow, 0);
83 lines += x/w + 1;
84 x=0;
85 }
86 wprintw(fWindow, "%c", fBacklog[i]);
87 x++;
88 }
89
90 if (empty)
91 fBacklog.clear();
92
93 fMuxWindow.unlock();
94 fMuxBacklog.unlock();
95
96 lines += x/w;
97}
98
99// --------------------------------------------------------------------------
100//
101//! Open a log-file into which any of the following output is written. If a
102//! log-file is alraedy open it is closed.
103//! before the new file is opened or an old one closed the current buffer
104//! is flushed.
105//!
106//! @param filename
107//! The filename of the file to open
108//!
109//! @returns
110//! Whether the log-file stream is open or not
111//
112bool WindowLog::OpenLogFile(const string &filename)
113{
114 fMuxFile.lock();
115 flush();
116
117 if (fLogFile.is_open())
118 fLogFile.close();
119
120 fLogFile.open(filename);
121 fMuxFile.unlock();
122
123 return fLogFile.is_open();
124}
125
126// --------------------------------------------------------------------------
127//
128//! Close an open log-file
129//
130void WindowLog::CloseLogFile()
131{
132 fMuxFile.lock();
133 fLogFile.close();
134 fMuxFile.unlock();
135}
136
137// --------------------------------------------------------------------------
138//
139//! This is the function which writes the stream physically to a device.
140//! If you want to add a new device this must be done here.
141//!
142//! If the backlog is enabled, the contents are put into the backlog.
143//! if fWindow is NULL the contents are flushed to cout, otherwise
144//! to the window defined by fWindow.
145//!
146//! In addition the contents are flushed to the log-file if open.
147//! If fIsNull is true any output on the screen (cout or fWindow) is
148//! suppressed.
149//!
150//! @todo
151//! Truncate the backlog
152//
153void WindowLog::WriteBuffer()
154{
155 // Store the number of characters in the buffer which should be flushed
156 const int len = fPPtr - fBase;
157
158 // restart writing to the buffer at its first char
159 fPPtr = fBase;
160
161 // If the is nothing to output, we are done
162 if (len<=0)
163 return;
164
165 // FIXME: Truncate backlog!
166
167 // If fWindow is set, output everything to the window, otherwise
168 // to cout
169 const string sout = string(fBase, len);
170
171 if (!fIsNull)
172 {
173 if (fWindow)
174 {
175 fMuxWindow.lock();
176 if (!fIsNull)
177 wprintw(fWindow, "%s", sout.c_str());
178 // If the stream got flushed due to a line break
179 // reset all attributes
180 if (fBase[len-1]=='\n')
181 wattrset(fWindow, 0);
182 fMuxWindow.unlock();
183 }
184 else
185 {
186 fMuxCout.lock();
187 cout << sout;
188 // If the stream got flushed due to a line break
189 // reset all attributes
190 if (fBase[len-1]=='\n')
191 cout << "\033[0m";
192 cout.flush();
193 fMuxCout.unlock();
194 }
195 }
196
197 // Add the buffer to the backlog
198 if (fEnableBacklog)
199 {
200 fMuxBacklog.lock();
201 fBacklog.insert(fBacklog.end(), fBase, fBase+len);
202
203 // If the stream got flushed due to a line break
204 // add the reset of all attributes to the backlog
205 if (fBase[len-1]=='\n')
206 {
207 if (!fWindow)
208 {
209 const char *reset = "\033[0m";
210 fBacklog.insert(fBacklog.end(), reset, reset+4);
211
212 }
213 else
214 fAttributes[fBacklog.size()] = -1;
215 }
216 fMuxBacklog.unlock();
217 }
218
219 // Output everything also to the log-file
220 fMuxFile.lock();
221 fLogFile << sout;
222 fLogFile.flush();
223 fMuxFile.unlock();
224
225 // If we are flushing because of an EOL, we reset also all attributes
226}
227
228// --------------------------------------------------------------------------
229//
230//! This is called to flush the buffer of the streaming devices
231//
232int WindowLog::sync()
233{
234 WriteBuffer();
235 return 0;
236}
237
238// --------------------------------------------------------------------------
239//
240//! This function comes from streambuf and should output the buffer to
241//! the device (flush, endl) or handle a buffer overflow (too many chars)
242//! If a real overflow happens i contains the next chars which doesn't
243//! fit into the buffer anymore.If the buffer is not really filled,
244//! i is EOF(-1).
245//
246int WindowLog::overflow(int i) // i=EOF means not a real overflow
247{
248 *fPPtr++ = (char)i;
249
250 if (fPPtr == fEPtr)
251 WriteBuffer();
252
253 return 0;
254}
255
256// --------------------------------------------------------------------------
257//
258//! Returns the size of the backlog buffer as string.
259//!
260//! @returns
261//! Size of the backlog as a string, e.g. "1k"
262//
263string WindowLog::GetSizeStr() const
264{
265 int s = GetSizeBacklog()/1000;
266 if (s==0)
267 return "0";
268
269 char u = 'k';
270 if (s>999)
271 {
272 s/=1000;
273 u = 'M';
274 }
275 return Tools::Form("%d%c", s, u);
276}
277
278// --------------------------------------------------------------------------
279//
280//! @returns
281//! the ANSI code corresponding to the attributes
282//
283string WindowLog::GetAnsiAttr(int m)
284{
285 if (m==kReset || m==kDefault)
286 return "\033[0m";
287
288 string rc;
289
290 if ((m&COLOR_PAIR(kRed) )==COLOR_PAIR(kRed) ) rc += "\033[31m";
291 if ((m&COLOR_PAIR(kGreen) )==COLOR_PAIR(kGreen) ) rc += "\033[32m";
292 if ((m&COLOR_PAIR(kYellow) )==COLOR_PAIR(kYellow) ) rc += "\033[33m";
293 if ((m&COLOR_PAIR(kBlue) )==COLOR_PAIR(kBlue) ) rc += "\033[34m";
294 if ((m&COLOR_PAIR(kMagenta))==COLOR_PAIR(kMagenta)) rc += "\033[35m";
295 if ((m&COLOR_PAIR(kCyan) )==COLOR_PAIR(kCyan) ) rc += "\033[36m";
296 if ((m&COLOR_PAIR(kWhite) )==COLOR_PAIR(kWhite) ) rc += "\033[0m\033[1m";
297
298 if ((m&kBold )==kBold ) rc += "\033[1m";
299 if ((m&kDim )==kDim ) rc += "\033[2m";
300 if ((m&kUnderline)==kUnderline) rc += "\033[4m";
301 if ((m&kBlink )==kBlink ) rc += "\033[5m";
302
303 return rc;
304}
305
306// --------------------------------------------------------------------------
307//
308//! Add color to the stream according to the attribute. If fWindow is not
309//! set this is an ANSI color code, otherwise the window's output
310//! attributes are set.
311//! It is also added to the backlog. Access to the backlog is encapsulated
312//! into its mutex.
313//
314void WindowLog::AddColor(int m)
315{
316 const int col = COLOR_PAIR(m);
317
318 if (!fWindow)
319 // We don't have to flush here, because the attributes are simply
320 // part of the stream
321 *this << GetAnsiAttr(col);
322 else
323 {
324 // Before we change the attributes we have to flush the screen
325 // otherwise we would have to buffer them until we flush the
326 // contents
327 flush();
328 wattron(fWindow, col);
329 }
330
331 fMuxBacklog.lock();
332 fAttributes[fBacklog.size()] |= col;
333 fMuxBacklog.unlock();
334}
335
336// --------------------------------------------------------------------------
337//
338//! Add attributes to the stream according to the attribute. If fWindow is
339//! not set this is an ANSI code, otherwise the window's output
340//! attributes are set.
341//! It is also added to the backlog. Access to the backlog is encapsulated
342//! into its mutex.
343//
344void WindowLog::AddAttr(int m)
345{
346 if (!fWindow)
347 // We don't have to flush here, because the attributes are simply
348 // part of the stream
349 *this << GetAnsiAttr(m);
350 else
351 {
352 // Before we change the attributes we have to flush the screen
353 // otherwise we would have to buffer them until we flush the
354 // contents
355 flush();
356 m==kReset ? wattrset(fWindow, 0) : wattron(fWindow, m);
357 }
358
359 fMuxBacklog.lock();
360 m==kReset ?
361 fAttributes[fBacklog.size()] = -1 :
362 fAttributes[fBacklog.size()] |= m;
363 fMuxBacklog.unlock();
364}
365
366// --------------------------------------------------------------------------
367//
368//!
369//
370std::ostream &operator<<(std::ostream &lout, WindowLogColor m)
371{
372 WindowLog *log=dynamic_cast<WindowLog*>(lout.rdbuf());
373 if (log)
374 log->AddColor(m);
375 return lout;
376}
377
378// --------------------------------------------------------------------------
379//
380//!
381//
382std::ostream &operator<<(std::ostream &lout, WindowLogAttrs m)
383{
384 WindowLog *log=dynamic_cast<WindowLog*>(lout.rdbuf());
385 if (log)
386 log->AddAttr(m);
387 return lout;
388}
Note: See TracBrowser for help on using the repository browser.