drop support for storing types that are not QString-convertable via QSettings

I am not interested in custom types feature at all - QMainWindow for
example saves its state via QDataStream. ofcourse it involves conversion
but that is the case with QVariant aswell. there is also the qreal type
thing - it may be float, it may double. streaming QRectF has to be done
in such a way to account for both cases but here is the catch - if
conversion fails there has to be fallback which QSettings::value() kinda
covers for types that are not composed of several more types.

Signed-off-by: Ivailo Monev <xakepa10@gmail.com>
This commit is contained in:
Ivailo Monev 2022-11-13 19:27:13 +02:00
parent 2ae0376a53
commit bc0040b970
3 changed files with 6 additions and 223 deletions

View file

@ -111,7 +111,7 @@ static bool ini_settings_read(QIODevice &device, QSettings::SettingsMap &map)
const QByteArray key = line.left(separatorpos).trimmed(); const QByteArray key = line.left(separatorpos).trimmed();
const QByteArray value = line.mid(separatorpos + 1).trimmed(); const QByteArray value = line.mid(separatorpos + 1).trimmed();
const QVariant variantvalue = QSettingsPrivate::stringToVariant(value); const QVariant variantvalue(value);
if (section.isEmpty()) { if (section.isEmpty()) {
map.insert(key, variantvalue); map.insert(key, variantvalue);
} else { } else {
@ -154,7 +154,11 @@ static bool ini_settings_write(QIODevice &device, const QSettings::SettingsMap &
return false; return false;
} }
const QString stringvalue = QSettingsPrivate::variantToString(map.value(key)); const QVariant variantvalue = map.value(key);
if (!variantvalue.canConvert<QString>()) {
return false;
}
const QString stringvalue = variantvalue.toString();
const QString datavalue = QLatin1Char('=') + stringvalue + QLatin1Char('\n'); const QString datavalue = QLatin1Char('=') + stringvalue + QLatin1Char('\n');
if (!device.write(datavalue.toAscii())) { if (!device.write(datavalue.toAscii())) {
return false; return false;
@ -317,152 +321,6 @@ QString QSettingsPrivate::toGroupKey(const QString &key) const
return group + QLatin1Char('/') + key; return group + QLatin1Char('/') + key;
} }
QString QSettingsPrivate::variantToString(const QVariant &v)
{
switch (v.type()) {
case QVariant::Invalid: {
return QLatin1String("@Invalid()");
}
case QVariant::ByteArray: {
QByteArray a = v.toByteArray();
QString result = QLatin1String("@ByteArray(");
result += QString::fromAscii(a.constData(), a.size());
result += QLatin1Char(')');
return result;
}
case QVariant::String:
case QVariant::LongLong:
case QVariant::ULongLong:
case QVariant::Int:
case QVariant::UInt:
case QVariant::Bool:
case QVariant::Double:
case QVariant::KeySequence: {
QString result = v.toString();
if (result.startsWith(QLatin1Char('@')))
result.prepend(QLatin1Char('@'));
return result;
}
case QVariant::Rect: {
QRect r = qvariant_cast<QRect>(v);
QString result = QLatin1String("@Rect(");
result += QString::number(r.x());
result += QLatin1Char(' ');
result += QString::number(r.y());
result += QLatin1Char(' ');
result += QString::number(r.width());
result += QLatin1Char(' ');
result += QString::number(r.height());
result += QLatin1Char(')');
return result;
}
case QVariant::Size: {
QSize s = qvariant_cast<QSize>(v);
QString result = QLatin1String("@Size(");
result += QString::number(s.width());
result += QLatin1Char(' ');
result += QString::number(s.height());
result += QLatin1Char(')');
return result;
}
case QVariant::Point: {
QPoint p = qvariant_cast<QPoint>(v);
QString result = QLatin1String("@Point(");
result += QString::number(p.x());
result += QLatin1Char(' ');
result += QString::number(p.y());
result += QLatin1Char(')');
return result;
}
default: {
#ifndef QT_NO_DATASTREAM
QByteArray a;
{
QDataStream s(&a, QIODevice::WriteOnly);
s << v;
}
QString result = QLatin1String("@Variant(");
result += QString::fromAscii(a.constData(), a.size());
result += QLatin1Char(')');
return result;
#else
Q_ASSERT(!"QSettings: Cannot save custom types without QDataStream support");
return QString();
#endif
}
}
return QString();
}
QVariant QSettingsPrivate::stringToVariant(const QString &s)
{
if (s.startsWith(QLatin1Char('@'))) {
if (s.endsWith(QLatin1Char(')'))) {
if (s.startsWith(QLatin1String("@ByteArray("))) {
return QVariant(s.toAscii().mid(11, s.size() - 12));
} else if (s.startsWith(QLatin1String("@Variant("))) {
#ifndef QT_NO_DATASTREAM
QByteArray a(s.toAscii().mid(9));
QDataStream stream(&a, QIODevice::ReadOnly);
QVariant result;
stream >> result;
return result;
#else
Q_ASSERT(!"QSettings: Cannot load custom types without QDataStream support");
#endif
} else if (s.startsWith(QLatin1String("@Rect("))) {
QStringList args = QSettingsPrivate::splitArgs(s, 5);
if (args.size() == 4)
return QVariant(QRect(args[0].toInt(), args[1].toInt(), args[2].toInt(), args[3].toInt()));
} else if (s.startsWith(QLatin1String("@Size("))) {
QStringList args = QSettingsPrivate::splitArgs(s, 5);
if (args.size() == 2)
return QVariant(QSize(args[0].toInt(), args[1].toInt()));
} else if (s.startsWith(QLatin1String("@Point("))) {
QStringList args = QSettingsPrivate::splitArgs(s, 6);
if (args.size() == 2)
return QVariant(QPoint(args[0].toInt(), args[1].toInt()));
} else if (s == QLatin1String("@Invalid()")) {
return QVariant();
}
}
if (s.startsWith(QLatin1String("@@")))
return QVariant(s.mid(1));
}
return QVariant(s);
}
QStringList QSettingsPrivate::splitArgs(const QString &s, int idx)
{
int l = s.length();
Q_ASSERT(l > 0);
Q_ASSERT(s.at(idx) == QLatin1Char('('));
Q_ASSERT(s.at(l - 1) == QLatin1Char(')'));
QStringList result;
QString item;
for (++idx; idx < l; ++idx) {
QChar c = s.at(idx);
if (c == QLatin1Char(')')) {
Q_ASSERT(idx == l - 1);
result.append(item);
} else if (c == QLatin1Char(' ')) {
result.append(item);
item.clear();
} else {
item.append(c);
}
}
return result;
}
/*! /*!
\class QSettings \class QSettings
\brief The QSettings class provides persistent platform-independent application settings. \brief The QSettings class provides persistent platform-independent application settings.

View file

@ -54,10 +54,6 @@ public:
void notify(); void notify();
QString toGroupKey(const QString &key) const; QString toGroupKey(const QString &key) const;
// INI parser functions
static QString variantToString(const QVariant &v);
static QVariant stringToVariant(const QString &s);
static QStringList splitArgs(const QString &s, int idx);
QSettings::Format format; QSettings::Format format;
QSettings::SettingsStatus status; QSettings::SettingsStatus status;

View file

@ -49,8 +49,6 @@ private slots:
void variant(); void variant();
void group_data(); void group_data();
void group(); void group();
void custom_data();
void custom();
}; };
void tst_QSettings::initTestCase() void tst_QSettings::initTestCase()
@ -142,27 +140,12 @@ void tst_QSettings::variant()
const QByteArray qbytearray("abc"); const QByteArray qbytearray("abc");
const QByteArray qstring("måndag"); const QByteArray qstring("måndag");
const QStringList qstringlist = QStringList() << "a" << "b" << "c"; const QStringList qstringlist = QStringList() << "a" << "b" << "c";
const QPoint qpoint(1, 2);
const QRect qrect(1, 2, 3, 4);
const QSize qsize(1, 2);
const QDate qdate = QDate::currentDate();
const QColor qcolor(1, 2, 3);
const QFont qfont = QApplication::font();
QVARIANT_TEST(qll); QVARIANT_TEST(qll);
QVARIANT_TEST(qrl); QVARIANT_TEST(qrl);
QVARIANT_TEST(qbytearray); QVARIANT_TEST(qbytearray);
QVARIANT_TEST(qstring); QVARIANT_TEST(qstring);
QVARIANT_TEST(qstringlist); QVARIANT_TEST(qstringlist);
if (format == QSettings::NativeFormat) {
QSKIP("Native format does not support some types", SkipAll);
}
QVARIANT_TEST(qpoint);
QVARIANT_TEST(qrect);
QVARIANT_TEST(qsize);
QVARIANT_TEST(qdate);
QVARIANT_TEST(qcolor);
QVARIANT_TEST(qfont);
} }
#undef QVARIANT_TEST #undef QVARIANT_TEST
@ -194,60 +177,6 @@ void tst_QSettings::group()
settings.endGroup(); settings.endGroup();
} }
struct CustomType {
int a;
QByteArray b;
QSize c;
};
Q_DECLARE_METATYPE(CustomType);
QDataStream &operator<<(QDataStream &stream, const CustomType &custom)
{
stream << custom.a;
stream << custom.b;
stream << custom.c;
return stream;
}
QDataStream &operator>>(QDataStream &stream, CustomType &custom)
{
stream >> custom.a;
stream >> custom.b;
stream >> custom.c;
return stream;
}
void tst_QSettings::custom_data()
{
tst_QSettings::value_data();
}
void tst_QSettings::custom()
{
QFETCH(QString, filename);
QFETCH(QSettings::Format, format);
if (format == QSettings::NativeFormat) {
QSKIP("Native format does not support custom types", SkipAll);
}
qRegisterMetaType<CustomType>();
qRegisterMetaTypeStreamOperators<CustomType>();
CustomType test;
test.a = 10;
test.b = QByteArray("test");
test.c = QSize(10, 10);
QSettings settings(filename, format);
settings.setValue("a", QVariant::fromValue(test));
CustomType result = qvariant_cast<CustomType>(settings.value("a"));
QCOMPARE(result.a, 10);
QCOMPARE(result.b, QByteArray("test"));
QCOMPARE(result.c, QSize(10, 10));
}
QTEST_MAIN(tst_QSettings) QTEST_MAIN(tst_QSettings)
#include "moc_tst_qsettings.cpp" #include "moc_tst_qsettings.cpp"