bugs fixed, QskModelObjectBinder improved
This commit is contained in:
parent
1a5dc6d358
commit
8faa6a8cad
|
@ -17,60 +17,77 @@
|
|||
#include <QSqlTableModel>
|
||||
#include <QSqlRecord>
|
||||
|
||||
Window::Window()
|
||||
namespace
|
||||
{
|
||||
auto db = QSqlDatabase::addDatabase( "QSQLITE" );
|
||||
class Model : public QSqlTableModel
|
||||
{
|
||||
public:
|
||||
Model( QObject *parent = nullptr )
|
||||
: QSqlTableModel( parent, QSqlDatabase::addDatabase( "QSQLITE" ) )
|
||||
{
|
||||
auto db = database();
|
||||
|
||||
db.setDatabaseName( ":memory:" );
|
||||
db.open();
|
||||
|
||||
QSqlQuery q(db);
|
||||
q.exec( "create table test(id integer,value text);" );
|
||||
q.exec( "insert into test (id,value) values (1,'HELLO');" );
|
||||
q.exec( "insert into test (id,value) values (2,'WORLD');" );
|
||||
QSqlQuery query( db );
|
||||
query.exec( "create table test(id integer,value text);" );
|
||||
query.exec( "insert into test (id,value) values (1,'HELLO');" );
|
||||
query.exec( "insert into test (id,value) values (2,'WORLD');" );
|
||||
|
||||
auto table = new QSqlTableModel( nullptr, db );
|
||||
table->setTable( "test" );
|
||||
table->select();
|
||||
|
||||
auto txt = new QskTextInput();
|
||||
auto spin = new QskSpinBox();
|
||||
|
||||
auto mapper = new QskModelObjectBinder();
|
||||
mapper->bindModel( table );
|
||||
|
||||
mapper->bindObject( spin, 0 );
|
||||
mapper->bindObject( txt, 1 );
|
||||
|
||||
// this loads the record from the first row and updates the controls data.
|
||||
mapper->setCurrentRow(0);
|
||||
|
||||
auto v = new QskLinearBox(Qt::Vertical);
|
||||
v->addSpacer( 0,100 );
|
||||
v->addItem( spin );
|
||||
v->addItem( txt );
|
||||
addItem(v);
|
||||
|
||||
auto h = new QskLinearBox(Qt::Horizontal);
|
||||
auto prev = new QskPushButton("<",h);
|
||||
auto next = new QskPushButton(">",h);
|
||||
connect(prev,&QskPushButton::clicked,[ = ]() { mapper->setCurrentRow( 0 ); });
|
||||
connect(next,&QskPushButton::clicked,[ = ]() { mapper->setCurrentRow( 1 ); });
|
||||
v->addItem(h);
|
||||
|
||||
auto save = new QskPushButton("Save Data to Model",v);
|
||||
connect(save,&QskPushButton::clicked,[ = ]() {
|
||||
// this will update the current record with the data from the SpinBox and TextInput
|
||||
mapper->updateModel();
|
||||
// just for illustration we print out the record
|
||||
auto r = table->record(mapper->currentRow() );
|
||||
qDebug() << r;
|
||||
});
|
||||
auto set0 = new QskPushButton("Set Model field to 0",v);
|
||||
connect(set0,&QskPushButton::clicked,[ = ]() {
|
||||
// this should trigger the binder and update the spinbox
|
||||
table->setData( table->index(mapper->currentRow(),0),0 );
|
||||
});
|
||||
v->addSpacer( 0,100 );
|
||||
setTable( "test" );
|
||||
select();
|
||||
}
|
||||
|
||||
#include "moc_Window.cpp"
|
||||
void setValue( int row, const QVariant &value )
|
||||
{
|
||||
setData( index( row, 0 ), value );
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
Window::Window()
|
||||
{
|
||||
auto model = new Model( this );
|
||||
|
||||
auto textInput = new QskTextInput();
|
||||
auto spinBox = new QskSpinBox();
|
||||
|
||||
auto mapper = new QskModelObjectBinder( model, this );
|
||||
|
||||
mapper->bindObject( spinBox, 0 );
|
||||
mapper->bindObject( textInput, 1 );
|
||||
|
||||
auto vBox = new QskLinearBox( Qt::Vertical );
|
||||
vBox->addSpacer( 0, 100 );
|
||||
vBox->addItem( spinBox );
|
||||
vBox->addItem( textInput );
|
||||
|
||||
addItem( vBox );
|
||||
|
||||
auto hBox = new QskLinearBox( Qt::Horizontal );
|
||||
|
||||
{
|
||||
auto prev = new QskPushButton( "<", hBox );
|
||||
auto next = new QskPushButton( ">", hBox);
|
||||
|
||||
connect(prev, &QskPushButton::clicked,
|
||||
[ mapper ]() { mapper->setCurrentRow( 0 ); });
|
||||
|
||||
connect( next, &QskPushButton::clicked,
|
||||
[ mapper ]() { mapper->setCurrentRow( 1 ); });
|
||||
|
||||
vBox->addItem( hBox );
|
||||
}
|
||||
|
||||
// update the current record with the data from the SpinBox and TextInput
|
||||
auto save = new QskPushButton( "Save Data to Model", vBox );
|
||||
connect( save, &QskPushButton::clicked,
|
||||
[=]() { mapper->submit(); qDebug() << model->record( mapper->currentRow() ); });
|
||||
|
||||
// trigger the binder and update the spinbox
|
||||
auto set0 = new QskPushButton( "Set Model field to 0", vBox );
|
||||
connect( set0, &QskPushButton::clicked,
|
||||
[=]() { model->setValue( mapper->currentRow(), 0 ); } );
|
||||
vBox->addSpacer( 0,100 );
|
||||
}
|
||||
|
|
|
@ -9,8 +9,6 @@
|
|||
|
||||
class Window : public QskWindow
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
Window();
|
||||
};
|
||||
|
|
|
@ -19,6 +19,21 @@ static inline QMetaProperty qskMetaProperty(
|
|||
return ( idx >= 0 ) ? metaObject->property( idx ) : QMetaProperty();
|
||||
}
|
||||
|
||||
static void qskEnableConnections( QObject* object,
|
||||
QskModelObjectBinder* binder, bool on )
|
||||
{
|
||||
if ( on )
|
||||
{
|
||||
QObject::connect( object, &QObject::destroyed,
|
||||
binder, &QskModelObjectBinder::unbindObject );
|
||||
}
|
||||
else
|
||||
{
|
||||
QObject::disconnect( object, &QObject::destroyed,
|
||||
binder, &QskModelObjectBinder::unbindObject );
|
||||
}
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
struct Binding
|
||||
|
@ -37,17 +52,29 @@ namespace
|
|||
class QskModelObjectBinder::PrivateData
|
||||
{
|
||||
public:
|
||||
void updateProperties()
|
||||
{
|
||||
if ( model && currentRowIndex.isValid() )
|
||||
{
|
||||
for ( auto it = bindings.constBegin(); it != bindings.constEnd(); ++it )
|
||||
updateObjectProperty( it.key(), it.value() );
|
||||
}
|
||||
}
|
||||
|
||||
void updateProperties( const QModelIndex& topLeft,
|
||||
const QModelIndex& bottomRight, const QVector< int >& roles )
|
||||
{
|
||||
if ( !roles.contains( Qt::EditRole ) )
|
||||
if ( !( model && currentRowIndex.isValid() ) )
|
||||
return;
|
||||
|
||||
if ( !roles.isEmpty() && roles.contains( Qt::EditRole ) )
|
||||
return;
|
||||
|
||||
const int row = currentRowIndex.row();
|
||||
|
||||
if ( topLeft.row() <= row && row <= bottomRight.row() )
|
||||
{
|
||||
for ( auto it = bindings.begin(); it != bindings.end(); ++it )
|
||||
for ( auto it = bindings.constBegin(); it != bindings.constEnd(); ++it )
|
||||
{
|
||||
const int col = it.value().column;
|
||||
|
||||
|
@ -78,7 +105,7 @@ QskModelObjectBinder::QskModelObjectBinder( QObject* parent )
|
|||
QskModelObjectBinder::QskModelObjectBinder( QAbstractItemModel* model, QObject* parent )
|
||||
: QskModelObjectBinder( parent )
|
||||
{
|
||||
bindModel( model );
|
||||
setModel( model );
|
||||
}
|
||||
|
||||
void QskModelObjectBinder::bindObject(
|
||||
|
@ -94,9 +121,13 @@ void QskModelObjectBinder::bindObject(
|
|||
|
||||
if ( metaProperty.isValid() )
|
||||
{
|
||||
m_data->bindings.insert( object, { column, metaProperty } );
|
||||
connect( object, &QObject::destroyed,
|
||||
this, &QskModelObjectBinder::unbindObject );
|
||||
const Binding binding = { column, metaProperty };
|
||||
|
||||
m_data->bindings.insert( object, binding );
|
||||
qskEnableConnections( object, this, true );
|
||||
|
||||
if ( m_data->model && m_data->currentRowIndex.isValid() )
|
||||
m_data->updateObjectProperty( object, binding );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -105,20 +136,37 @@ void QskModelObjectBinder::unbindObject( QObject* object )
|
|||
auto it = m_data->bindings.find( object );
|
||||
if ( it != m_data->bindings.end() )
|
||||
{
|
||||
disconnect( object, &QObject::destroyed,
|
||||
this, &QskModelObjectBinder::unbindObject );
|
||||
|
||||
qskEnableConnections( object, this, false );
|
||||
m_data->bindings.erase( it );
|
||||
}
|
||||
}
|
||||
|
||||
void QskModelObjectBinder::bindModel( QAbstractItemModel* model )
|
||||
void QskModelObjectBinder::clearBindings()
|
||||
{
|
||||
auto& bindings = m_data->bindings;
|
||||
|
||||
for ( auto it = bindings.constBegin(); it != bindings.constEnd(); ++it )
|
||||
qskEnableConnections( it.key(), this, false );
|
||||
|
||||
bindings.clear();
|
||||
}
|
||||
|
||||
void QskModelObjectBinder::setModel( QAbstractItemModel* model )
|
||||
{
|
||||
if ( model == m_data->model )
|
||||
return;
|
||||
|
||||
if ( m_data->model )
|
||||
disconnect( m_data->model, nullptr, this, nullptr );
|
||||
{
|
||||
disconnect( m_data->model, &QAbstractItemModel::dataChanged, this, nullptr );
|
||||
|
||||
m_data->model = nullptr;
|
||||
m_data->currentRowIndex = QModelIndex();
|
||||
|
||||
clearBindings();
|
||||
}
|
||||
|
||||
m_data->model = model;
|
||||
m_data->currentRowIndex = QModelIndex();
|
||||
|
||||
if( model )
|
||||
{
|
||||
|
@ -131,20 +179,40 @@ void QskModelObjectBinder::bindModel( QAbstractItemModel* model )
|
|||
|
||||
connect( m_data->model, &QAbstractItemModel::dataChanged,
|
||||
this, updateProperties );
|
||||
|
||||
connect( m_data->model, &QObject::destroyed,
|
||||
this, &QskModelObjectBinder::clearBindings );
|
||||
|
||||
setCurrentRow( 0 );
|
||||
}
|
||||
}
|
||||
|
||||
const QAbstractItemModel* QskModelObjectBinder::model() const
|
||||
{
|
||||
return m_data->model;
|
||||
}
|
||||
|
||||
QAbstractItemModel* QskModelObjectBinder::model()
|
||||
{
|
||||
return m_data->model;
|
||||
}
|
||||
|
||||
void QskModelObjectBinder::setCurrentRow( int row )
|
||||
{
|
||||
Q_ASSERT( m_data->model != nullptr );
|
||||
auto model = m_data->model.data();
|
||||
auto& bindings = m_data->bindings;
|
||||
|
||||
if ( m_data->model == nullptr )
|
||||
return;
|
||||
Q_ASSERT( model != nullptr );
|
||||
|
||||
m_data->currentRowIndex = m_data->model->index( row, 0 );
|
||||
if ( model && row >= 0 && row < model->rowCount() )
|
||||
{
|
||||
m_data->currentRowIndex = model->index( row, 0 );
|
||||
|
||||
for ( auto it = m_data->bindings.begin(); it != m_data->bindings.end(); ++it )
|
||||
for ( auto it = bindings.constBegin(); it != bindings.constEnd(); ++it )
|
||||
m_data->updateObjectProperty( it.key(), it.value() );
|
||||
|
||||
Q_EMIT currentRowChanged( row );
|
||||
}
|
||||
}
|
||||
|
||||
int QskModelObjectBinder::currentRow() const
|
||||
|
@ -152,7 +220,7 @@ int QskModelObjectBinder::currentRow() const
|
|||
return m_data->currentRowIndex.row();
|
||||
}
|
||||
|
||||
void QskModelObjectBinder::updateModel()
|
||||
void QskModelObjectBinder::submit()
|
||||
{
|
||||
if ( auto model = m_data->model )
|
||||
{
|
||||
|
@ -170,4 +238,9 @@ void QskModelObjectBinder::updateModel()
|
|||
}
|
||||
}
|
||||
|
||||
void QskModelObjectBinder::revert()
|
||||
{
|
||||
m_data->updateProperties();
|
||||
}
|
||||
|
||||
#include "moc_QskModelObjectBinder.cpp"
|
||||
|
|
|
@ -19,20 +19,33 @@ class QSK_EXPORT QskModelObjectBinder : public QObject
|
|||
{
|
||||
Q_OBJECT
|
||||
|
||||
Q_PROPERTY( int currentRow READ currentRow
|
||||
WRITE setCurrentRow NOTIFY currentRowChanged )
|
||||
|
||||
public:
|
||||
QskModelObjectBinder( QObject* parent = nullptr );
|
||||
QskModelObjectBinder( QAbstractItemModel*, QObject* parent = nullptr );
|
||||
|
||||
void setModel( QAbstractItemModel* );
|
||||
|
||||
const QAbstractItemModel* model() const;
|
||||
QAbstractItemModel* model();
|
||||
|
||||
void setCurrentRow( int row );
|
||||
int currentRow() const;
|
||||
|
||||
void bindObject( QObject*, int column,
|
||||
const QByteArray& propertyName = QByteArray() );
|
||||
|
||||
void unbindObject( QObject* );
|
||||
void bindModel( QAbstractItemModel* );
|
||||
|
||||
void setCurrentRow( int row );
|
||||
[[nodiscard]] int currentRow() const;
|
||||
Q_SIGNALS:
|
||||
void currentRowChanged( int );
|
||||
|
||||
void updateModel();
|
||||
public Q_SLOTS:
|
||||
void submit();
|
||||
void revert();
|
||||
void clearBindings();
|
||||
|
||||
private:
|
||||
class PrivateData;
|
||||
|
|
Loading…
Reference in New Issue