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

Last change on this file since 10429 was 10429, checked in by tbretz, 9 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.