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

Last change on this file since 10290 was 10183, checked in by tbretz, 14 years ago
New import.
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 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.