From 327b2ba3b77e7a738ccfbe84c6ca5e9525010630 Mon Sep 17 00:00:00 2001 From: David Faure Date: Fri, 27 Jul 2012 14:17:38 +0200 Subject: Add class QDebugStateSaver for writing QDebug operators correctly Had to move QTextStreamPrivate to a private header, to be able to use its new internal Params struct from qdebug.cpp Change-Id: If28e25f27bbd04b1825a5eb3e2ef83ecad72e7b2 Reviewed-by: Olivier Goffart Reviewed-by: Thiago Macieira --- src/corelib/io/io.pri | 1 + src/corelib/io/qdebug.cpp | 73 ++++++++++++++ src/corelib/io/qdebug.h | 12 +++ src/corelib/io/qtextstream.cpp | 218 ++++++++++------------------------------- src/corelib/io/qtextstream.h | 1 + src/corelib/io/qtextstream_p.h | 185 ++++++++++++++++++++++++++++++++++ 6 files changed, 324 insertions(+), 166 deletions(-) create mode 100644 src/corelib/io/qtextstream_p.h (limited to 'src/corelib') diff --git a/src/corelib/io/io.pri b/src/corelib/io/io.pri index 36c553acec..f1b24e30b2 100644 --- a/src/corelib/io/io.pri +++ b/src/corelib/io/io.pri @@ -22,6 +22,7 @@ HEADERS += \ io/qprocess.h \ io/qprocess_p.h \ io/qtextstream.h \ + io/qtextstream_p.h \ io/qtemporarydir.h \ io/qtemporaryfile.h \ io/qtemporaryfile_p.h \ diff --git a/src/corelib/io/qdebug.cpp b/src/corelib/io/qdebug.cpp index 656f26b0fe..164e22dab2 100644 --- a/src/corelib/io/qdebug.cpp +++ b/src/corelib/io/qdebug.cpp @@ -47,6 +47,9 @@ #endif #include "qdebug.h" +#include + +QT_BEGIN_NAMESPACE // This file is needed to force compilation of QDebug into the kernel library. @@ -170,6 +173,8 @@ between writes. \since 5.0 + + \sa QDebugStateSaver */ /*! @@ -179,6 +184,8 @@ automatic insertion of spaces is disabled. \since 5.0 + + \sa QDebugStateSaver */ /*! @@ -321,3 +328,69 @@ \fn QDebug &QDebug::operator<<(QTextStreamManipulator m) \internal */ + +/*! + \class QDebugStateSaver + + \brief Convenience class for custom QDebug operators + + Saves the settings used by QDebug, and restores them upon destruction. + + The automatic insertion of spaces between writes is one of the settings + that QDebugStateSaver stores for the duration of the current block. + + The settings of the internal QTextStream are also saved and restored, + so that using << hex in a QDebug operator doesn't affect other QDebug + operators. + + \since 5.1 +*/ + +class QDebugStateSaverPrivate +{ +public: + QDebugStateSaverPrivate(QDebug &dbg) + : m_dbg(dbg), + m_spaces(dbg.autoInsertSpaces()), + m_streamParams(dbg.stream->ts.d_ptr->params) + { + } + void restoreState() + { + m_dbg.setAutoInsertSpaces(m_spaces); + m_dbg.stream->ts.d_ptr->params = m_streamParams; + } + + QDebug &m_dbg; + + // QDebug state + const bool m_spaces; + + // QTextStream state + const QTextStreamPrivate::Params m_streamParams; +}; + + +/*! + Creates a QDebugStateSaver instance, which saves the settings + currently used by \a dbg. + + \sa QDebug::setAutoInsertSpaces(), QDebug::autoInsertSpaces() +*/ +QDebugStateSaver::QDebugStateSaver(QDebug &dbg) + : d(new QDebugStateSaverPrivate(dbg)) +{ +} + +/*! + Destroyes a QDebugStateSaver instance, which restores the settings + used by \a dbg when the QDebugStateSaver instance was created. + + \sa QDebug::setAutoInsertSpaces(), QDebug::autoInsertSpaces() +*/ +QDebugStateSaver::~QDebugStateSaver() +{ + d->restoreState(); +} + +QT_END_NAMESPACE diff --git a/src/corelib/io/qdebug.h b/src/corelib/io/qdebug.h index 4c8f961ed8..9618dd5a2f 100644 --- a/src/corelib/io/qdebug.h +++ b/src/corelib/io/qdebug.h @@ -61,6 +61,7 @@ QT_BEGIN_NAMESPACE class Q_CORE_EXPORT QDebug { friend class QMessageLogger; + friend class QDebugStateSaverPrivate; struct Stream { Stream(QIODevice *device) : ts(device), ref(1), type(QtDebugMsg), space(true), message_output(false) {} Stream(QString *string) : ts(string, QIODevice::WriteOnly), ref(1), type(QtDebugMsg), space(true), message_output(false) {} @@ -132,6 +133,17 @@ public: Q_DECLARE_SHARED(QDebug) +class QDebugStateSaverPrivate; +class Q_CORE_EXPORT QDebugStateSaver +{ +public: + QDebugStateSaver(QDebug &dbg); + ~QDebugStateSaver(); +private: + Q_DISABLE_COPY(QDebugStateSaver) + QScopedPointer d; +}; + class QNoDebug { public: diff --git a/src/corelib/io/qtextstream.cpp b/src/corelib/io/qtextstream.cpp index 36de6a283c..8dd635dee8 100644 --- a/src/corelib/io/qtextstream.cpp +++ b/src/corelib/io/qtextstream.cpp @@ -226,12 +226,10 @@ static const int QTEXTSTREAM_BUFFERSIZE = 16384; */ #include "qtextstream.h" +#include "private/qtextstream_p.h" #include "qbuffer.h" #include "qfile.h" #include "qnumeric.h" -#ifndef QT_NO_TEXTCODEC -#include "qtextcodec.h" -#endif #ifndef Q_OS_WINCE #include #endif @@ -315,119 +313,7 @@ QT_END_NAMESPACE QT_BEGIN_NAMESPACE -#ifndef QT_NO_QOBJECT -class QDeviceClosedNotifier : public QObject -{ - Q_OBJECT -public: - inline QDeviceClosedNotifier() - { } - - inline void setupDevice(QTextStream *stream, QIODevice *device) - { - disconnect(); - if (device) - connect(device, SIGNAL(aboutToClose()), this, SLOT(flushStream())); - this->stream = stream; - } - -public Q_SLOTS: - inline void flushStream() { stream->flush(); } - -private: - QTextStream *stream; -}; -#endif - //------------------------------------------------------------------- -class QTextStreamPrivate -{ - Q_DECLARE_PUBLIC(QTextStream) -public: - QTextStreamPrivate(QTextStream *q_ptr); - ~QTextStreamPrivate(); - void reset(); - - // device - QIODevice *device; -#ifndef QT_NO_QOBJECT - QDeviceClosedNotifier deviceClosedNotifier; -#endif - bool deleteDevice; - - // string - QString *string; - int stringOffset; - QIODevice::OpenMode stringOpenMode; - -#ifndef QT_NO_TEXTCODEC - // codec - QTextCodec *codec; - QTextCodec::ConverterState readConverterState; - QTextCodec::ConverterState writeConverterState; - QTextCodec::ConverterState *readConverterSavedState; - bool autoDetectUnicode; -#endif - - // i/o - enum TokenDelimiter { - Space, - NotSpace, - EndOfLine - }; - - QString read(int maxlen); - bool scan(const QChar **ptr, int *tokenLength, - int maxlen, TokenDelimiter delimiter); - inline const QChar *readPtr() const; - inline void consumeLastToken(); - inline void consume(int nchars); - void saveConverterState(qint64 newPos); - void restoreToSavedConverterState(); - int lastTokenSize; - - // Return value type for getNumber() - enum NumberParsingStatus { - npsOk, - npsMissingDigit, - npsInvalidPrefix - }; - - inline bool getChar(QChar *ch); - inline void ungetChar(QChar ch); - NumberParsingStatus getNumber(qulonglong *l); - bool getReal(double *f); - - inline void write(const QString &data); - inline void putString(const QString &ch, bool number = false); - void putNumber(qulonglong number, bool negative); - - // buffers - bool fillReadBuffer(qint64 maxBytes = -1); - void resetReadBuffer(); - void flushWriteBuffer(); - QString writeBuffer; - QString readBuffer; - int readBufferOffset; - int readConverterSavedStateOffset; //the offset between readBufferStartDevicePos and that start of the buffer - qint64 readBufferStartDevicePos; - - // streaming parameters - int realNumberPrecision; - int integerBase; - int fieldWidth; - QChar padChar; - QTextStream::FieldAlignment fieldAlignment; - QTextStream::RealNumberNotation realNumberNotation; - QTextStream::NumberFlags numberFlags; - - // status - QTextStream::Status status; - - QLocale locale; - - QTextStream *q_ptr; -}; /*! \internal @@ -481,10 +367,7 @@ static void copyConverterStateHelper(QTextCodec::ConverterState *dest, } #endif -/*! - \internal -*/ -void QTextStreamPrivate::reset() +void QTextStreamPrivate::Params::reset() { realNumberPrecision = 6; integerBase = 0; @@ -493,6 +376,14 @@ void QTextStreamPrivate::reset() fieldAlignment = QTextStream::AlignRight; realNumberNotation = QTextStream::SmartNotation; numberFlags = 0; +} + +/*! + \internal +*/ +void QTextStreamPrivate::reset() +{ + params.reset(); device = 0; deleteDevice = false; @@ -985,15 +876,17 @@ inline void QTextStreamPrivate::putString(const QString &s, bool number) QString tmp = s; // handle padding - int padSize = fieldWidth - s.size(); + int padSize = params.fieldWidth - s.size(); if (padSize > 0) { - QString pad(padSize, padChar); - if (fieldAlignment == QTextStream::AlignLeft) { - tmp.append(QString(padSize, padChar)); - } else if (fieldAlignment == QTextStream::AlignRight - || fieldAlignment == QTextStream::AlignAccountingStyle) { - tmp.prepend(QString(padSize, padChar)); - if (fieldAlignment == QTextStream::AlignAccountingStyle && number) { + QString pad(padSize, params.padChar); + switch (params.fieldAlignment) { + case QTextStream::AlignLeft: + tmp.append(pad); + break; + case QTextStream::AlignRight: + case QTextStream::AlignAccountingStyle: + tmp.prepend(pad); + if (params.fieldAlignment == QTextStream::AlignAccountingStyle && number) { const QChar sign = s.size() > 0 ? s.at(0) : QChar(); if (sign == locale.negativeSign() || sign == locale.positiveSign()) { QChar *data = tmp.data(); @@ -1001,9 +894,11 @@ inline void QTextStreamPrivate::putString(const QString &s, bool number) data[0] = sign; } } - } else if (fieldAlignment == QTextStream::AlignCenter) { - tmp.prepend(QString(padSize/2, padChar)); - tmp.append(QString(padSize - padSize/2, padChar)); + break; + case QTextStream::AlignCenter: + tmp.prepend(QString(padSize/2, params.padChar)); + tmp.append(QString(padSize - padSize/2, params.padChar)); + break; } } @@ -1175,13 +1070,7 @@ void QTextStream::reset() { Q_D(QTextStream); - d->realNumberPrecision = 6; - d->integerBase = 0; - d->fieldWidth = 0; - d->padChar = QLatin1Char(' '); - d->fieldAlignment = QTextStream::AlignRight; - d->realNumberNotation = QTextStream::SmartNotation; - d->numberFlags = 0; + d->params.reset(); } /*! @@ -1400,7 +1289,7 @@ QString *QTextStream::string() const void QTextStream::setFieldAlignment(FieldAlignment mode) { Q_D(QTextStream); - d->fieldAlignment = mode; + d->params.fieldAlignment = mode; } /*! @@ -1411,7 +1300,7 @@ void QTextStream::setFieldAlignment(FieldAlignment mode) QTextStream::FieldAlignment QTextStream::fieldAlignment() const { Q_D(const QTextStream); - return d->fieldAlignment; + return d->params.fieldAlignment; } /*! @@ -1432,7 +1321,7 @@ QTextStream::FieldAlignment QTextStream::fieldAlignment() const void QTextStream::setPadChar(QChar ch) { Q_D(QTextStream); - d->padChar = ch; + d->params.padChar = ch; } /*! @@ -1443,7 +1332,7 @@ void QTextStream::setPadChar(QChar ch) QChar QTextStream::padChar() const { Q_D(const QTextStream); - return d->padChar; + return d->params.padChar; } /*! @@ -1461,7 +1350,7 @@ QChar QTextStream::padChar() const void QTextStream::setFieldWidth(int width) { Q_D(QTextStream); - d->fieldWidth = width; + d->params.fieldWidth = width; } /*! @@ -1472,7 +1361,7 @@ void QTextStream::setFieldWidth(int width) int QTextStream::fieldWidth() const { Q_D(const QTextStream); - return d->fieldWidth; + return d->params.fieldWidth; } /*! @@ -1486,7 +1375,7 @@ int QTextStream::fieldWidth() const void QTextStream::setNumberFlags(NumberFlags flags) { Q_D(QTextStream); - d->numberFlags = flags; + d->params.numberFlags = flags; } /*! @@ -1497,7 +1386,7 @@ void QTextStream::setNumberFlags(NumberFlags flags) QTextStream::NumberFlags QTextStream::numberFlags() const { Q_D(const QTextStream); - return d->numberFlags; + return d->params.numberFlags; } /*! @@ -1513,7 +1402,7 @@ QTextStream::NumberFlags QTextStream::numberFlags() const void QTextStream::setIntegerBase(int base) { Q_D(QTextStream); - d->integerBase = base; + d->params.integerBase = base; } /*! @@ -1525,7 +1414,7 @@ void QTextStream::setIntegerBase(int base) int QTextStream::integerBase() const { Q_D(const QTextStream); - return d->integerBase; + return d->params.integerBase; } /*! @@ -1539,7 +1428,7 @@ int QTextStream::integerBase() const void QTextStream::setRealNumberNotation(RealNumberNotation notation) { Q_D(QTextStream); - d->realNumberNotation = notation; + d->params.realNumberNotation = notation; } /*! @@ -1550,7 +1439,7 @@ void QTextStream::setRealNumberNotation(RealNumberNotation notation) QTextStream::RealNumberNotation QTextStream::realNumberNotation() const { Q_D(const QTextStream); - return d->realNumberNotation; + return d->params.realNumberNotation; } /*! @@ -1567,10 +1456,10 @@ void QTextStream::setRealNumberPrecision(int precision) Q_D(QTextStream); if (precision < 0) { qWarning("QTextStream::setRealNumberPrecision: Invalid precision (%d)", precision); - d->realNumberPrecision = 6; + d->params.realNumberPrecision = 6; return; } - d->realNumberPrecision = precision; + d->params.realNumberPrecision = precision; } /*! @@ -1582,7 +1471,7 @@ void QTextStream::setRealNumberPrecision(int precision) int QTextStream::realNumberPrecision() const { Q_D(const QTextStream); - return d->realNumberPrecision; + return d->params.realNumberPrecision; } /*! @@ -1722,7 +1611,7 @@ QTextStreamPrivate::NumberParsingStatus QTextStreamPrivate::getNumber(qulonglong consumeLastToken(); // detect int encoding - int base = integerBase; + int base = params.integerBase; if (base == 0) { QChar ch; if (!getChar(&ch)) @@ -2300,6 +2189,7 @@ void QTextStreamPrivate::putNumber(qulonglong number, bool negative) QString result; unsigned flags = 0; + const QTextStream::NumberFlags numberFlags = params.numberFlags; if (numberFlags & QTextStream::ShowBase) flags |= QLocalePrivate::ShowBase; if (numberFlags & QTextStream::ForceSign) @@ -2315,7 +2205,7 @@ void QTextStreamPrivate::putNumber(qulonglong number, bool negative) flags |= QLocalePrivate::ThousandsGroup; const QLocalePrivate *dd = locale.d; - int base = integerBase ? integerBase : 10; + int base = params.integerBase ? params.integerBase : 10; if (negative && base == 10) { result = dd->longLongToString(-static_cast(number), -1, base, -1, flags); @@ -2330,7 +2220,7 @@ void QTextStreamPrivate::putNumber(qulonglong number, bool negative) result = dd->unsLongLongToString(number, -1, base, -1, flags); // workaround for backward compatibility - in octal form with // ShowBase flag set zero should be written as '00' - if (number == 0 && base == 8 && numberFlags & QTextStream::ShowBase + if (number == 0 && base == 8 && params.numberFlags & QTextStream::ShowBase && result == QLatin1String("0")) { result.prepend(QLatin1Char('0')); } @@ -2524,7 +2414,7 @@ QTextStream &QTextStream::operator<<(double f) flags |= QLocalePrivate::Alternate; const QLocalePrivate *dd = d->locale.d; - QString num = dd->doubleToString(f, d->realNumberPrecision, form, -1, flags); + QString num = dd->doubleToString(f, d->params.realNumberPrecision, form, -1, flags); d->putString(num, true); return *this; } @@ -2605,13 +2495,13 @@ QTextStream &QTextStream::operator<<(const void *ptr) { Q_D(QTextStream); CHECK_VALID_STREAM(*this); - int oldBase = d->integerBase; - NumberFlags oldFlags = d->numberFlags; - d->integerBase = 16; - d->numberFlags |= ShowBase; + const int oldBase = d->params.integerBase; + const NumberFlags oldFlags = d->params.numberFlags; + d->params.integerBase = 16; + d->params.numberFlags |= ShowBase; d->putNumber(reinterpret_cast(ptr), false); - d->integerBase = oldBase; - d->numberFlags = oldFlags; + d->params.integerBase = oldBase; + d->params.numberFlags = oldFlags; return *this; } @@ -3130,7 +3020,3 @@ QLocale QTextStream::locale() const QT_END_NAMESPACE -#ifndef QT_NO_QOBJECT -#include "qtextstream.moc" -#endif - diff --git a/src/corelib/io/qtextstream.h b/src/corelib/io/qtextstream.h index cf19721bee..3a26c78be8 100644 --- a/src/corelib/io/qtextstream.h +++ b/src/corelib/io/qtextstream.h @@ -194,6 +194,7 @@ public: private: Q_DISABLE_COPY(QTextStream) + friend class QDebugStateSaverPrivate; QScopedPointer d_ptr; }; diff --git a/src/corelib/io/qtextstream_p.h b/src/corelib/io/qtextstream_p.h new file mode 100644 index 0000000000..d5d5288426 --- /dev/null +++ b/src/corelib/io/qtextstream_p.h @@ -0,0 +1,185 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QTEXTSTREAM_P_H +#define QTEXTSTREAM_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "qtextstream.h" +#ifndef QT_NO_TEXTCODEC +#include "qtextcodec.h" +#endif + +QT_BEGIN_NAMESPACE + +#ifndef QT_NO_QOBJECT +class QDeviceClosedNotifier : public QObject +{ + Q_OBJECT +public: + inline QDeviceClosedNotifier() + { } + + inline void setupDevice(QTextStream *stream, QIODevice *device) + { + disconnect(); + if (device) + connect(device, SIGNAL(aboutToClose()), this, SLOT(flushStream())); + this->stream = stream; + } + +public Q_SLOTS: + inline void flushStream() { stream->flush(); } + +private: + QTextStream *stream; +}; +#endif + +class QTextStreamPrivate +{ + Q_DECLARE_PUBLIC(QTextStream) +public: + QTextStreamPrivate(QTextStream *q_ptr); + ~QTextStreamPrivate(); + void reset(); + + // device + QIODevice *device; +#ifndef QT_NO_QOBJECT + QDeviceClosedNotifier deviceClosedNotifier; +#endif + bool deleteDevice; + + // string + QString *string; + int stringOffset; + QIODevice::OpenMode stringOpenMode; + +#ifndef QT_NO_TEXTCODEC + // codec + QTextCodec *codec; + QTextCodec::ConverterState readConverterState; + QTextCodec::ConverterState writeConverterState; + QTextCodec::ConverterState *readConverterSavedState; + bool autoDetectUnicode; +#endif + + // i/o + enum TokenDelimiter { + Space, + NotSpace, + EndOfLine + }; + + QString read(int maxlen); + bool scan(const QChar **ptr, int *tokenLength, + int maxlen, TokenDelimiter delimiter); + inline const QChar *readPtr() const; + inline void consumeLastToken(); + inline void consume(int nchars); + void saveConverterState(qint64 newPos); + void restoreToSavedConverterState(); + int lastTokenSize; + + // Return value type for getNumber() + enum NumberParsingStatus { + npsOk, + npsMissingDigit, + npsInvalidPrefix + }; + + inline bool getChar(QChar *ch); + inline void ungetChar(QChar ch); + NumberParsingStatus getNumber(qulonglong *l); + bool getReal(double *f); + + inline void write(const QString &data); + inline void putString(const QString &ch, bool number = false); + void putNumber(qulonglong number, bool negative); + + // buffers + bool fillReadBuffer(qint64 maxBytes = -1); + void resetReadBuffer(); + void flushWriteBuffer(); + QString writeBuffer; + QString readBuffer; + int readBufferOffset; + int readConverterSavedStateOffset; //the offset between readBufferStartDevicePos and that start of the buffer + qint64 readBufferStartDevicePos; + + // streaming parameters + class Params + { + public: + void reset(); + + int realNumberPrecision; + int integerBase; + int fieldWidth; + QChar padChar; + QTextStream::FieldAlignment fieldAlignment; + QTextStream::RealNumberNotation realNumberNotation; + QTextStream::NumberFlags numberFlags; + }; + Params params; + + // status + QTextStream::Status status; + + QLocale locale; + + QTextStream *q_ptr; +}; + +QT_END_NAMESPACE + +#endif // QTEXTSTREAM_P_H -- cgit v1.2.3