Qt Labs Settings: warn if failed to initialize internal QSettings instance

First, warn the user that the QSettings instance failed to initialize
if there was an error. Then, if the error was QSettings::AccessError,
print the specific application identifiers that weren't set so they
know what they have to do. For example:

    QML Settings: Failed to initialize QSettings instance. Status code is: 1
    QML Settings: The following application identifiers have not been set: QVector("organizationName", "organizationDomain")

In my case, the QSettings instance wasn't created on
Windows because organizationName wasn't set.

Change-Id: I7970209e09b78f785730422c45978775311b96ac
Reviewed-by: Jan Arve Sæther <jan-arve.saether@qt.io>
This commit is contained in:
Mitch Curtis 2018-09-11 10:41:57 +02:00
parent 7ca32bc41c
commit 1ce94fc0f5
2 changed files with 52 additions and 4 deletions

View File

@ -39,10 +39,12 @@
#include "qqmlsettings_p.h"
#include <qcoreevent.h>
#include <qcoreapplication.h>
#include <qloggingcategory.h>
#include <qsettings.h>
#include <qpointer.h>
#include <qjsvalue.h>
#include <qqmlinfo.h>
#include <qdebug.h>
#include <qhash.h>
@ -269,6 +271,26 @@ QSettings *QQmlSettingsPrivate::instance() const
if (!settings) {
QQmlSettings *q = const_cast<QQmlSettings*>(q_func());
settings = new QSettings(q);
if (settings->status() != QSettings::NoError) {
// TODO: can't print out the enum due to the following error:
// error: C2666: 'QQmlInfo::operator <<': 15 overloads have similar conversions
qmlWarning(q) << "Failed to initialize QSettings instance. Status code is: " << int(settings->status());
if (settings->status() == QSettings::AccessError) {
QVector<QString> missingIdentifiers;
if (QCoreApplication::organizationName().isEmpty())
missingIdentifiers.append(QLatin1String("organizationName"));
if (QCoreApplication::organizationDomain().isEmpty())
missingIdentifiers.append(QLatin1String("organizationDomain"));
if (QCoreApplication::applicationName().isEmpty())
missingIdentifiers.append(QLatin1String("applicationName"));
if (!missingIdentifiers.isEmpty())
qmlWarning(q) << "The following application identifiers have not been set: " << missingIdentifiers;
}
return settings;
}
if (!category.isEmpty())
settings->beginGroup(category);
if (initialized)

View File

@ -53,6 +53,7 @@ private slots:
void categories();
void siblings();
void initial();
void noApplicationIdentifiersSet();
};
// ### Replace keyValueMap("foo", "bar") with QVariantMap({{"foo", "bar"}})
@ -147,10 +148,6 @@ void tst_QQmlSettings::initTestCase()
{
QQmlDataTest::initTestCase();
QCoreApplication::setApplicationName("tst_QQmlSettings");
QCoreApplication::setOrganizationName("QtProject");
QCoreApplication::setOrganizationDomain("qt-project.org");
qmlRegisterType<CppObject>("Qt.test", 1, 0, "CppObject");
}
@ -158,6 +155,10 @@ void tst_QQmlSettings::init()
{
QSettings settings;
settings.clear();
QCoreApplication::setApplicationName("tst_QQmlSettings");
QCoreApplication::setOrganizationName("QtProject");
QCoreApplication::setOrganizationDomain("qt-project.org");
}
void tst_QQmlSettings::cleanup()
@ -481,6 +482,31 @@ void tst_QQmlSettings::initial()
QCOMPARE(settings->property("value").toString(), QStringLiteral("initial"));
}
void tst_QQmlSettings::noApplicationIdentifiersSet()
{
#ifdef Q_OS_MACOS
QSKIP("macOS doesn't complain about empty application identifiers");
#endif
QCoreApplication::setApplicationName(QString());
QCoreApplication::setOrganizationName(QString());
QCoreApplication::setOrganizationDomain(QString());
QTest::ignoreMessage(QtWarningMsg, QRegularExpression(".*QML Settings: Failed to initialize QSettings instance. Status code is: 1"));
// Can't set an empty applicationName because QCoreApplication won't allow it, which is why it's not listed here.
QTest::ignoreMessage(QtWarningMsg, QRegularExpression(".*QML Settings: The following application identifiers have not been set: QVector\\(\"organizationName\", \"organizationDomain\"\\)"));
QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("basic.qml"));
QScopedPointer<QObject> root(component.create());
QVERIFY(root.data());
// The value of the QML property will be true because it defaults to it...
QVERIFY(root->property("success").toBool());
QSettings settings;
// ... but the settings' value should be false because it was never loaded.
QVERIFY(!settings.value("success").toBool());
}
QTEST_MAIN(tst_QQmlSettings)
#include "tst_qqmlsettings.moc"