source: branches/vendor/trolltech/qt/current/tools/xmlpatterns/qcoloroutput.cpp @ 2

Last change on this file since 2 was 2, checked in by Dmitry A. Kuminov, 12 years ago

Initially imported qt-all-opensource-src-4.5.1 from Trolltech.

File size: 11.1 KB
Line 
1/****************************************************************************
2 * ** * ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
3** Contact: Qt Software Information (qt-info@nokia.com)
4 * **
5 * ** This file is part of the Patternist project on Trolltech Labs.
6 * **
7 * ** $QT_BEGIN_LICENSE:LGPL$
8** Commercial Usage
9** Licensees holding valid Qt Commercial licenses may use this file in
10** accordance with the Qt Commercial License Agreement provided with the
11** Software or, alternatively, in accordance with the terms contained in
12** a written agreement between you and Nokia.
13**
14** GNU Lesser General Public License Usage
15** Alternatively, this file may be used under the terms of the GNU Lesser
16** General Public License version 2.1 as published by the Free Software
17** Foundation and appearing in the file LICENSE.LGPL included in the
18** packaging of this file.  Please review the following information to
19** ensure the GNU Lesser General Public License version 2.1 requirements
20** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
21**
22** In addition, as a special exception, Nokia gives you certain
23** additional rights. These rights are described in the Nokia Qt LGPL
24** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
25** package.
26**
27** GNU General Public License Usage
28** Alternatively, this file may be used under the terms of the GNU
29** General Public License version 3.0 as published by the Free Software
30** Foundation and appearing in the file LICENSE.GPL included in the
31** packaging of this file.  Please review the following information to
32** ensure the GNU General Public License version 3.0 requirements will be
33** met: http://www.gnu.org/copyleft/gpl.html.
34**
35** If you are unsure which license is appropriate for your use, please
36** contact the sales department at qt-sales@nokia.com.
37** $QT_END_LICENSE$
38 * **
39 * ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
40 * ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
41 * **
42 * ****************************************************************************/
43
44#include <QFile>
45#include <QHash>
46#include <QTextCodec>
47
48#include "qcoloroutput_p.h"
49
50// TODO: rename insertMapping() to insertColorMapping()
51// TODO: Use a smart pointer for managing ColorOutputPrivate *d;
52// TODO: break out the C++ example into a snippet file
53
54/* This include must appear here, because if it appears at the beginning of the file for
55 * instance, it breaks build -- "qglobal.h:628: error: template with
56 * C linkage" -- on Mac OS X 10.4. */
57#ifndef Q_OS_WIN
58#include <unistd.h>
59#endif
60
61QT_BEGIN_NAMESPACE
62
63using namespace QPatternist;
64
65namespace QPatternist
66{
67    class ColorOutputPrivate
68    {
69    public:
70        ColorOutputPrivate() : currentColorID(-1)
71
72        {
73            /* - QIODevice::Unbuffered because we want it to appear when the user actually calls, performance
74             *   is considered of lower priority.
75             */
76            m_out.open(stderr, QIODevice::WriteOnly | QIODevice::Unbuffered);
77
78            coloringEnabled = isColoringPossible();
79        }
80
81        ColorOutput::ColorMapping   colorMapping;
82        int                         currentColorID;
83        bool                        coloringEnabled;
84
85        static const char *const foregrounds[];
86        static const char *const backgrounds[];
87
88        inline void write(const QString &msg)
89        {
90            m_out.write(msg.toLocal8Bit());
91        }
92
93        static QString escapeCode(const QString &in)
94        {
95            QString result;
96            result.append(QChar(0x1B));
97            result.append(QLatin1Char('['));
98            result.append(in);
99            result.append(QLatin1Char('m'));
100            return result;
101        }
102
103    private:
104        QFile                       m_out;
105
106        /*!
107         Returns true if it's suitable to send colored output to \c stderr.
108         */
109        inline bool isColoringPossible() const
110        {
111#           if defined(Q_OS_WIN32) || defined(Q_OS_WINCE)
112                /* Windows doesn't at all support ANSI escape codes, unless
113                 * the user install a "device driver". See the Wikipedia links in the
114                 * class documentation for details. */
115                return false;
116#           else
117                /* We use QFile::handle() to get the file descriptor. It's a bit unsure
118                 * whether it's 2 on all platforms and in all cases, so hopefully this layer
119                 * of abstraction helps handle such cases. */
120                return isatty(m_out.handle());
121#           endif
122        }
123    };
124}
125
126const char *const ColorOutputPrivate::foregrounds[] =
127{
128    "0;30",
129    "0;34",
130    "0;32",
131    "0;36",
132    "0;31",
133    "0;35",
134    "0;33",
135    "0;37",
136    "1;30",
137    "1;34",
138    "1;32",
139    "1;36",
140    "1;31",
141    "1;35",
142    "1;33",
143    "1;37"
144};
145
146const char *const ColorOutputPrivate::backgrounds[] =
147{
148    "0;40",
149    "0;44",
150    "0;42",
151    "0;46",
152    "0;41",
153    "0;45",
154    "0;43"
155};
156
157/*!
158 \since 4.4
159 \nonreentrant
160 \brief Outputs colored messages to \c stderr.
161 \internal
162
163 ColorOutput is a convenience class for outputting messages to \c stderr
164 using color escape codes, as mandated in ECMA-48. ColorOutput will only
165 color output when it is detected to be suitable. For instance, if \c stderr is
166 detected to be attached to a file instead of a TTY, no coloring will be done.
167
168 ColorOutput does its best attempt. but it is generally undefined what coloring
169 or effect the various coloring flags has. It depends strongly on what terminal
170 software that is being used.
171
172 When using `echo -e 'my escape sequence'`, \033 works as an initiator but not
173 when printing from a C++ program, despite having escaped the backslash.
174 That's why we below use characters with value 0x1B.
175
176 It can be convenient to subclass ColorOutput with a private scope, such that the
177 functions are directly available in the class using it.
178
179 \section1 Usage
180
181 To output messages, call write() or writeUncolored(). write() takes as second
182 argument an integer, which ColorOutput uses as a lookup key to find the color
183 it should color the text in. The mapping from keys to colors is done using
184 insertMapping(). Typically this is used by having enums for the various kinds
185 of messages, which subsequently are registered.
186
187 \code
188 enum MyMessage
189 {
190    Error,
191    Important
192 };
193
194 ColorOutput output;
195 output.insertMapping(Error, ColorOutput::RedForeground);
196 output.insertMapping(Import, ColorOutput::BlueForeground);
197
198 output.write("This is important", Important);
199 output.write("Jack, I'm only the selected official!", Error);
200 \endcode
201
202 \sa {http://tldp.org/HOWTO/Bash-Prompt-HOWTO/x329.html}                        {Bash Prompt HOWTO, 6.1. Colours}
203     {http://linuxgazette.net/issue51/livingston-blade.html}                    {Linux Gazette, Tweaking Eterm, Edward Livingston-Blade}
204     {http://www.ecma-international.org/publications/standards/Ecma-048.htm}    {Standard ECMA-48, Control Functions for Coded Character Sets, ECMA International},
205     {http://en.wikipedia.org/wiki/ANSI_escape_code}                            {Wikipedia, ANSI escape code}
206     {http://linuxgazette.net/issue65/padala.html}                              {Linux Gazette, So You Like Color!, Pradeep Padala}
207 */
208
209/*!
210 \enum ColorOutput::ColorCode
211
212 \value DefaultColor ColorOutput performs no coloring. This typically means black on white
213                     or white on black, depending on the settings of the user's terminal.
214 */
215
216/*!
217 Sets the color mapping to be \a cMapping.
218
219 Negative values are disallowed.
220
221 \sa colorMapping(), insertMapping()
222 */
223void ColorOutput::setColorMapping(const ColorMapping &cMapping)
224{
225    d->colorMapping = cMapping;
226}
227
228/*!
229 Returns the color mappings in use.
230
231 \sa setColorMapping(), insertMapping()
232 */
233ColorOutput::ColorMapping ColorOutput::colorMapping() const
234{
235    return d->colorMapping;
236}
237
238/*!
239  Constructs a ColorOutput instance, ready for use.
240 */
241ColorOutput::ColorOutput() : d(new ColorOutputPrivate())
242{
243}
244
245/*!
246 Destructs this ColorOutput instance.
247 */
248ColorOutput::~ColorOutput()
249{
250    delete d;
251}
252
253/*!
254 Sends \a message to \c stderr, using the color looked up in colorMapping() using \a colorID.
255
256 If \a color isn't available in colorMapping(), result and behavior is undefined.
257
258 If \a colorID is 0, which is the default value, the previously used coloring is used. ColorOutput
259 is initialized to not color at all.
260
261 If \a message is empty, effects are undefined.
262
263 \a message will be printed as is. For instance, no line endings will be inserted.
264 */
265void ColorOutput::write(const QString &message, int colorID)
266{
267    d->write(colorify(message, colorID));
268}
269
270/*!
271 Writes \a message to \c stderr as if for instance
272 QTextStream would have been used, and adds a line ending at the end.
273
274 This function can be practical to use such that one can use ColorOutput for all forms of writing.
275 */
276void ColorOutput::writeUncolored(const QString &message)
277{
278    d->write(message + QLatin1Char('\n'));
279}
280
281/*!
282 Treats \a message and \a colorID identically to write(), but instead of writing
283 \a message to \c stderr, it is prepared for being written to \c stderr, but is then
284 returned.
285
286 This is useful when the colored string is inserted into a translated string(dividing
287 the string into several small strings prevents proper translation).
288 */
289QString ColorOutput::colorify(const QString &message, int colorID) const
290{
291    Q_ASSERT_X(colorID == -1 || d->colorMapping.contains(colorID), Q_FUNC_INFO,
292               qPrintable(QString::fromLatin1("There is no color registered by id %1").arg(colorID)));
293    Q_ASSERT_X(!message.isEmpty(), Q_FUNC_INFO, "It makes no sense to attempt to print an empty string.");
294
295    if(colorID != -1)
296        d->currentColorID = colorID;
297
298    if(d->coloringEnabled && colorID != -1)
299    {
300        const int color(d->colorMapping.value(colorID));
301
302        /* If DefaultColor is set, we don't want to color it. */
303        if(color & DefaultColor)
304            return message;
305
306        const int foregroundCode = (int(color) & ForegroundMask) >> ForegroundShift;
307        const int backgroundCode = (int(color) & BackgroundMask) >> BackgroundShift;
308        QString finalMessage;
309        bool closureNeeded = false;
310
311        if(foregroundCode)
312        {
313            finalMessage.append(ColorOutputPrivate::escapeCode(QLatin1String(ColorOutputPrivate::foregrounds[foregroundCode - 1])));
314            closureNeeded = true;
315        }
316
317        if(backgroundCode)
318        {
319            finalMessage.append(ColorOutputPrivate::escapeCode(QLatin1String(ColorOutputPrivate::backgrounds[backgroundCode - 1])));
320            closureNeeded = true;
321        }
322
323        finalMessage.append(message);
324
325        if(closureNeeded)
326        {
327            finalMessage.append(QChar(0x1B));
328            finalMessage.append(QLatin1String("[0m"));
329        }
330
331        return finalMessage;
332    }
333    else
334        return message;
335}
336
337/*!
338  Adds a color mapping from \a colorID to \a colorCode, for this ColorOutput instance.
339
340  This is a convenience function for creating a ColorOutput::ColorMapping instance and
341  calling setColorMapping().
342
343  \sa colorMapping(), setColorMapping()
344 */
345void ColorOutput::insertMapping(int colorID, const ColorCode colorCode)
346{
347    d->colorMapping.insert(colorID, colorCode);
348}
349
350QT_END_NAMESPACE
Note: See TracBrowser for help on using the repository browser.