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

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