Vous avez reçu un message "Your GitLab account has been locked ..." ? Pas d'inquiétude : lisez cet article https://docs.gricad-pages.univ-grenoble-alpes.fr/help/unlock/

QSettings_impl.h 8.52 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
/****************************************************************************
 * **
 * ** Copyright (C) 2017 MinMaxMedical.
 * ** All rights reserved.
 * ** Contact: MinMaxMedical <InCAS@MinMaxMedical.com>
 * **
 * ** This file is part of the modmedLog module.
 * **
 * ** $QT_BEGIN_LICENSE:BSD$
 * ** You may use this file under the terms of the BSD license as follows:
 * **
 * ** "Redistribution and use in source and binary forms, with or without
 * ** modification, are permitted provided that the following conditions are
 * ** met:
 * **   * Redistributions of source code must retain the above copyright
 * **     notice, this list of conditions and the following disclaimer.
 * **   * Redistributions in binary form must reproduce the above copyright
 * **     notice, this list of conditions and the following disclaimer in
 * **     the documentation and/or other materials provided with the
 * **     distribution.
 * **   * Neither the name of MinMaxMedical S.A.S. and its Subsidiary(-ies) nor
 * **     the names of its contributors may be used to endorse or promote
 * **     products derived from this software without specific prior written
 * **     permission.
 * **
 * ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
 * ** $QT_END_LICENSE$
 * **
 * ****************************************************************************/
#pragma once

#include <QtCore/qsettings.h>
#include <QtCore/qvariant.h>
#include <QtCore/qstack.h>

EXT Arnaud Clère's avatar
EXT Arnaud Clère committed
46
#include "QValue.h"
47
48

// //////////////////////////////////////////////////////////////////////////
EXT Arnaud Clère's avatar
EXT Arnaud Clère committed
49
// QSettings* support for the fixed set of QSettingsWriter's BindNative types
50

51
class QSettingsWriter : public QAbstractValueWriter
52
53
54
{
    Q_DISABLE_COPY(QSettingsWriter)
public:
55
    QSettingsWriter(QSettings* s) : settings(s) { Q_ASSERT(s); settings->beginGroup("test"); } // FIXME remove extra beginGroup
56
57

    // Shortcuts
58
59
60
    /**/                 QValue    value   (                  ) { return QCur(this).value(); }
    /**/                 QSequence sequence(quint32* s=nullptr) { return QCur(this).value().sequence(s); }
    template<typename T> QValueEnd bind    (             T&& t) { return QCur(this).value().bind(std::forward<T>(t)); }
61
protected:
62
63
64
65
66
67
    bool tryBind    (     quint8&& t) { settings->setValue(key(), int(t)                               ); return true; }
    bool tryBind    (    quint16&& t) { settings->setValue(key(), int(t)                               ); return true; }
    bool tryBind    (    quint32&& t) { settings->setValue(key(), int(t)                               ); return true; }
    bool tryBind    (QUtf8DataView u) { settings->setValue(key(), QString::fromUtf8(u.data(), u.size())); return true; }
    bool tryBind    (  QStringView s) { settings->setValue(key(), s.toString()                         ); return true; }
    bool tryBind    (    QString&& s) { settings->setValue(key(), s                                    ); return true; }
68
69
70

    bool tryAny () { settings->setValue(key(), QVariant()                  ); return true; }
    bool tryNull() { settings->setValue(key(), QVariant::fromValue(nullptr)); return true; }
71

72
73
    bool trySequence(quint32* =nullptr) { levels.push(Level(                 )); settings->beginGroup(key()); return true; } // TODO use beginWriteArray
    bool tryRecord  (quint32* =nullptr) { levels.push(Level(qBindExpectedItem)); settings->beginGroup(key()); return true; }
74
75
76

    bool tryItem(QIdentifier& n) { levels.last().key=n; return true; }
    bool tryItem(              ) { levels.last().idx++; return true; }
77
78
79
80
81
    bool tryOut (              ) {
        levels.pop();
        settings->endGroup();
        return true;
    }
82
83
private:
    QString key() {
84
        return levels.size()==0 ? QString("") :
85
86
87
              !levels.last().key.isNull()
                 ? QString        (levels.last().key.latin1())
                 : QString::number(levels.last().idx         );
88
89
90
    }

    QSettings* settings;
91
    struct Level { QIdentifier key; quint32 idx=0; Level(QIdentifier k=QIdentifier()) : key(k) {} };
92
93
94
95
96
    QStack<Level> levels = QStack<Level>(); //!< minimal dynamic context to implement out() and ensure actual building in case QSettingsWriter is abandoned
};

// --------------------------------------------------------------------------

97
class QSettingsReader : public QAbstractValueReader
98
99
100
{
    Q_DISABLE_COPY(QSettingsReader)
public:
101
    Q_ENABLE_MOVE_DEFAULT(QSettingsReader)
102
    QSettingsReader(QSettings* s) : settings(s) { Q_ASSERT(s); levels.push(Level(qBindExpectedItem)); }
103

104
    QAsciiData currentPath() {
105
        QByteArray path;
106
        Q_FOREACH(Level l, levels) {
107
108
            if (l.key.isNull()) { path.append('/').append(                   l.key.utf8() ); }
            else                { path.append('/').append(QByteArray::number(l.idx       )); }
109
        }
110
        return QAsciiData(path);
111
112
113
    }

    // Shortcuts
114
    template<typename T> QValueEnd bind(T&& t) { return QCur(this).value().bind(std::forward<T>(t)); }
115
116
protected:
    template<typename T>
117
    bool tryBind(T& t) { return set(t, "Expected declared metatype T"); }
118

119
120
121
122
    bool tryBind(QUtf8Data& t) { return set(t, qBindExpectedText   ); }
    bool tryBind(    QString& t) { return set(t, qBindExpectedText   ); }
    bool tryBind(       bool& t) { return set(t, qBindExpectedBoolean); }
    bool tryBind( QByteArray& t) { return set(t, qBindExpectedBytes  ); }
123
    // Convert numerical types to strictly larger ones // TODO convert all compatible values
124
125
126
127
128
129
130
131
132
133
    bool tryBind(      qint8& t) { return set(t, qBindExpectedInteger        ); }
    bool tryBind(     qint16& t) { return set(t, qBindExpectedInteger        ); }
    bool tryBind(     qint32& t) { return set(t, qBindExpectedInteger        ); }
    bool tryBind(     qint64& t) { return set(t, qBindExpectedInteger        ); }
    bool tryBind(     quint8& t) { return set(t, qBindExpectedPositiveInteger); }
    bool tryBind(    quint16& t) { return set(t, qBindExpectedPositiveInteger); }
    bool tryBind(    quint32& t) { return set(t, qBindExpectedPositiveInteger); }
    bool tryBind(    quint64& t) { return set(t, qBindExpectedPositiveInteger); }
    bool tryBind(      float& t) { return set(t, qBindExpectedDecimal        ); }
    bool tryBind(     double& t) { return set(t, qBindExpectedDecimal        ); }
134

135
136
    bool trySequence(quint32* =nullptr) { if (levels.last().isGroup) { levels.push(Level(                 )); return true; } handleError(qBindExpectedSequence); return false; }
    bool tryRecord  (quint32* =nullptr) { if (levels.last().isGroup) { levels.push(Level(qBindExpectedItem)); return true; } handleError(qBindExpectedRecord  ); return false; }
137

138
    bool tryNull() { if ( settings->value(key()).isNull ()) { return true; } handleError(qBindExpectedNull); return false; }
139
140
141
142

    bool tryItem(QIdentifier& k) { levels.last().key=k               ; return true; }
    bool tryItem(              ) { levels.last().idx++               ; return true; }
    bool tryOut (              ) { levels.pop(); settings->endGroup(); return true; }
143

144
    bool tryAny() { return true; }
EXT Arnaud Clère's avatar
EXT Arnaud Clère committed
145
    bool isValid() const noexcept { return settings; }
146
    bool handleError(QIdentifierLiteral error, QString context = QString()) { return errorHandler ? errorHandler(error, QString(currentPath().latin1()).append(context)) : false; }
147
148
private:
    template<typename T>
149
    bool set(T& t, QIdentifierLiteral error) { QVariant v = settings->value(key()); if (v.convert(qMetaTypeId<T>())) { t = v.value<T>(); return true; } handleError(error); return false; }
150
151
    QString key() {
        Q_ASSERT(!levels.isEmpty());
152
        return !levels.last().key.isNull()
153
154
            ? QString        (levels.last().key.latin1())
            : QString::number(levels.last().idx         );
155
156
157
    }

    QSettings* settings;
158
    struct Level { QIdentifier key; int idx=-1; bool isGroup=true; Level(QIdentifier n=QIdentifier(), bool isGroup=true) : key(n), isGroup(isGroup) {} };
159
160
    QStack<Level> levels;
};