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/

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

QModelReader working for simple cases allowing to change data from some

views to QList persons and other views
parent ed4b15cc
......@@ -161,63 +161,63 @@ struct IBind {
virtual bool _item(QIdentifierLiteral n) = 0;
virtual bool _out ( ) = 0; //!< End of sequence or record
virtual bool _bind( QUtf8DataView u) = 0;
virtual bool _bind( const char* u) = 0;
virtual bool _bind(QAsciiDataView a) = 0;
virtual bool _bind( QLatin1String l) = 0;
virtual bool _bind( QStringView s) = 0;
virtual bool _bind( QUtf8Data& r) = 0;
virtual bool _bind( QString& r) = 0;
virtual bool _bind( bool& r) = 0;
virtual bool _bind( qint8& r) = 0; //!< \warning Must return false instead of losing sign or digit
virtual bool _bind( quint8& r) = 0; //!< \warning Must return false instead of losing sign or digit
virtual bool _bind( qint16& r) = 0; //!< \warning Must return false instead of losing sign or digit
virtual bool _bind( quint16& r) = 0; //!< \warning Must return false instead of losing sign or digit
virtual bool _bind( qint32& r) = 0; //!< \warning Must return false instead of losing sign or digit
virtual bool _bind( quint32& r) = 0; //!< \warning Must return false instead of losing sign or digit
virtual bool _bind( qint64& r) = 0; //!< \warning Must return false instead of losing sign or digit
virtual bool _bind( quint64& r) = 0; //!< \warning Must return false instead of losing sign or digit
virtual bool _bind( float& r) = 0; //!< \warning Must return false instead of losing sign or digit
virtual bool _bind( double& r) = 0; //!< \warning Must return false instead of losing sign or digit
virtual bool _bind( QByteArray& r) = 0;
virtual bool _bind( QVariant& r) = 0;
virtual bool _bind( QUtf8DataView u) = 0;
virtual bool _bind( const char* u) = 0;
virtual bool _bind( QAsciiDataView a) = 0;
virtual bool _bind( QLatin1String l) = 0;
virtual bool _bind( QStringView s) = 0;
virtual bool _bind( QUtf8Data& r) = 0;
virtual bool _bind( QString& r) = 0;
virtual bool _bind( bool& r) = 0;
virtual bool _bind( qint8& r) = 0; //!< \warning Must return false instead of losing sign or digit
virtual bool _bind( quint8& r) = 0; //!< \warning Must return false instead of losing sign or digit
virtual bool _bind( qint16& r) = 0; //!< \warning Must return false instead of losing sign or digit
virtual bool _bind( quint16& r) = 0; //!< \warning Must return false instead of losing sign or digit
virtual bool _bind( qint32& r) = 0; //!< \warning Must return false instead of losing sign or digit
virtual bool _bind( quint32& r) = 0; //!< \warning Must return false instead of losing sign or digit
virtual bool _bind( qint64& r) = 0; //!< \warning Must return false instead of losing sign or digit
virtual bool _bind( quint64& r) = 0; //!< \warning Must return false instead of losing sign or digit
virtual bool _bind( float& r) = 0; //!< \warning Must return false instead of losing sign or digit
virtual bool _bind( double& r) = 0; //!< \warning Must return false instead of losing sign or digit
virtual bool _bind( QByteArray& r) = 0;
virtual bool _bind( QVariant& r) = 0;
// TODO QChar, QDateTime, QDate, QTime, QUuid (text or numerical)
// Overloads for const& and && T
virtual bool _bind(const QUtf8Data& r) = 0;
virtual bool _bind(const QString& r) = 0;
virtual bool _bind(const bool& r) = 0;
virtual bool _bind(const qint8& r) = 0;
virtual bool _bind(const quint8& r) = 0;
virtual bool _bind(const qint16& r) = 0;
virtual bool _bind(const quint16& r) = 0;
virtual bool _bind(const qint32& r) = 0;
virtual bool _bind(const quint32& r) = 0;
virtual bool _bind(const qint64& r) = 0;
virtual bool _bind(const quint64& r) = 0;
virtual bool _bind(const float& r) = 0;
virtual bool _bind(const double& r) = 0;
virtual bool _bind(const QByteArray& r) = 0;
virtual bool _bind(const QVariant& r) = 0;
virtual bool _bind( QUtf8Data&& r) = 0;
virtual bool _bind( QString&& r) = 0;
virtual bool _bind( bool&& r) = 0;
virtual bool _bind( qint8&& r) = 0;
virtual bool _bind( quint8&& r) = 0;
virtual bool _bind( qint16&& r) = 0;
virtual bool _bind( quint16&& r) = 0;
virtual bool _bind( qint32&& r) = 0;
virtual bool _bind( quint32&& r) = 0;
virtual bool _bind( qint64&& r) = 0;
virtual bool _bind( quint64&& r) = 0;
virtual bool _bind( float&& r) = 0;
virtual bool _bind( double&& r) = 0;
virtual bool _bind( QByteArray&& r) = 0;
virtual bool _bind( QVariant&& r) = 0;
virtual bool _bind(const QUtf8Data& r) = 0;
virtual bool _bind(const QString& r) = 0;
virtual bool _bind(const bool& r) = 0;
virtual bool _bind(const qint8& r) = 0;
virtual bool _bind(const quint8& r) = 0;
virtual bool _bind(const qint16& r) = 0;
virtual bool _bind(const quint16& r) = 0;
virtual bool _bind(const qint32& r) = 0;
virtual bool _bind(const quint32& r) = 0;
virtual bool _bind(const qint64& r) = 0;
virtual bool _bind(const quint64& r) = 0;
virtual bool _bind(const float& r) = 0;
virtual bool _bind(const double& r) = 0;
virtual bool _bind(const QByteArray& r) = 0;
virtual bool _bind(const QVariant& r) = 0;
virtual bool _bind( QUtf8Data&& r) = 0;
virtual bool _bind( QString&& r) = 0;
virtual bool _bind( bool&& r) = 0;
virtual bool _bind( qint8&& r) = 0;
virtual bool _bind( quint8&& r) = 0;
virtual bool _bind( qint16&& r) = 0;
virtual bool _bind( quint16&& r) = 0;
virtual bool _bind( qint32&& r) = 0;
virtual bool _bind( quint32&& r) = 0;
virtual bool _bind( qint64&& r) = 0;
virtual bool _bind( quint64&& r) = 0;
virtual bool _bind( float&& r) = 0;
virtual bool _bind( double&& r) = 0;
virtual bool _bind( QByteArray&& r) = 0;
virtual bool _bind( QVariant&& r) = 0;
virtual bool _any() { return _null(); }
......@@ -1022,11 +1022,19 @@ struct QBind<QVector<T>> {
}
else if (v->mode()==Read) {
auto s(v.sequence());
Val<Seq<Cursor>> i;
Val<Seq<Cursor>> i; int it = 0;
while ((i = s.item())) {
T t;
if((s = i.bind(t))) // gives back control to s, enabling the next s.item() call
ts.append(t);
if (it==ts.size()) {
T t;
if ((s = i.bind(t))) // gives back control to s, enabling the next s.item() call
ts.insert(it++, t);
// TODO else s = i.any();
}
else {
T t(ts[it]);
if ((s = i.bind(t)))
ts[it++] = t;
}
}
return s;
}
......@@ -1051,15 +1059,27 @@ struct QBind<QList<T>> {
}
static Cursor bind(Val<Cursor>&& v, QList<T>& ts) {
if (v->mode()==Write) {
return bind(std::move(v),QList<T>(ts));
quint32 size=quint32(ts.size());
auto s(v.sequence(&size));
for (auto&& t : ts) {
s = s.bind(t);
}
return s;
}
else if (v->mode()==Read) {
auto s(v.sequence());
Val<Seq<Cursor>> i;
Val<Seq<Cursor>> i; int it = 0;
while ((i = s.item())) {
T v;
if ((s = i.bind(v)))
ts.append(v);
if (it==ts.size()) {
T t;
if ((s = i.bind(t)))
ts.insert(it++, t);
}
else {
T t(ts[it]);
if ((s = i.bind(t)))
ts[it++] = t;
}
}
return s;
}
......@@ -1078,7 +1098,7 @@ struct QBind<QMap<QString,T>> {
quint32 size=quint32(ts.size());
auto s(v.record(&size));
for (QString key : ts.keys()) {
s = s.bind(key.toUtf8().constData(),ts[key]);
s = s.bind(key.toLatin1().constData(),ts[key]);
}
return s;
}
......@@ -1086,15 +1106,20 @@ struct QBind<QMap<QString,T>> {
}
static Cursor bind(Val<Cursor>&& v, QMap<QString,T>& ts) {
if (v->mode()==Write) {
return bind(std::move(v),QMap<QString,T>(ts));
quint32 size=quint32(ts.size());
auto s(v.record(&size));
for (QString key : ts.keys()) {
s = s.bind(key.toLatin1().constData(),ts[key]);
}
return s;
}
else if (v->mode()==Read) {
auto r(v.record());
QIdentifier name; Val<Rec<Cursor>> i;
while ((i = r.item(name))) {
T value;
T value(ts[name.latin1()]);
if ((r = i.bind(value)))
ts.insert(name.utf8(),value);
ts.insert(name.latin1(),value);
}
return r;
}
......
......@@ -231,6 +231,18 @@ class QJsonReader : public IReader
Q_DISABLE_COPY(QJsonReader)
public:
QJsonReader(QIODevice* io) : io(io), cacheWriter(&cachedValue), cacheReader(&cachedValue) { Q_ASSERT(io); }
void reset(QIODevice* other) {
errors.clear(); levels.clear();
line=0; column=0; index=-1;
isChoice=false;
cachedNumber = None; d=.0; i=0; neg=bool();
cacheLevel = 0; cachedValue = QJsonValue();
cacheWriter.reset(&cachedValue);
caching = nullptr; //!< Only used when cacheLevel>=1 && key!=expectedKey
cacheReader.reset(&cachedValue);
io=other;
Q_ASSERT(io);
}
struct Step { int index; const char* end; QMap<QIdentifier,QJsonValue/*TODO QVariant for meta() support*/> cachedItems; Step(int i=-1, const char* e=nullptr) : index(i), end(e) {} };
struct Error { QIdentifierLiteral error; int line; int column; int index; template<class T> T bind(Val<T>&& value) { QByteArray u(error.utf8()); u.append(' ').append(QByteArray::number(line)).append(':').append(QByteArray::number(column)); return value.bind(QUtf8Data(u)); } };
......@@ -465,7 +477,8 @@ private:
return false;
}
char getChar () { char c; if (io->getChar(&c) ) { if (c=='\n') { line++; column=0; } else { column++; } index++; return c; } return '\0'; }
char nextChar() { char c; if (io->peek (&c,1)==1) { return c; } return '\0'; }
char nextChar() { char c; if (io->peek (&c,1)==1) {
return c; } return '\0'; }
char next(const char* validChars, char expected='\0') {
if (validChars) {
while (!(nextChar() == expected || strchr(validChars, nextChar()) || nextChar() == '\0')) {
......
This diff is collapsed.
......@@ -64,10 +64,13 @@
#include <QtWidgets/qtreeview.h>
#include <QtWidgets/qtableview.h>
#include <QtWidgets/qdialog.h>
#include <QtWidgets/qboxlayout.h>
#include <QtWidgets/qsplitter.h>
#include <QtWidgets/qgridlayout.h>
#include <QtWidgets/qtabwidget.h>
#include <QtWidgets/qlabel.h>
#include <QtWidgets/qapplication.h>
#include <tuple>
// //////////////////////////////////////////////////////////////////////////
// QBind-enabled types examples
......@@ -82,18 +85,17 @@ struct Person
QString firstName, lastName; double height; int age; QVector<Phone> phones; QString comments; QList<Person> children;
Cursor bind(Val<Cursor>&& value) { // works with value->mode()==Read as well as Write
return value
.record("Person")
.sequence("names")
.bind(firstName)
.bind( lastName)
.out()
.bind("height" ,height )
.bind("age" ,age ,-1) // reads null() as -1
.bind("phones" ,phones ) // recursive calls to QBind will take care of that part
.bind("comments",comments)
.bind("children",children)
; // automagically closes opened record()
auto r = value.record("Person");
auto s = r.sequence("names");
s = s.bind(firstName);
s = s.bind( lastName);
r = s.out();
r = r.bind("height" ,height );
r = r.bind("age" ,age ,-1); // reads null() as -1
r = r.bind("phones" ,phones ); // recursive calls to QBind will take care of that part
r = r.bind("comments",comments);
r = r.bind("children",children);
return r; // automagically closes opened record()
}
};
......@@ -1010,7 +1012,8 @@ void doGuiExample() {
person.lastName="";
person.comments="";
person.phones.append(phone);
QList<Person> persons; persons << person << person;
QList<Person> persons;
persons << person << person;
persons[0].age=42;
persons[0].children.append(person);
persons[0].children[0].firstName="Joe";
......@@ -1021,20 +1024,8 @@ void doGuiExample() {
persons[0].height=1.72;
persons[1].phones.append(Phone{Phone::Office,"112"});
// Generic data structures to bind with
QStandardItemModel matrixModel, treeModel, tableModel, viewModel, customModel, flatModel;
// Using meta() to drive various custom bind
QModelWriter<>(&matrixModel,false).value().meta(qmSizes ,"4,3" ).bind(transform);
QModelWriter<>(& treeModel ).value().meta(qmChildren,"children" )
/*.meta(qmColumns ,"names,age")*/.bind(persons);
QModelWriter<>(& tableModel ).value().meta(qmColumns ,"names,age") .bind(persons);
// Various possibilities to customize bind
// Using view types (non owning const & with a custom bind method)
QModelWriter<TextWriter>(& viewModel).value().bind(PersonsView{persons});
#if 0
// Design that works for Read/Write but requires several cumbersome functions
QModelWriter<>(&customModel).sequence().forEach(persons, [](Person& p, Val<Cursor>&& item)->Cursor {
......@@ -1048,41 +1039,100 @@ void doGuiExample() {
Phone::isOffice)
; // automagically closed while cast to returned Cursor type
});
#else
// More expressive design similar to Python list comprehensions that does not work by default for Read/Write
QModelWriter<>(&customModel).sequence().with([&](Seq<Cursor>&& s) {
for (auto&& person : persons) { // Read would require looping while !s.item()
s = s // To keep working with the active Cursor
.record()
.item("first name")
.meta(qmColor, person.age >= 42 ? "green" : "blue")
.bind(person.firstName)
.item("office phone").with([&](Val<Cursor>&& v) {
for (auto&& phone : person.phones) {
if (phone._t == Phone::Office) {
return v.bind(phone._n);
}
}
return v.null();
})
.out();
}
return std::move(s); // So caller stops calling IBind if user function was unable to keep track of the active Cursor
});
#endif
// The same design allows flattening trees into a sequence
QModelWriter<>(& flatModel).sequence().with(persons, flatten);
QDialog dlg;
auto layout = new QVBoxLayout(&dlg); dlg.setLayout(layout);
auto r1 = new QSplitter (&dlg); layout->addWidget(r1);
auto r2 = new QSplitter (&dlg); layout->addWidget(r2);
auto matrix = new QTableView(&dlg); r1 ->addWidget(matrix); matrix->setModel(&matrixModel); matrix->resizeColumnsToContents();
auto flat = new QTableView(&dlg); r1 ->addWidget(flat ); flat ->setModel(& flatModel); flat ->resizeColumnsToContents();
auto tree = new QTreeView (&dlg); r1 ->addWidget(tree ); tree ->setModel(& treeModel); for(int i=0; i<treeModel.columnCount(); i++) tree->resizeColumnToContents(i);
auto table = new QTableView(&dlg); r2 ->addWidget(table ); table ->setModel(& tableModel); table ->resizeColumnsToContents();
auto custom = new QTableView(&dlg); r2 ->addWidget(custom); custom->setModel(&customModel); custom->resizeColumnsToContents();
auto view = new QTreeView (&dlg); r2 ->addWidget(view ); view ->setModel(& viewModel); for(int i=0; i<viewModel.columnCount(); i++) view->resizeColumnToContents(i);
auto grid = new QGridLayout(&dlg); grid->setColumnStretch(0, 1); grid->setColumnStretch(1, 3);
dlg.setLayout(grid);
auto r0Label = new QLabel(&dlg); grid->addWidget(r0Label, 0, 0); r0Label->setWordWrap(true); r0Label->setMinimumWidth(100); r0Label->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Expanding);
auto r0 = new QTabWidget(&dlg); grid->addWidget(r0 , 0, 1);
struct { QStandardItemModel* model; QAbstractItemView* widget; const char* name; QBindLambda bind; } transformTabs[] = {
{ new QStandardItemModel(&dlg), new QTableView(&dlg), "bind(transform)" , [&](Val<Cursor>&& v) { return v .bind(transform); } },
{ new QStandardItemModel(&dlg), new QTableView(&dlg), "meta(qmSizes,\"4,3\")...", [&](Val<Cursor>&& v) { return v.meta(qmSizes,"4,3").bind(transform); } },
};
for (auto&& t: transformTabs) { r0->addTab(t.widget, t.name); t.widget->setModel(t.model); }
int currentTransformTab = -1;
QObject::connect(r0, &QTabWidget::currentChanged, [&](int newTab) {
if (0<=currentTransformTab)
transformTabs[currentTransformTab].bind(QModelReader<>(transformTabs[currentTransformTab].model, false).value());
QByteArray json;
QJsonWriter(&json).bind(transform);
r0Label->setText(QString::fromUtf8(json));
transformTabs[newTab].model->clear();
transformTabs[newTab].bind(QModelWriter<>(transformTabs[newTab].model, false).value());
auto table = qobject_cast<QTableView*>(transformTabs[newTab].widget); table->resizeColumnsToContents(); table->resizeRowsToContents();
currentTransformTab = newTab;
});
r0->setCurrentIndex(0);
auto r1Label = new QLabel(&dlg); grid->addWidget(r1Label, 1, 0); r1Label->setWordWrap(true); r1Label->setMinimumWidth(100); r1Label->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Expanding);
auto r1 = new QTabWidget(&dlg); grid->addWidget(r1 , 1, 1);
struct { QStandardItemModel* model; QAbstractItemView* widget; const char* name; QBindLambda bind; } personsTabs[] = {
{ new QStandardItemModel(&dlg), new QTableView(&dlg), "bind(persons)", [&](Val<Cursor>&& v) {
return v.bind(persons); } },
// Using meta() to drive various custom bind
{ new QStandardItemModel(&dlg), new QTableView(&dlg), "meta(qmColumns,\"names,age\")...", [&](Val<Cursor>&& v) {
return v.meta(qmColumns,"names,age").bind(persons); } },
{ new QStandardItemModel(&dlg), new QTreeView (&dlg), "meta(qmChildren,\"children\")...", [&](Val<Cursor>&& v) {
return v.meta(qmChildren,"children").bind(persons); } },
// Using view types (non-owning const& with a custom bind method)
{ new QStandardItemModel(&dlg), new QTreeView (&dlg), "bind(PersonsView{persons})", [&](Val<Cursor>&& v) {
return v.bind(PersonsView{persons}); } },
// Using sequence comprehensions similar to Python (that does not work by default for Read/Write)
{ new QStandardItemModel(&dlg), new QTableView(&dlg), "sequence().with([&](...){for...", [&](Val<Cursor>&& v) {
return v.sequence().with([&](Seq<Cursor>&& s) {
for (auto&& person : persons) { // Read would require looping while !s.item()
s = s // To keep working with the active Cursor
.record()
.item("first name")
.meta(qmColor, person.age >= 42 ? "green" : "blue")
.bind(person.firstName)
.item("office phone").with([&](Val<Cursor>&& v) {
for (auto&& phone : person.phones) {
if (phone._t == Phone::Office) {
return v.bind(phone._n);
}
}
return v.null();
})
.out();
}
return std::move(s); // So caller stops calling IBind if user function was unable to keep track of the active Cursor
});}},
// The same design allows flattening trees into a sequence
{ new QStandardItemModel(&dlg), new QTableView(&dlg), "sequence().with(persons,flatten)", [&](Val<Cursor>&& v) {
return v.sequence().with(persons,flatten); } },
};
for (auto&& t: personsTabs) { r1->addTab(t.widget, t.name); t.widget->setModel(t.model); }
int currentPersonsTab = -1;
QObject::connect(r1, &QTabWidget::currentChanged, [&](int newTab) {
if (0<=currentPersonsTab)
personsTabs[currentPersonsTab].bind(QModelReader<>(personsTabs[currentPersonsTab].model).value());
QByteArray json;
QJsonWriter(&json).bind(persons);
r1Label->setText(QString::fromUtf8(json));
personsTabs[newTab].model->clear();
personsTabs[newTab].bind(QModelWriter<>(personsTabs[newTab].model).value());
auto table = qobject_cast<QTableView*>(personsTabs[newTab].widget); if (table) { table->resizeColumnsToContents(); table->resizeRowsToContents(); }
auto tree = qobject_cast< QTreeView*>(personsTabs[newTab].widget); if (tree ) for(int i=0; i<personsTabs[newTab].model->columnCount(); i++) tree->resizeColumnToContents(i);
currentPersonsTab = newTab;
});
r1->setCurrentIndex(0);
dlg.resize(960,360);
dlg.exec();
}
Markdown is supported
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