Commit 12c42b18 authored by EXT Arnaud Clère's avatar EXT Arnaud Clère
Browse files

first working QModelWriter

parent 285308e1
......@@ -83,6 +83,7 @@ static QName qBindExpectedBoolean = "Expected boolean" ;
static QName qBindExpectedConstant = "Expected constant" ;
static QName qBindIgnoredItem = "Ignored item" ;
static QName qBindIgnoredItemName = "Ignored item name" ;
static QName qBindIgnoredCharacter = "Ignored character" ;
static QName qBindIgnoredBytes = "Ignored bytes" ;
......@@ -599,7 +600,8 @@ struct IReader : public IBind
double d; // matches most used numbers more easily than types below
qint64 i; // matches most used integrals more easily than types below
quint64 u;
if (_bind(b) || _bind(d) || _bind(i) || _bind(u)) {
QByteArray bytes;
if (_bind(b) || _bind(d) || _bind(i) || _bind(u) || _bind(bytes)) {
return true;
}
_setChoice(false);
......
......@@ -358,19 +358,6 @@ protected:
bool _bind ( qint64& t) { if (caching) { cacheLevel++; return caching->_bind(t) && cacheOut(); }
double d; qint64 i; bool neg; auto r=getNumber(d,i,neg); if (r) t= i ; return r; }
bool _any ( ) { return next();
//isChoice=true; QString s; QByteArray t; double d; bool b;
//((_sequence() && _out())
//||_null()
//||_bind(b)
//||_bind(d)
//||_bind(t)
//||_bind(s)
//);
//isChoice=false;
//return true;
}
bool _item( QName u) { if (caching) { return caching->_item(u); }
QUtf8String s;
while (true) {
......@@ -433,6 +420,7 @@ protected:
}
return leaveContainer(); }
bool _any() { return next(); }
bool _isOk() { return lastError()==QCborError::NoError; }
void _setChoice(bool b) { isChoice = b; }
void _reportError(const char* e) { if (!isChoice) errors.append(Error{ e, currentOffset(), lastError() }); }
......@@ -523,7 +511,7 @@ struct QBind<QCborValue, TResult> {
QString t; if ((r = v.bind(t))) { j = QCborValue( t ); return r; }
bool b; if ((r = v.bind(b))) { j = QCborValue( b ); return r; }
qint64 i; if ((r = v.bind(i))) { j = QCborValue( i ); return r; }
quint64 u; if ((r = v.bind(u))) { Q_ASSERT(std::numeric_limits<qint64>::max()<u); // or _bind<qint64>() would have succeeded
quint64 u; if ((r = v.bind(u))) { Q_ASSERT(quint64(std::numeric_limits<qint64>::max())<u); // or _bind<qint64>() would have succeeded
j = QCborValue(double(u)); return r; }
double d; if ((r = v.bind(d))) { j = QCborValue( d ); return r; }
QByteArray y; if ((r = v.bind(y))) { j = QCborValue( y ); return r; }
......
......@@ -156,12 +156,15 @@ class QJsonWriter : public IWriter
public:
QJsonWriter(QIODevice* io) : io(io) { Q_ASSERT(io); }
~QJsonWriter() { for (auto&& level : levels) io->write(level.end); }
void reset(QIODevice* io) { this->io=io; Q_ASSERT(io); levels.clear(); }
// Shortcuts
/**/ Val<Cursor> value ( ) { return Cursor(this).value(); }
/**/ Seq<Cursor> sequence(quint32* s=nullptr) { return Cursor(this).value().sequence ( s); }
template<typename T> Cursor bind ( T&& t) { return Cursor(this).value().bind(std::forward<T>(t)); }
protected:
template<class T> friend class QModelWriter;
bool _sequence(quint32* s=nullptr) { Q_UNUSED(s); levels.push(Step{"","]"}); return io->write("["); }
bool _record (quint32* s=nullptr) { Q_UNUSED(s); levels.push(Step{"","}"}); return io->write("{"); }
bool _null ( ) { return io->write( "null" ); }
......@@ -170,8 +173,8 @@ protected:
bool _bind ( bool&& n) { return io->write( n?"true":"false" ); }
bool _bind ( float&& n) { return io->write(QUtf8String::number(n,'g',std::numeric_limits< float>::max_digits10)); }
bool _bind ( double&& n) { return io->write(QUtf8String::number(n,'g',std::numeric_limits<double>::max_digits10)); }
bool _bind ( quint64&& t) { return io->write(QUtf8String::number(t)); }
bool _bind ( qint64&& t) { return io->write(QUtf8String::number(t)); }
bool _bind ( quint64&& t) { return io->write(QUtf8String::number(t)); }
bool _bind ( qint64&& t) { return io->write(QUtf8String::number(t)); }
bool _item(QName n) { auto r=(io->write(levels.last().sep) || *levels.last().sep=='\0') && putString(n) && io->write(":"); levels.last().sep = ","; return r; }
bool _item( ) { auto r=(io->write(levels.last().sep) || *levels.last().sep=='\0') ; levels.last().sep = ","; return r; }
......
......@@ -43,23 +43,26 @@
#include <QtCore/qabstractitemmodel.h>
#include <QtCore/qvariant.h>
#include <QtCore/qbuffer.h>
#include "QBind_impl.h"
#include "QVariant_impl.h"
#include "QJson_impl.h"
// //////////////////////////////////////////////////////////////////////////
// QBind<T,Q*Model> support
template <class TItemWriter=QJsonWriter>
class QModelWriter : public IWriter
{
Q_DISABLE_COPY(QModelWriter)
enum : int {
T=0, //!< nothing called
S=1, //!< sequence() called, expecting out() or item()... calls
R=2, //!< record () called, expecting out() or item(key)... calls
T=0, //!< initial state
R=1, //!< 1st and odd model dimensions where items bind to row (views being row-wise by default)
C=2, //!< 2nd and even model dimensions where items bind to col or index(row,col,parent).model().index(0,0) where row>sizes[?] or QName n==childrenName
I=3, //!< final model dimension handled by TItemWriter to set leaf items depending on their type
};
public:
QModelWriter(QAbstractItemModel* m) : m(m) { Q_ASSERT(m); }
QModelWriter(QAbstractItemModel* m) : m(m), w(&io) { Q_ASSERT(m); }
Val<Cursor> meta(QMetaData&& m) { return Cursor(this).value().meta(m); }
protected:
......@@ -70,10 +73,11 @@ protected:
if (meta.find(qmColumns)!=meta.end()) {
int i=0;
Q_FOREACH(auto k,meta[qmColumns].split(',')) {
names.append(k.toUtf8());
m->setHeaderData(i++,Qt::Horizontal,k);
columnNames.append(k.toUtf8());
m->insertColumn(i);
m->setHeaderData(i,Qt::Horizontal,k);
i++;
}
m->insertColumns(0,names.size());
}
if (meta.find(qmSizes)!=meta.end()) {
Q_FOREACH(auto k,meta[qmSizes].split(',')) {
......@@ -82,46 +86,96 @@ protected:
}
}
bool _null( ) { return m->setData(idx, QVariant( )); }
bool _bind( const char* s) { return m->setData(idx, QVariant( s)); }
bool _bind( QString&& s) { return m->setData(idx, QVariant( s)); }
bool _bind( bool&& b) { return m->setData(idx, QVariant( b)); }
bool _bind( float&& f) { return m->setData(idx, QVariant( f)); }
bool _bind( double&& d) { return m->setData(idx, QVariant( d)); }
bool _bind( quint64&& i) { return m->setData(idx, QVariant((unsigned int)i)); }
bool _bind( qint64&& u) { return m->setData(idx, QVariant(( int)u)); }
// TODO BindNative all types in http://doc.qt.io/qt-5/qitemeditorfactory.html#details ?
bool _null( ) { return !canBind() ? false : d<I ? m->setData(current(), QVariant( )) : w._null( ); }
bool _bind( const char* s) { return !canBind() ? false :
d<I ? m->setData(current(), QString(s)) : w._bind(std::move(s)); }
bool _bind( bool&& b) { return !canBind() ? false : d<I ? m->setData(current(), QVariant(b)) : w._bind(std::move(b)); }
bool _bind( float&& f) { return !canBind() ? false : d<I ? m->setData(current(), QVariant(f)) : w._bind(std::move(f)); }
bool _bind( double&& f) { return !canBind() ? false : d<I ? m->setData(current(), QVariant(f)) : w._bind(std::move(f)); }
bool _bind( quint64&& i) { return !canBind() ? false :
d<I ? m->setData(current(), QVariant(i)) : w._bind(std::move(i)); }
bool _bind( qint64&& u) { return !canBind() ? false :
d<I ? m->setData(current(), QVariant(u)) : w._bind(std::move(u)); }
// TODO QDate*, QTime
// TODO QPixmap if metadata suggests a QMimeData image ?
bool _out ( ) { Q_ASSERT(d!=T);
if (!canBind()) return false;
if (d--==I) {
return w._out() && _bind(io.buffer()); }
return d<I ? true : w._out(); }
bool _sequence(quint32* s=nullptr) { if (!canBind()) return false;
if (++d==I) {
io.buffer().clear(); io.open(QIODevice::WriteOnly); w.reset(&io); }
if (d==R)
row=-1; // set to 0 by mandatory _item() following
if (d==C)
col=-1; // set to 0 by mandatory _item() following
return d<I ? true : w._sequence(s); }
bool _record (quint32* s=nullptr) { if (!canBind()) return false;
if (++d==I) {
io.buffer().clear(); io.open(QIODevice::WriteOnly); w.reset(&io); }
if (d==R)
row=-1; // set to 0 by mandatory _item() following
if (d==C)
col=-1; // set to 0 by mandatory _item() following
return d<I ? true : w._record (s); }
bool _item ( ) { Q_ASSERT(d!=T);
if (d==C) { col++;
// TODO if (currentSize()<=col && childrenName.isEmpty()) { d=R; parent=m->index(row,col,parent); row=col=0; return true; } _reportError(qBindIgnoredItem); return false; }
return true; } else
if (d==R) { row++;
// TODO if (currentSize()<=row) ...
return true; } else
return w._item(); }
bool _item ( QName n) { Q_ASSERT(d!=T);
if (d==R) { row++; if (n!=childrenName) {
// TODO if (rowNames...
_reportError(qBindIgnoredItemName); return true; } } else
if (d==C) { col++; if (n!=childrenName) {
if (!columnNames.isEmpty()) {
col=columnNames.indexOf(n); if (col<0) { _reportError(qBindIgnoredItem); return false; } else return true; }
// TODO if (currentSize()<=col) ...
_reportError(qBindIgnoredItemName); return true; } } else
if (n==childrenName) {
d=R; parent=m->index(row,col,parent); row=col=0; return true; } else
return w._item(n); }
bool _out ( ) { if (d> T) { --d; return true; } return false; }
bool _sequence (quint32* =nullptr) { if (d==T) { ++d; return true; } return false; }
bool _record (quint32* =nullptr) { if (d==S) { ++d; return true; } return false; }
bool _item ( ) { if (d==S) { if (!idx.isValid()) {
m->insertRows(0,1);
idx=m->index(0,0);
}
else {
m->insertRows(idx.row(),1);
idx=idx.sibling(idx.row()+1,idx.column());
}
return true; } return false; }
bool _item ( QName n) { if (d==R) { if (n==childrenName) {
idx=idx.child(0,0);
return true;
}
else if (names.indexOf(n)>=0) {
idx=idx.sibling(idx.row(),names.indexOf(n));
return true;
}
} return false; }
private:
//! 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);
int cols = m->columnCount(parent); if (cols<=col)
m->insertColumns(cols,1+col-cols);
auto idx = m->index(row,col,parent); Q_ASSERT(!canBind() || m->checkIndex(idx)); return idx;
}
bool canBind() noexcept { return -1<=col && -1<=row; } //!< Write status is useful to bypass filtered out items
//! Returns an unlimited size if sizes.isEmpty() or the size corresponding to the current dimension or 0 if the dimension exceeds defined sizes
int currentSize() {
int dimension = d;
for (auto index = parent; index.isValid() ; index = index.parent()) {
dimension += 2;
}
return sizes.isEmpty() ? std::numeric_limits<int>::max() : dimension<sizes.size() ? sizes.at(dimension) : 0;
}
QAbstractItemModel* m;
QModelIndex idx;
QBuffer io;
TItemWriter w;
// 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 QMetaData
QUtf8String childrenName;
QList<QUtf8String> names;
QList<QUtf8String> columnNames;
QVector<int> sizes;
int d=T; // bind depth wrt successive fluent interface calls
// TODO setHeaderData on 1st item and
// TODO setHeaderData on 1st item
};
// --------------------------------------------------------------------------
......@@ -207,7 +207,6 @@ int main(int argc, char *argv[])
QBuffer b; b.open(QIODevice::ReadWrite);
QVariant v;
QDataStream d(&b);
GROUP("builtin>")//========================================================
{
START {
......@@ -680,21 +679,19 @@ int main(int argc, char *argv[])
STOP("Cbor>Json",QString::fromUtf8(b.buffer()+Text(readerErrors)))
}
GROUP_STOP
{
QVector<Person> persons; persons << person << person << person;
QStandardItemModel treeModel; QModelWriter(& treeModel).meta({{qmChildren,"phones" },{qmColumns ,"names,age"}}).bind(persons );
QStandardItemModel tableModel; QModelWriter(& tableModel).meta({ {qmColumns ,"names,age"}}).bind(persons );
QStandardItemModel matrixModel; QModelWriter(&matrixModel).meta({{qmSizes ,"4,4" } }).bind(transform);
//m.setHorizontalHeaderLabels({"names"});
QStandardItemModel treeModel; QModelWriter<>(& treeModel).meta({{qmChildren,"phones" },{qmColumns ,"names,height,age"}}).bind(persons ); // FIXME age missing if height removed
QStandardItemModel tableModel; QModelWriter<>(& tableModel).meta({ {qmColumns ,"names,height,age"}}).bind(persons );
QStandardItemModel matrixModel; QModelWriter<>(&matrixModel).meta({{qmSizes ,"4,4" } }).bind(transform);
QDialog dlg;
auto layout = new QHBoxLayout(&dlg); dlg.setLayout(layout);
auto tree = new QTreeView (&dlg); layout->addWidget(tree ); tree ->setModel(& treeModel); tree->setUniformRowHeights(true);
auto tree = new QTreeView (&dlg); layout->addWidget(tree ); tree ->setModel(& treeModel);
auto table = new QTableView (&dlg); layout->addWidget(table ); table ->setModel(& tableModel);
auto matrix = new QTableView (&dlg); layout->addWidget(matrix); matrix->setModel(&matrixModel);
dlg.adjustSize();
dlg.exec();
}
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment