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/

QModel_impl.h 29.3 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
/****************************************************************************
 * **
 * ** Copyright (C) 2018 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 <type_traits>

#include <QtCore/qabstractitemmodel.h>
45
#include <QtCore/qvariant.h>
46
#include <QtCore/qstring.h>
EXT Arnaud Clère's avatar
EXT Arnaud Clère committed
47
#include <QtCore/qbuffer.h>
48
#include <QtGui/qcolor.h>
49

EXT Arnaud Clère's avatar
EXT Arnaud Clère committed
50
#include "QValue.h"
EXT Arnaud Clère's avatar
EXT Arnaud Clère committed
51
#include "QJson_impl.h"
52
53

// //////////////////////////////////////////////////////////////////////////
EXT Arnaud Clère's avatar
EXT Arnaud Clère committed
54
// Q*Model support
55

56
class QModelBind : public QAbstractValue
57
{
58
    Q_DISABLE_COPY(QModelBind)
59
public:
60
    QModelBind(QAbstractItemModel* m, bool rowFirst=true) : m(m), rowFirst(rowFirst) { Q_ASSERT(m); }
61

62
    QValue value() { return QCur(this).value(); }
63
protected:
64
65
66
67
68
69
70
    enum : int {
        T=0, //!< initial state
        R=1, //!< 1st model dimension (and all odd  ones in a tree) where items bind to row (views being row-wise by default)
        C=2, //!< 2nd model dimension (and all even ones in a tree) where items bind to col or index(row,col,parent).model().index(0,0) where row>sizes[?] or QIdentifierLiteral n==childrenName
        I=3, //!< final model dimension handled by TItemWriter to set leaf items depending on their type
    };

71
    virtual void _meta(QIdentifierLiteral& n, QAsciiData& meta) {
EXT Arnaud Clère's avatar
EXT Arnaud Clère committed
72
        if (T==d) {
73
74
            if (n == qmChildren) {
                childrenName = QIdentifier(meta.latin1());
75
            }
76
            else if (n == qmColumns) {
EXT Arnaud Clère's avatar
EXT Arnaud Clère committed
77
78
                metaColumnNames=true;
                int i=0;
79
                for (auto&& k : meta.utf8().split(',')) {
EXT Arnaud Clère's avatar
EXT Arnaud Clère committed
80
81
                    m->insertColumn(i);
                    m->setHeaderData(i,Qt::Horizontal,k);
82
                    columnNames.insert(i,k);
EXT Arnaud Clère's avatar
EXT Arnaud Clère committed
83
84
85
                    i++;
                }
            }
86
            else if (n == qmSizes) {
87
                for (auto&& k : meta.utf8().split(',')) {
88
                    int i = k.toInt();
EXT Arnaud Clère's avatar
EXT Arnaud Clère committed
89
90
                    if (0<i) sizes.append(i);
                }
91
            }
92
            else { qDebug("Ignored meta %s=%s", n.utf8(), meta.data()); }
93
        }
94
        else if (C==d) {
95
96
            if (n == qmColor) {
                m->setData(current(),QColor(meta.latin1()),Qt::ForegroundRole);
97
            }
98
            else { qDebug("Ignored meta %s=%s", n.utf8(), meta.data()); }
99
100
        }
        else {
101
            itemBind()->_meta(n, meta);
EXT Arnaud Clère's avatar
EXT Arnaud Clère committed
102
        }
103
    }
104

105
106
    virtual bool tryAny() { return true; }

107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
    using QAbstractValue::tryBind; // full overload set so that following overloads calls work (instead of calling themselves and overflowing the call stack)

    virtual bool tryBind(const  QUtf8Data& r) {  QUtf8Data copy(r); return tryBind(std::move(copy)); }
    virtual bool tryBind(const    QString& r) {    QString copy(r); return tryBind(std::move(copy)); }
    virtual bool tryBind(const       bool& r) {       bool copy(r); return tryBind(std::move(copy)); }
    virtual bool tryBind(const      qint8& r) {      qint8 copy(r); return tryBind(std::move(copy)); }
    virtual bool tryBind(const     quint8& r) {     quint8 copy(r); return tryBind(std::move(copy)); }
    virtual bool tryBind(const     qint16& r) {     qint16 copy(r); return tryBind(std::move(copy)); }
    virtual bool tryBind(const    quint16& r) {    quint16 copy(r); return tryBind(std::move(copy)); }
    virtual bool tryBind(const     qint32& r) {     qint32 copy(r); return tryBind(std::move(copy)); }
    virtual bool tryBind(const    quint32& r) {    quint32 copy(r); return tryBind(std::move(copy)); }
    virtual bool tryBind(const     qint64& r) {     qint64 copy(r); return tryBind(std::move(copy)); }
    virtual bool tryBind(const    quint64& r) {    quint64 copy(r); return tryBind(std::move(copy)); }
    virtual bool tryBind(const      float& r) {      float copy(r); return tryBind(std::move(copy)); }
    virtual bool tryBind(const     double& r) {     double copy(r); return tryBind(std::move(copy)); }
    virtual bool tryBind(const QByteArray& r) { QByteArray copy(r); return tryBind(std::move(copy)); }
    virtual bool tryBind(const   QVariant& r) {   QVariant copy(r); return tryBind(std::move(copy)); }

    virtual bool tryBind(      const char* u) { return tryBind(QString::fromUtf8  (u                 )); } // required to match better than QString overloads
    virtual bool tryBind(    QUtf8DataView u) { return tryBind(QString::fromUtf8  (u.data(), u.size())); }
    virtual bool tryBind(   QAsciiDataView a) { return tryBind(QString::fromLatin1(a.data(), a.size())); }
    virtual bool tryBind(    QLatin1String l) { return tryBind(QString(l)                             ); }
    virtual bool tryBind(      QStringView s) { return tryBind(s.toString()                           ); }

    virtual bool tryBind(      QUtf8Data&& s) { return tryBind(QString::fromUtf8  (s.utf8(), s.size())); }

    virtual bool tryBind(     QByteArray&& s) { return tryBind(QString(s.size()*2+2+1, Qt::Uninitialized).append("0x").append(s.toHex())); }

    virtual bool tryBind(          qint8&& n) { return tryBind(    qint64(n)); }
    virtual bool tryBind(         quint8&& n) { return tryBind(   quint64(n)); }
    virtual bool tryBind(         qint16&& n) { return tryBind(    qint64(n)); }
    virtual bool tryBind(        quint16&& n) { return tryBind(   quint64(n)); }
    virtual bool tryBind(         qint32&& n) { return tryBind(    qint64(n)); }
    virtual bool tryBind(        quint32&& n) { return tryBind(   quint64(n)); }

    virtual bool tryBind(          qint8&  n) { return tryBind(    qint64(n)); }
    virtual bool tryBind(         quint8&  n) { return tryBind(   quint64(n)); }
    virtual bool tryBind(         qint16&  n) { return tryBind(    qint64(n)); }
    virtual bool tryBind(        quint16&  n) { return tryBind(   quint64(n)); }
    virtual bool tryBind(         qint32&  n) { return tryBind(    qint64(n)); }
    virtual bool tryBind(        quint32&  n) { return tryBind(   quint64(n)); }

    virtual bool tryBind(       QUtf8Data& r) { return tryBind( QUtf8Data(r)); }
    virtual bool tryBind(         QString& r) { return tryBind(   QString(r)); }
    virtual bool tryBind(            bool& r) { return tryBind(      bool(r)); }
    virtual bool tryBind(          qint64& r) { return tryBind(    qint64(r)); }
    virtual bool tryBind(         quint64& r) { return tryBind(   quint64(r)); }
    virtual bool tryBind(           float& r) { return tryBind(     float(r)); }
    virtual bool tryBind(          double& r) { return tryBind(    double(r)); }
    virtual bool tryBind(      QByteArray& r) { return tryBind(QByteArray(r)); }
    virtual bool tryBind(        QVariant& r) { return tryBind(  QVariant(r)); }
158

159
    bool handleError(QIdentifierLiteral e, QString context = QString()) {
160
161
162
163
164
        if (errorHandler) {
            QString path;
            for (auto current = parent; parent.isValid(); current = current.parent()) {
                path.prepend(QString('/').append(current.row()).append(',').append(current.column()));
            }
165
166
167
168
            return errorHandler(e, path.append(context));
        }
        else {
            return false;
169
170
        }
    }
171

172
    virtual QAbstractValue*        itemBind() = 0;
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222

    //! Checks whether current dimension \c d is R or C, inverting R and C dimensions if !rowFirst
    bool   is(int rc) { Q_ASSERT(rc==R || rc==C); return rowFirst ? d==rc : d==(rc==R ? C : R); }
    int  next(      ) { Q_ASSERT( d==R ||  d==C); return                    d==(    R ? C : R); }
    //! Returns a valid QModelIndex inserting rows/columns as needed
    QModelIndex current() {
        int rows = m->   rowCount(parent); if (rows<=row) m->insertRows   (rows,1+row-rows,parent);
        int cols = m->columnCount(parent); if (cols<=col) m->insertColumns(cols,1+col-cols,parent);
        auto idx = m->index(row,col,parent); Q_ASSERT(hidden() || m->checkIndex(idx)); return idx;
    }
    //! Returns whether current data must be hidden because a current or parent column or row was filtered out
    bool hidden() noexcept {
        for(auto i=parent;;i=i.parent()) {
            if (col<0 || row<0)
                return true;
            if (!i.isValid()) // after previous test
                return false; // without trying i=i.parent()
        }
        Q_ASSERT(false);
    }
    //! Returns an unlimited size if sizes.isEmpty() or the size corresponding to the current dimension or 0 if the dimension exceeds defined sizes
    int dimension() {
        int dimension = d-R;
        for (auto index = parent; index.isValid() ; index = index.parent()) {
            dimension += 2;
        }
        return dimension;
    }
    //! Returns int max value if no dimension sizes or 0 if current dimension exceeds number of sizes
    int max(int dimension) {
        return sizes.isEmpty()        ? std::numeric_limits<int>::max() :
               dimension<sizes.size() ? sizes.at(dimension)
                                      : 0;
    }
    inline bool write(QVariant v) { m->setData(current(), v); return true; }
    inline QVariant read() { return m->   data(current()); } // TODO Handle Undefined ?

    QAbstractItemModel* m;
    bool rowFirst;

    // Current bind state
    int d=T;
    QModelIndex parent;
    int row=0, col=0; //!< Allows handling {null} equally to {} (but not equally to null) without requiring QModelIndex to reference rows/columns before they actually exist

    // Supported meta()
    QIdentifier childrenName;
    QList<QByteArray> columnNames;
    bool metaColumnNames=false;
    QVector<int> sizes;
223

224
    QValueErrorHandler errorHandler = nullptr;
225
226
227
228
229
230
231
232
233
234
235
};

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

template <class TItemWriter=QJsonWriter>
class QModelWriter : public QModelBind
{
    Q_DISABLE_COPY(QModelWriter)
public:
    QModelWriter(QAbstractItemModel* m, bool rowFirst=true) : QModelBind(m, rowFirst), w(&ba) {}

236
    virtual QValueMode mode() const noexcept { return QValueMode::Write; }
EXT Arnaud Clère's avatar
EXT Arnaud Clère committed
237
    virtual bool      isValid() const noexcept { return true; } //!< Write status ignored by default (no need to test intermediate status to choose between trySequence(), etc.
238
protected:
239
    virtual bool tryOut() {
240
241
242
243
244
        d--;
        if (I<=(d+1)) {
            if (hidden()) {
                return true;
            }
245
            if  (!itemBind()->tryOut()) {
246
247
248
                return false;
            }
            if (I==(d+1)) {
249
                return tryBind(QString::fromUtf8(ba.data(), ba.size()));
250
            }
EXT Arnaud Clère's avatar
EXT Arnaud Clère committed
251
            return true;
252
        }
253
254
255
256
257
        else {
            if (T==d && parent.isValid()) { // case of a tree, even if hidden()
                row=parent.row(); parent=parent.parent(); d=C;
            }
            return true;
258
259
        }
    }
EXT Arnaud Clère's avatar
EXT Arnaud Clère committed
260

261
    virtual bool trySequence(quint32* s=nullptr) {
262
263
264
265
        ++d;
        if (hidden()) {
            return true;
        }
266
267
268
269
        else if (I<=d) {
            if  (I==d) {
                resetItemData();
            }
270
            return itemBind()->trySequence(s);
271
        }
272
        else if (is(C)) {
273
            col=-1; // set to 0 by mandatory tryItem() following
274
275
276
            return true;
        }
        else if (is(R)) {
277
            row=-1; // set to 0 by mandatory tryItem() following
278
            return true;
279
        }
280
281
        else { Q_ASSERT(T==d);
            return true;
282
283
284
        }
    }

285
    virtual bool tryRecord  (quint32* s=nullptr) {
286
287
288
289
        ++d;
        if (hidden()) {
            return true;
        }
290
291
292
293
        else if (I<=d) {
            if  (I==d) {
                resetItemData();
            }
294
            return itemBind()->tryRecord(s);
295
296
        }
        else if (is(C)) {
297
            col=-1; // set to 0 by mandatory tryItem() following
298
            return true;
299
        }
300
        else if (is(R)) {
301
            row=-1; // set to 0 by mandatory tryItem() following
302
            return true;
303
        }
304
305
        else { Q_ASSERT(T==d);
            return true;
306
307
308
        }
    }

309
    virtual bool tryItem() {
310
311
        Q_ASSERT(d!=T);
        if (is(C)) {
312
            col++; // mandatory after trySequence()
313
314
315
            if (hidden()) {
                return true;
            }
316
            else if (max(dimension())<=col) {
317
318
319
320
                if (d==R && row+1<max(dimension()+1)) { // new row
                    row++; col=0;
                    return true;
                }
321
                handleError(qBindIgnoredItem);
322
323
324
325
                return false;
            }
            return true;
        }
326
        else if (is(R)) {
327
            row++; // mandatory after trySequence()
328
329
330
            if (hidden()) {
                return true;
            }
331
            else if (max(dimension())<=row) {
332
333
334
335
              if (d==R && col+1<max(dimension()+1)) { // new row
                  row=0; col++;
                  return true;
              }
336
              handleError(qBindIgnoredItem);
337
338
339
340
              return false;
            }
            return true;
        }
341
        else { Q_ASSERT(I<=d);
342
            return hidden() || itemBind()->tryItem();
343
        }
344
    }
EXT Arnaud Clère's avatar
EXT Arnaud Clère committed
345

346
347
    virtual bool tryItem(QIdentifierLiteral n) { QIdentifier id(n); return tryItem(id); }
    virtual bool tryItem(QIdentifier& n) {
348
349
        Q_ASSERT(d!=T);
        if (is(C)) {
350
            col++; // mandatory after tryRecord()
351
352
353
            if (hidden()) {
                return true;
            }
354
            else if (n!=childrenName) {
355
356
357
358
359
360
361
362
363
364
365
                if (!metaColumnNames) {
                    if (!parent.isValid() && row==0) {
                        int i = m->columnCount();
                        m->insertColumn(i);
                        m->setHeaderData(i,Qt::Horizontal,n.latin1());
                        columnNames.insert(i,n.utf8());
                    }
                }
                else {
                     col=columnNames.indexOf(n.utf8());
                     // TODO if (max(dimension())<=col) col=-1;
366
367
                     if (col<0 && !handleError(qBindIgnoredItem)) {
                         return false;
368
369
370
371
                     }
                }
                return true;
            }
372
373
374
375
            else {
                d=T; parent=m->index(row,0,parent); row=col=0;
                return true;
            }
376
        }
377
        else if (is(R)) {
378
            row++; // mandatory after tryRecord()
379
380
381
382
383
            if (hidden()) {
                return true;
            }
            else {
                // TODO if (rowNames...
384
                return handleError(qBindIgnoredItemName);
385
            }
386
        }
387
        else { Q_ASSERT(I<=d);
388
            return hidden() || itemBind()->tryItem(n);
389
390
        }
    }
EXT Arnaud Clère's avatar
EXT Arnaud Clère committed
391

392
    using QAbstractValue::tryBind; // full overload set so that following overloads calls work (instead of calling themselves and overflowing the call stack)
393

394
395
    virtual bool tryAny (             ) { return hidden() ? true : I<=d ? itemBind()->tryAny()              : write(QVariant()); }
    virtual bool tryNull(             ) { return hidden() ? true : I<=d ? itemBind()->tryNull()             : write(QVariant::fromValue(nullptr)); }
396
397
398
399
400
    virtual bool tryBind(  QString&& u) { return hidden() ? true : I<=d ? itemBind()->tryBind(std::move(u)) : write(u         ); }
    virtual bool tryBind(     bool&& b) { return hidden() ? true : I<=d ? itemBind()->tryBind(std::move(b)) : write(b         ); }
    virtual bool tryBind(    float&& f) { return hidden() ? true : I<=d ? itemBind()->tryBind(std::move(f)) : write(f         ); }
    virtual bool tryBind(   double&& f) { return hidden() ? true : I<=d ? itemBind()->tryBind(std::move(f)) : write(f         ); }
    virtual bool tryBind(  quint64&& i) { return hidden() ? true : I<=d ? itemBind()->tryBind(std::move(i)) : i<=quint64(std::numeric_limits<unsigned int>::max()) ? write(static_cast<unsigned int>(i)) :
401
                                                                                                          write(i         ); } // with QSpinBox delegate
402
    virtual bool tryBind(   qint64&& i) { return hidden() ? true : I<=d ? itemBind()->tryBind(std::move(i)) : i<= qint64(std::numeric_limits<         int>::max()) ? write(static_cast<         int>(i)) :
403
                                                                                                          write(i         ); }
404
    virtual bool tryBind( QVariant&& t) { return hidden() ? true : I<=d ? itemBind()->tryBind( QVariant(t)) : write(t         ); }
405
406
    // TODO QDate*, QTime
    // TODO QPixmap if metadata suggests a QMimeData image ?
407

408
    void     resetItemData() { ba.clear(); w = std::move(TItemWriter(&ba)); }
409
    QAbstractValue*        itemBind() { return static_cast<QAbstractValue*>(&w); }
410

411
    QByteArray ba;
412
413
414
415
416
417
418
419
420
    TItemWriter w;
};

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

template <class TItemReader=QJsonReader>
class QModelReader : public QModelBind
{
    Q_DISABLE_COPY(QModelReader)
421
    Q_ENABLE_MOVE_DEFAULT(QModelReader)
422
public:
423
    QModelReader(QAbstractItemModel* m, bool rowFirst=true) : QModelBind(m, rowFirst), r(&io) { io.open(QIODevice::ReadOnly); }
424

425
    virtual QValueMode mode() const noexcept { return QValueMode::Read; }
EXT Arnaud Clère's avatar
EXT Arnaud Clère committed
426
    virtual bool      isValid() const noexcept { return true; } //!< Read status ignored by default (QAbstractItemModel is not sequential)
427
protected:
428
    virtual bool tryOut() {
429
430
        if (I<=d) {
            d--;
431
            return hidden() || itemBind()->tryOut();
432
433
434
435
436
437
438
439
440
441
        }
        else { Q_ASSERT(C==d || R==d);
            d--;
            if (R==d && parent.isValid()) { // case of a tree, even if hidden()
                row=parent.row(); parent=parent.parent(); d=C;
            }
            return true;
        }
    }

442
    virtual bool trySequence(quint32* s=nullptr) {
443
444
445
446
447
448
449
450
451
452
453
454
        ++d;
        if (hidden()) {
            return true;
        }
        else if (I<=d) {
            if  (I==d) {
                QVariant v = read();
                if (v.type()!=QVariant::String) {
                    return false;
                }
                setItemData(QUtf8Data(v.toString().toUtf8()));
            }
455
            return itemBind()->trySequence(s);
456
457
        }
        else if (is(C)) {
458
            col=-1; // set to 0 by mandatory tryItem() following
459
460
461
            return true;
        }
        else if (is(R)) {
462
            row=-1; // set to 0 by mandatory tryItem() following
463
464
465
466
467
468
469
            return true;
        }
        else { Q_ASSERT(T==d);
            return true;
        }
    }

470
    virtual bool tryRecord  (quint32* s=nullptr) {
471
472
473
474
475
476
477
478
479
480
481
482
        ++d;
        if (hidden()) {
            return true;
        }
        else if (I<=d) {
            if  (I==d) {
                QVariant v = read();
                if (v.type()!=QVariant::String) {
                    return false;
                }
                setItemData(QUtf8Data(v.toString().toUtf8()));
            }
483
            return itemBind()->tryRecord(s);
484
485
        }
        else if (is(C)) {
486
            col=-1; // set to 0 by mandatory tryItem() following
487
488
489
            return true;
        }
        else if (is(R)) {
490
            row=-1; // set to 0 by mandatory tryItem() following
491
492
493
494
495
496
497
            return true;
        }
        else { Q_ASSERT(T==d);
            return true;
        }
    }

498
    virtual bool tryItem() {
499
500
        Q_ASSERT(d!=T);
        if (is(C)) {
501
            col++; // mandatory after trySequence()
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
            if (hidden()) {
                return true;
            }
            else {
                if (max(dimension())<=col) {
                    if (d==R && row+1 < max(dimension()+1)) { // new row
                        row++; col=0;
                        if (row < m->rowCount()) { Q_ASSERT(col < m->columnCount());
                            return true;
                        }
                    }
                }
                if (col < m->columnCount()) {
                    return true;
                }
517
                handleError(qBindIgnoredItem);
518
519
520
521
522
                return false;
            }
            return true;
        }
        else if (is(R)) {
523
524
525
            if (m->rowCount() <= row+1) {
                return false;
            }
526
            row++; // mandatory after trySequence()
527
528
529
530
531
532
533
534
            if (hidden()) {
                return true;
            }
            else if (max(dimension())<=row) {
              if (d==R && col+1<max(dimension()+1)) { // new row
                  row=0; col++;
                  return true;
              }
535
              handleError(qBindIgnoredItem);
536
537
538
539
540
              return false;
            }
            return true;
        }
        else { Q_ASSERT(I<=d);
541
            return hidden() || itemBind()->tryItem();
542
543
544
        }
    }

545
546
    virtual bool tryItem(QIdentifierLiteral n) { QIdentifier id(n); return tryItem(id); }
    virtual bool tryItem(QIdentifier& n) {
547
548
        Q_ASSERT(d!=T);
        if (is(C)) {
549
            col++; // mandatory after tryRecord()
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
            if (hidden()) {
                return true;
            }
            else if (n!=childrenName) {
                if (!metaColumnNames) {
                    col=-1;
                    for (int i=0; i < m->columnCount(); ++i) {
                        if (m->headerData(i, Qt::Horizontal).toString()==n.latin1()) {
                            col=i;
                            break;
                        }
                    }
                }
                else {
                     col=columnNames.indexOf(n.utf8());
                }
                // TODO if (max(dimension())<=col) col=-1;
567
568
                if (col<0 && !handleError(qBindIgnoredItem)) {
                    return false;
569
570
571
                }
                return true;
            }
EXT Arnaud Clère's avatar
EXT Arnaud Clère committed
572
            else { return true; }
573
574
        }
        else if (is(R)) {
575
            row++; // mandatory after tryRecord()
576
577
578
579
580
            if (hidden()) {
                return true;
            }
            else if (n!=childrenName) {
                // TODO if (rowNames...
581
                return handleError(qBindIgnoredItemName);
582
            }
EXT Arnaud Clère's avatar
EXT Arnaud Clère committed
583
            else { return true; }
584
585
586
587
588
589
590
591
592
593
        }
        else { Q_ASSERT(I<=d);
            if (hidden()) {
                return true;
            }
            else if (I==d && n==childrenName) {
                d=T; parent=m->index(row,0,parent); row=col=0;
                return true;
            }
            else {
594
                return itemBind()->tryItem(n);
595
596
597
598
            }
        }
    }

599
    using QAbstractValue::tryBind; // full overload set so that following overloads calls work (instead of calling themselves and overflowing the call stack)
600

601
602
    virtual bool tryAny (             ) { return hidden() ? true : I<=d ? itemBind()->tryAny()              :                !read().isValid () ; }
    virtual bool tryNull(             ) { return hidden() ? true : I<=d ? itemBind()->tryNull()             :                 read().isNull  () ; }
603
604
605
606
607
608
609
    virtual bool tryBind(  QString&& u) { return hidden() ? true : I<=d ? itemBind()->tryBind(std::move(u)) :              u==read().toString() ; }
    virtual bool tryBind(     bool&& b) { return hidden() ? true : I<=d ? itemBind()->tryBind(std::move(b)) :              b==read().toBool  () ; }
    virtual bool tryBind(    float&& f) { return hidden() ? true : I<=d ? itemBind()->tryBind(std::move(f)) : qFuzzyCompare(f,read().toFloat ()); }
    virtual bool tryBind(   double&& f) { return hidden() ? true : I<=d ? itemBind()->tryBind(std::move(f)) : qFuzzyCompare(f,read().toDouble()); }
    virtual bool tryBind(  quint64&& i) { return hidden() ? true : I<=d ? itemBind()->tryBind(std::move(i)) :              i==read().toUInt  () ; }
    virtual bool tryBind(   qint64&& i) { return hidden() ? true : I<=d ? itemBind()->tryBind(std::move(i)) :              i==read(). toInt  () ; }
    virtual bool tryBind( QVariant&& t) { return hidden() ? true : I<=d ? itemBind()->tryBind( QVariant(t)) :              t==read()            ; }
610
611
    // TODO QDate*, QTime
    // TODO QPixmap if metadata suggests a QMimeData image ?
612

613
614
615
616
617
618
    virtual bool tryBind(    qint8&  n) {  qint64 l; if (!tryBind(l)) return false; if (l<std::numeric_limits<  qint8>::min() || std::numeric_limits<  qint8>::max()<l) { handleError(qBindExpectedSmallerNumber); return false; } n=  qint8(l); return true; }
    virtual bool tryBind(   quint8&  n) { quint64 l; if (!tryBind(l)) return false; if (                                         std::numeric_limits< quint8>::max()<l) { handleError(qBindExpectedSmallerNumber); return false; } n= quint8(l); return true; }
    virtual bool tryBind(   qint16&  n) {  qint64 l; if (!tryBind(l)) return false; if (l<std::numeric_limits< qint16>::min() || std::numeric_limits< qint16>::max()<l) { handleError(qBindExpectedSmallerNumber); return false; } n= qint16(l); return true; }
    virtual bool tryBind(  quint16&  n) { quint64 l; if (!tryBind(l)) return false; if (                                         std::numeric_limits<quint16>::max()<l) { handleError(qBindExpectedSmallerNumber); return false; } n=quint16(l); return true; }
    virtual bool tryBind(   qint32&  n) {  qint64 l; if (!tryBind(l)) return false; if (l<std::numeric_limits< qint32>::min() || std::numeric_limits< qint32>::max()<l) { handleError(qBindExpectedSmallerNumber); return false; } n= qint32(l); return true; }
    virtual bool tryBind(  quint32&  n) { quint64 l; if (!tryBind(l)) return false; if (                                         std::numeric_limits<quint32>::max()<l) { handleError(qBindExpectedSmallerNumber); return false; } n=quint32(l); return true; }
619
620
621
622
623
624
625
626
627
628
629
630

    virtual bool tryBind( QUtf8Data& r) { if (hidden()) return true; if (I<=d) return itemBind()->tryBind(r); QVariant v=read(); if (v.type()!=QVariant ::String   ) return false; r=QUtf8Data(v.toString().toUtf8()); return true; }
    virtual bool tryBind(   QString& r) { if (hidden()) return true; if (I<=d) return itemBind()->tryBind(r); QVariant v=read(); if (v.type()!=QVariant ::String   ) return false; r=          v.toString         () ; return true; }
    virtual bool tryBind(      bool& r) { if (hidden()) return true; if (I<=d) return itemBind()->tryBind(r); QVariant v=read(); if (v.type()!=QVariant ::Bool     ) return false; r=          v.toBool           () ; return true; }
    virtual bool tryBind(    qint64& r) { if (hidden()) return true; if (I<=d) return itemBind()->tryBind(r); QVariant v=read(); bool isConverted=false;  qint64 i=v. toLongLong(&isConverted); if (!isConverted || v.type()==QVariant::Bool || v.type()==QVariant::ByteArray) { return false; } r=i; return true; }
    virtual bool tryBind(   quint64& r) { if (hidden()) return true; if (I<=d) return itemBind()->tryBind(r); QVariant v=read(); bool isConverted=false; quint64 i=v.toULongLong(&isConverted); if (!isConverted || v.type()==QVariant::Bool || v.type()==QVariant::ByteArray) { return false; } r=i; return true; }
    virtual bool tryBind(     float& r) { if (hidden()) return true; if (I<=d) return itemBind()->tryBind(r); QVariant v=read(); bool isConverted=false; float   i=v.toFloat    (&isConverted); if (!isConverted || v.type()==QVariant::Bool || v.type()==QVariant::ByteArray) { return false; } r=i; return true; }
    virtual bool tryBind(    double& r) { if (hidden()) return true; if (I<=d) return itemBind()->tryBind(r); QVariant v=read(); bool isConverted=false; double  i=v.toDouble   (&isConverted); if (!isConverted || v.type()==QVariant::Bool || v.type()==QVariant::ByteArray) { return false; } r=i; return true; }
    virtual bool tryBind(QByteArray& r) { if (hidden()) return true; if (I<=d) return itemBind()->tryBind(r); QVariant v=read(); if (v.type()!=QVariant ::ByteArray) return false; r=          v.toByteArray      () ; return true; }
    virtual bool tryBind(  QVariant& r) { if (hidden()) return true; if (I<=d) return itemBind()->tryBind(r);          r=read()                                                                                      ; return true; }

    QAbstractValue*  itemBind() { return static_cast<QAbstractValue*>(&r); }
631
632
633
    void setItemData(QUtf8Data u) { io.buffer() = u.utf8(); io.seek(0); r.reset(&io); }

    QBuffer io;
634
635
    TItemReader r;
};