diff options
-rw-r--r-- | src/qml/qml/qml.pri | 6 | ||||
-rw-r--r-- | src/qml/qml/qqmlengine.cpp | 2 | ||||
-rw-r--r-- | src/qml/qml/qqmlloggingcategory.cpp | 128 | ||||
-rw-r--r-- | src/qml/qml/qqmlloggingcategory_p.h | 89 | ||||
-rw-r--r-- | src/qml/qml/v8/qqmlbuiltinfunctions.cpp | 25 | ||||
-rw-r--r-- | tests/auto/qml/qqmlconsole/data/categorized_logging.qml | 65 | ||||
-rw-r--r-- | tests/auto/qml/qqmlconsole/tst_qqmlconsole.cpp | 36 | ||||
-rw-r--r-- | tests/auto/shared/util.cpp | 11 | ||||
-rw-r--r-- | tests/auto/shared/util.h | 5 |
9 files changed, 358 insertions, 9 deletions
diff --git a/src/qml/qml/qml.pri b/src/qml/qml/qml.pri index 87be140cbb..4244b16210 100644 --- a/src/qml/qml/qml.pri +++ b/src/qml/qml/qml.pri @@ -49,7 +49,8 @@ SOURCES += \ $$PWD/qqmlfileselector.cpp \ $$PWD/qqmlobjectcreator.cpp \ $$PWD/qqmldirparser.cpp \ - $$PWD/qqmldelayedcallqueue.cpp + $$PWD/qqmldelayedcallqueue.cpp \ + $$PWD/qqmlloggingcategory.cpp HEADERS += \ $$PWD/qqmlglobal_p.h \ @@ -121,7 +122,8 @@ HEADERS += \ $$PWD/qqmlfileselector.h \ $$PWD/qqmlobjectcreator_p.h \ $$PWD/qqmldirparser_p.h \ - $$PWD/qqmldelayedcallqueue_p.h + $$PWD/qqmldelayedcallqueue_p.h \ + $$PWD/qqmlloggingcategory_p.h include(ftw/ftw.pri) include(v8/v8.pri) diff --git a/src/qml/qml/qqmlengine.cpp b/src/qml/qml/qqmlengine.cpp index 48832f3b07..4acc74ee43 100644 --- a/src/qml/qml/qqmlengine.cpp +++ b/src/qml/qml/qqmlengine.cpp @@ -89,6 +89,7 @@ #include <private/qqmlobjectmodel_p.h> #include <private/qquickworkerscript_p.h> #include <private/qqmlinstantiator_p.h> +#include <private/qqmlloggingcategory_p.h> #ifdef Q_OS_WIN // for %APPDATA% # include <qt_windows.h> @@ -184,6 +185,7 @@ void QQmlEnginePrivate::registerBaseTypes(const char *uri, int versionMajor, int qmlRegisterType<QQmlInstantiator>(uri, versionMajor, (versionMinor < 1 ? 1 : versionMinor), "Instantiator"); //Only available in >=2.1 qmlRegisterCustomType<QQmlConnections>(uri, versionMajor, versionMinor,"Connections", new QQmlConnectionsParser); qmlRegisterType<QQmlInstanceModel>(); + qmlRegisterType<QQmlLoggingCategory>(uri, versionMajor, (versionMinor < 8 ? 8 : versionMinor), "LoggingCategory"); //Only available in >=2.8 } diff --git a/src/qml/qml/qqmlloggingcategory.cpp b/src/qml/qml/qqmlloggingcategory.cpp new file mode 100644 index 0000000000..88cf14cba0 --- /dev/null +++ b/src/qml/qml/qqmlloggingcategory.cpp @@ -0,0 +1,128 @@ +/**************************************************************************** +** +** Copyright (C) 2016 Pelagicore AG +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQml 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 The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/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 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qqmlloggingcategory_p.h" + +#include <QtQml/qqmlinfo.h> + +/*! + \qmltype LoggingCategory + \ingroup qml-utility-elements + \inqmlmodule QtQml + \brief Defines a logging category in QML + \since 5.8 + + A logging category can be passed to console.log() and friends as the first argument. + If supplied to to the logger the LoggingCategory's name will be used as Logging Category + otherwise the default logging category will be used. + + \qml + import QtQuick 2.8 + + Item { + LoggingCategory { + id: category + name: "com.qt.category" + } + + Component.onCompleted: { + console.log(category, "message"); + } + } + \endqml + + \note As the creation of objects is expensive, it is encouraged to put the needed + LoggingCategory definitions into a singleton and import this where needed. + + \sa QLoggingCategory +*/ + +/*! + \qmlproperty string QtQml::LoggingCategory::name + + Holds the name of the logging category. + + \note This property needs to be set when declaring the LoggingCategory + and cannot be changed later. + + \sa QLoggingCategory::name() +*/ + +QQmlLoggingCategory::QQmlLoggingCategory(QObject *parent) + : QObject(parent) + , m_initialized(false) +{ +} + +QQmlLoggingCategory::~QQmlLoggingCategory() +{ +} + +QString QQmlLoggingCategory::name() const +{ + return QString::fromUtf8(m_name); +} + +QLoggingCategory *QQmlLoggingCategory::category() const +{ + return m_category.data(); +} + +void QQmlLoggingCategory::classBegin() +{ +} + +void QQmlLoggingCategory::componentComplete() +{ + m_initialized = true; + if (m_name.isNull()) + qmlInfo(this) << QString(QLatin1String("Declaring the name of the LoggingCategory is mandatory and cannot be changed later !")); +} + +void QQmlLoggingCategory::setName(const QString &name) +{ + if (m_initialized) { + qmlInfo(this) << QString(QLatin1String("The name of a LoggingCategory cannot be changed after the Item is created")); + return; + } + + m_name = name.toUtf8(); + QScopedPointer<QLoggingCategory> category(new QLoggingCategory(m_name.constData())); + m_category.swap(category); +} diff --git a/src/qml/qml/qqmlloggingcategory_p.h b/src/qml/qml/qqmlloggingcategory_p.h new file mode 100644 index 0000000000..2b7f2f5b53 --- /dev/null +++ b/src/qml/qml/qqmlloggingcategory_p.h @@ -0,0 +1,89 @@ +/**************************************************************************** +** +** Copyright (C) 2016 Pelagicore AG +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQml 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 The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/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 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QQMLLOGGINGCATEGORY_P_H +#define QQMLLOGGINGCATEGORY_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 <QtCore/qobject.h> +#include <QtCore/qstring.h> +#include <QtCore/qloggingcategory.h> + +#include <QtQml/qqmlparserstatus.h> + +QT_BEGIN_NAMESPACE + +class QQmlLoggingCategory : public QObject, public QQmlParserStatus +{ + Q_OBJECT + Q_INTERFACES(QQmlParserStatus) + + Q_PROPERTY(QString name READ name WRITE setName) + +public: + QQmlLoggingCategory(QObject *parent = 0); + virtual ~QQmlLoggingCategory(); + + QString name() const; + void setName(const QString &name); + + QLoggingCategory *category() const; + + void classBegin() override; + void componentComplete() override; + +private: + QByteArray m_name; + QScopedPointer<QLoggingCategory> m_category; + bool m_initialized; +}; + +QT_END_NAMESPACE + +#endif // QQMLLOGGINGCATEGORY_H diff --git a/src/qml/qml/v8/qqmlbuiltinfunctions.cpp b/src/qml/qml/v8/qqmlbuiltinfunctions.cpp index 76a900c846..edc83b3bf1 100644 --- a/src/qml/qml/v8/qqmlbuiltinfunctions.cpp +++ b/src/qml/qml/v8/qqmlbuiltinfunctions.cpp @@ -42,6 +42,7 @@ #include <QtQml/qqmlcomponent.h> #include <private/qqmlengine_p.h> #include <private/qqmlcomponent_p.h> +#include <private/qqmlloggingcategory_p.h> #include <private/qqmlstringconverters_p.h> #include <private/qqmllocale_p.h> #include <private/qv8engine_p.h> @@ -76,6 +77,8 @@ #include <QtCore/qcoreapplication.h> #include <QtCore/qloggingcategory.h> +#include <QDebug> + QT_BEGIN_NAMESPACE using namespace QV4; @@ -1464,11 +1467,26 @@ static QString jsStack(QV4::ExecutionEngine *engine) { static QV4::ReturnedValue writeToConsole(ConsoleLogTypes logType, CallContext *ctx, bool printStack = false) { + QLoggingCategory *loggingCategory = 0; QString result; QV4::ExecutionEngine *v4 = ctx->d()->engine; - for (int i = 0; i < ctx->argc(); ++i) { - if (i != 0) + int start = 0; + if (ctx->argc() > 0) { + if (const QObjectWrapper* wrapper = ctx->args()[0].as<QObjectWrapper>()) { + if (QQmlLoggingCategory* category = qobject_cast<QQmlLoggingCategory*>(wrapper->object())) { + if (category->category()) + loggingCategory = category->category(); + else + V4THROW_ERROR("A QmlLoggingCatgory was provided without a valid name"); + start = 1; + } + } + } + + + for (int i = start; i < ctx->argc(); ++i) { + if (i != start) result.append(QLatin1Char(' ')); if (ctx->args()[i].as<ArrayObject>()) @@ -1485,7 +1503,8 @@ static QV4::ReturnedValue writeToConsole(ConsoleLogTypes logType, CallContext *c static QLoggingCategory qmlLoggingCategory("qml"); static QLoggingCategory jsLoggingCategory("js"); - QLoggingCategory *loggingCategory = v4->qmlEngine() ? &qmlLoggingCategory : &jsLoggingCategory; + if (!loggingCategory) + loggingCategory = v4->qmlEngine() ? &qmlLoggingCategory : &jsLoggingCategory; QV4::StackFrame frame = v4->currentStackFrame(); const QByteArray baSource = frame.source.toUtf8(); const QByteArray baFunction = frame.function.toUtf8(); diff --git a/tests/auto/qml/qqmlconsole/data/categorized_logging.qml b/tests/auto/qml/qqmlconsole/data/categorized_logging.qml new file mode 100644 index 0000000000..d19b6ecc41 --- /dev/null +++ b/tests/auto/qml/qqmlconsole/data/categorized_logging.qml @@ -0,0 +1,65 @@ +/**************************************************************************** +** +** Copyright (C) 2016 Pelagicore AG +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQml 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 The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/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 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.8 + +Item { + id:root + + LoggingCategory { + id: testCategory + name: "qt.test" + } + + LoggingCategory { + id: emptyCategory + } + + Component.onCompleted: { + console.debug(testCategory, "console.debug"); + console.log(testCategory, "console.log"); + console.info(testCategory, "console.info"); + console.warn(testCategory, "console.warn"); + console.error(testCategory, "console.error"); + + testCategory.name = "qt.test2"; + + console.error(emptyCategory, "console.error"); + } +} diff --git a/tests/auto/qml/qqmlconsole/tst_qqmlconsole.cpp b/tests/auto/qml/qqmlconsole/tst_qqmlconsole.cpp index f12656c5fe..f832143935 100644 --- a/tests/auto/qml/qqmlconsole/tst_qqmlconsole.cpp +++ b/tests/auto/qml/qqmlconsole/tst_qqmlconsole.cpp @@ -40,6 +40,7 @@ public: private slots: void logging(); + void categorized_logging(); void tracing(); void profiling(); void testAssert(); @@ -87,6 +88,41 @@ void tst_qqmlconsole::logging() delete object; } +void tst_qqmlconsole::categorized_logging() +{ + QUrl testUrl = testFileUrl("categorized_logging.qml"); + QQmlTestMessageHandler messageHandler; + messageHandler.setIncludeCategoriesEnabled(true); + + QLoggingCategory testCategory("qt.test"); + testCategory.setEnabled(QtDebugMsg, true); + QVERIFY(testCategory.isDebugEnabled()); + QVERIFY(testCategory.isWarningEnabled()); + QVERIFY(testCategory.isCriticalEnabled()); + + QQmlComponent component(&engine, testUrl); + QObject *object = component.create(); + QVERIFY2(object != 0, component.errorString().toUtf8()); + + QVERIFY(messageHandler.messages().contains("qt.test: console.info")); + QVERIFY(messageHandler.messages().contains("qt.test: console.warn")); + QVERIFY(messageHandler.messages().contains("qt.test: console.error")); + + QString emptyCategory = "default: " + QString::fromLatin1("%1:%2:%3: ").arg(testUrl.toString()).arg(50).arg(5) + + "QML LoggingCategory: Declaring the name of the LoggingCategory is mandatory and cannot be changed later !"; + QVERIFY(messageHandler.messages().contains(emptyCategory)); + + QString changedCategory = "default: " + QString::fromLatin1("%1:%2:%3: ").arg(testUrl.toString()).arg(45).arg(5) + + "QML LoggingCategory: The name of a LoggingCategory cannot be changed after the Item is created"; + QVERIFY(messageHandler.messages().contains(changedCategory)); + + QString useEmptyCategory = "default: " + QString::fromLatin1("%1:%2: ").arg(testUrl.toString()).arg(63) + + "Error: A QmlLoggingCatgory was provided without a valid name"; + QVERIFY(messageHandler.messages().contains(useEmptyCategory)); + + delete object; +} + void tst_qqmlconsole::tracing() { QUrl testUrl = testFileUrl("tracing.qml"); diff --git a/tests/auto/shared/util.cpp b/tests/auto/shared/util.cpp index 55041eeb4d..96beb51612 100644 --- a/tests/auto/shared/util.cpp +++ b/tests/auto/shared/util.cpp @@ -101,11 +101,15 @@ Q_GLOBAL_STATIC(QMutex, qQmlTestMessageHandlerMutex) QQmlTestMessageHandler *QQmlTestMessageHandler::m_instance = 0; -void QQmlTestMessageHandler::messageHandler(QtMsgType, const QMessageLogContext &, const QString &message) +void QQmlTestMessageHandler::messageHandler(QtMsgType, const QMessageLogContext &context, const QString &message) { QMutexLocker locker(qQmlTestMessageHandlerMutex()); - if (QQmlTestMessageHandler::m_instance) - QQmlTestMessageHandler::m_instance->m_messages.push_back(message); + if (QQmlTestMessageHandler::m_instance) { + if (QQmlTestMessageHandler::m_instance->m_includeCategories) + QQmlTestMessageHandler::m_instance->m_messages.push_back(QString("%1: %2").arg(context.category, message)); + else + QQmlTestMessageHandler::m_instance->m_messages.push_back(message); + } } QQmlTestMessageHandler::QQmlTestMessageHandler() @@ -114,6 +118,7 @@ QQmlTestMessageHandler::QQmlTestMessageHandler() Q_ASSERT(!QQmlTestMessageHandler::m_instance); QQmlTestMessageHandler::m_instance = this; m_oldHandler = qInstallMessageHandler(messageHandler); + m_includeCategories = false; } QQmlTestMessageHandler::~QQmlTestMessageHandler() diff --git a/tests/auto/shared/util.h b/tests/auto/shared/util.h index 47a4aae231..33d7cbd1d0 100644 --- a/tests/auto/shared/util.h +++ b/tests/auto/shared/util.h @@ -87,12 +87,15 @@ public: void clear() { m_messages.clear(); } + void setIncludeCategoriesEnabled(bool enabled) { m_includeCategories = enabled; } + private: - static void messageHandler(QtMsgType, const QMessageLogContext &, const QString &message); + static void messageHandler(QtMsgType, const QMessageLogContext &context, const QString &message); static QQmlTestMessageHandler *m_instance; QStringList m_messages; QtMessageHandler m_oldHandler; + bool m_includeCategories; }; #endif // QQMLTESTUTILS_H |