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

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