Coverage Report

Created: 2026-04-29 07:00

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/kconfig/src/gui/kconfiggroupgui.cpp
Line
Count
Source
1
/*
2
    This file is part of the KDE libraries
3
    SPDX-FileCopyrightText: 2007 Thiago Macieira <thiago@kde.org>
4
5
    SPDX-License-Identifier: LGPL-2.0-or-later
6
*/
7
8
#include "kconfiggui_export.h"
9
#include <kconfiggroup.h>
10
11
#include <QColor>
12
#include <QDebug>
13
#include <QFont>
14
15
#include <kconfiggroup_p.h>
16
17
/*
18
 * Try to read a GUI type from config group cg at key key.
19
 * input is the default value and also indicates the type to be read.
20
 * output is to be set with the value that has been read.
21
 *
22
 * Returns true if something was handled (even if output was set to clear or default)
23
 *          or false if nothing was handled (e.g., Core type)
24
 */
25
static bool readEntryGui(const QByteArray &data, const char *key, const QVariant &input, QVariant &output)
26
0
{
27
0
    const auto errString = [&]() {
28
0
        return QStringLiteral("\"%1\" - conversion from \"%3\" to %2 failed")
29
0
            .arg(QLatin1String(key), QLatin1String(input.typeName()), QLatin1String(data.constData()));
30
0
    };
31
32
    // set in case of failure
33
0
    output = input;
34
35
0
    switch (static_cast<QMetaType::Type>(input.userType())) {
36
0
    case QMetaType::QColor: {
37
0
        if (data.isEmpty() || data == "invalid") {
38
0
            output = QColor(); // return what was stored
39
0
            return true;
40
0
        } else if (data.at(0) == '#') {
41
0
            QColor col = QColor::fromString(QUtf8StringView(data.constData(), data.length()));
42
0
            if (!col.isValid()) {
43
0
                qCritical() << qPrintable(errString());
44
0
            }
45
0
            output = col;
46
0
            return true;
47
0
        } else if (!data.contains(',')) {
48
0
            QColor col = QColor::fromString(QUtf8StringView(data.constData(), data.length()));
49
0
            if (!col.isValid()) {
50
0
                qCritical() << qPrintable(errString());
51
0
            }
52
0
            output = col;
53
0
            return true;
54
0
        } else {
55
0
            const QList<QByteArray> list = data.split(',');
56
0
            const int count = list.count();
57
58
0
            if (count != 3 && count != 4) {
59
0
                qCritical() //
60
                    << qPrintable(errString()) //
61
0
                    << qPrintable(QStringLiteral(" (wrong format: expected '%1' items, read '%2')").arg(QStringLiteral("3' or '4")).arg(count));
62
0
                return true; // return default
63
0
            }
64
65
0
            int temp[4];
66
            // bounds check components
67
0
            for (int i = 0; i < count; i++) {
68
0
                bool ok;
69
0
                const int j = temp[i] = list.at(i).toInt(&ok);
70
0
                if (!ok) { // failed to convert to int
71
0
                    qCritical() << qPrintable(errString()) << " (integer conversion failed)";
72
0
                    return true; // return default
73
0
                }
74
0
                if (j < 0 || j > 255) {
75
0
                    static const char *const components[] = {"red", "green", "blue", "alpha"};
76
0
                    qCritical() << qPrintable(errString())
77
0
                                << qPrintable(QStringLiteral(" (bounds error: %1 component %2)")
78
0
                                                  .arg(QLatin1String(components[i]), //
79
0
                                                       j < 0 ? QStringLiteral("< 0") : QStringLiteral("> 255")));
80
0
                    return true; // return default
81
0
                }
82
0
            }
83
0
            QColor aColor(temp[0], temp[1], temp[2]);
84
0
            if (count == 4) {
85
0
                aColor.setAlpha(temp[3]);
86
0
            }
87
88
0
            if (aColor.isValid()) {
89
0
                output = aColor;
90
0
            } else {
91
0
                qCritical() << qPrintable(errString());
92
0
            }
93
0
            return true;
94
0
        }
95
0
    }
96
97
0
    case QMetaType::QFont: {
98
0
        QVariant tmp = QString::fromUtf8(data.constData(), data.length());
99
0
        if (tmp.canConvert<QFont>()) {
100
0
            output = tmp;
101
0
        } else {
102
0
            qCritical() << qPrintable(errString());
103
0
        }
104
0
        return true;
105
0
    }
106
0
    case QMetaType::QPixmap:
107
0
    case QMetaType::QImage:
108
0
    case QMetaType::QBrush:
109
0
    case QMetaType::QPalette:
110
0
    case QMetaType::QIcon:
111
0
    case QMetaType::QRegion:
112
0
    case QMetaType::QBitmap:
113
0
    case QMetaType::QCursor:
114
0
    case QMetaType::QSizePolicy:
115
0
    case QMetaType::QPen:
116
        // we may want to handle these in the future
117
118
0
    default:
119
0
        break;
120
0
    }
121
122
0
    return false; // not handled
123
0
}
124
125
/*
126
 * Try to write a GUI type prop to config group cg at key key.
127
 *
128
 * Returns true if something was handled (even if an empty value was written)
129
 *          or false if nothing was handled (e.g., Core type)
130
 */
131
static bool writeEntryGui(KConfigGroup *cg, const char *key, const QVariant &prop, KConfigGroup::WriteConfigFlags pFlags)
132
11.5k
{
133
11.5k
    switch (static_cast<QMetaType::Type>(prop.userType())) {
134
0
    case QMetaType::QColor: {
135
0
        const QColor rColor = prop.value<QColor>();
136
137
0
        if (!rColor.isValid()) {
138
0
            cg->writeEntry(key, "invalid", pFlags);
139
0
            return true;
140
0
        }
141
142
0
        QList<int> list;
143
0
        list.insert(0, rColor.red());
144
0
        list.insert(1, rColor.green());
145
0
        list.insert(2, rColor.blue());
146
0
        if (rColor.alpha() != 255) {
147
0
            list.insert(3, rColor.alpha());
148
0
        }
149
150
0
        cg->writeEntry(key, list, pFlags);
151
0
        return true;
152
0
    }
153
0
    case QMetaType::QFont: {
154
0
        QFont f = prop.value<QFont>();
155
        // If the styleName property is set for a QFont, using setBold(true) would
156
        // lead to Qt using an "emboldended"/synthetic font style instead of using
157
        // the bold style provided by the font itself; the latter looks much better
158
        // than the former. For more details see:
159
        // https://bugreports.qt.io/browse/QTBUG-63792
160
        // https://bugs.kde.org/show_bug.cgi?id=378523
161
        /* clang-format off */
162
0
        if (f.weight() == QFont::Normal
163
0
            && (f.styleName() == QLatin1String("Regular")
164
0
                || f.styleName() == QLatin1String("Normal")
165
0
                || f.styleName() == QLatin1String("Book")
166
0
                || f.styleName() == QLatin1String("Roman"))) { /* clang-format on */
167
0
            f.setStyleName(QString());
168
0
        }
169
0
        cg->writeEntry(key, f.toString().toUtf8(), pFlags);
170
0
        return true;
171
0
    }
172
0
    case QMetaType::QPixmap:
173
0
    case QMetaType::QImage:
174
0
    case QMetaType::QBrush:
175
0
    case QMetaType::QPalette:
176
0
    case QMetaType::QIcon:
177
0
    case QMetaType::QRegion:
178
0
    case QMetaType::QBitmap:
179
0
    case QMetaType::QCursor:
180
0
    case QMetaType::QSizePolicy:
181
0
    case QMetaType::QPen:
182
        // we may want to handle one of these in the future
183
0
        break;
184
185
11.5k
    default:
186
11.5k
        break;
187
11.5k
    }
188
189
11.5k
    return false;
190
11.5k
}
191
192
// Not static, because for static builds we use it in the kconfigguistaticinitializer.cpp file
193
// Exported as we need this to force linking in consumers that read GUI types from KConfig, but
194
// which are otherwise not using this library (and thus linking with --as-needed or MSVC would
195
// break things)
196
KCONFIGGUI_EXPORT int initKConfigGroupGui()
197
8
{
198
8
    _kde_internal_KConfigGroupGui.readEntryGui = readEntryGui;
199
8
    _kde_internal_KConfigGroupGui.writeEntryGui = writeEntryGui;
200
8
    return 42; // because 42 is nicer than 1 or 0
201
8
}
202
203
#ifdef Q_CONSTRUCTOR_FUNCTION
204
Q_CONSTRUCTOR_FUNCTION(initKConfigGroupGui)
205
#else
206
static int dummyKConfigGroupGui = initKConfigGroupGui();
207
#endif