Compare commits
17 Commits
master
...
features/m
Author | SHA1 | Date |
---|---|---|
|
9040e006ad | |
|
d9ef4f51ae | |
|
04e3378abb | |
|
52686242ec | |
|
c6fc72e07c | |
|
69eae90d3a | |
|
a888d9c5a8 | |
|
cd8fd0d2b2 | |
|
6a547e4698 | |
|
0a651782ba | |
|
7b4db3afc1 | |
|
e2486f914d | |
|
60c7442fd0 | |
|
8faa6a8cad | |
|
1a5dc6d358 | |
|
59afa42c84 | |
|
6ea2126638 |
|
@ -9,6 +9,7 @@ add_subdirectory(shadows)
|
||||||
add_subdirectory(shapes)
|
add_subdirectory(shapes)
|
||||||
add_subdirectory(charts)
|
add_subdirectory(charts)
|
||||||
add_subdirectory(plots)
|
add_subdirectory(plots)
|
||||||
|
add_subdirectory(models)
|
||||||
|
|
||||||
if (BUILD_INPUTCONTEXT)
|
if (BUILD_INPUTCONTEXT)
|
||||||
add_subdirectory(inputpanel)
|
add_subdirectory(inputpanel)
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
############################################################################
|
||||||
|
# QSkinny - Copyright (C) The authors
|
||||||
|
# SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
############################################################################
|
||||||
|
|
||||||
|
qsk_add_example(models MainView.h MainView.cpp main.cpp)
|
||||||
|
target_link_libraries(models)
|
|
@ -0,0 +1,215 @@
|
||||||
|
/******************************************************************************
|
||||||
|
* QSkinny - Copyright (C) The authors
|
||||||
|
* SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
#include "MainView.h"
|
||||||
|
|
||||||
|
#include <QskLinearBox.h>
|
||||||
|
#include <QskPushButton.h>
|
||||||
|
#include <QskTextLabel.h>
|
||||||
|
#include <QskTextField.h>
|
||||||
|
#include <QskSpinBox.h>
|
||||||
|
#include <QskSeparator.h>
|
||||||
|
#include <QskFontRole.h>
|
||||||
|
#include <QskModelObjectBinder.h>
|
||||||
|
|
||||||
|
#include <QStandardItemModel>
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
class TitleLabel : public QskTextLabel
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
TitleLabel( const QString& text, QQuickItem* parent = nullptr )
|
||||||
|
: QskTextLabel( text, parent )
|
||||||
|
{
|
||||||
|
setFontRole( QskFontRole::Title );
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class SpinBox : public QskSpinBox
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
SpinBox( QQuickItem* parent = nullptr )
|
||||||
|
: QskSpinBox( -100.0, 100.0, 1.0, parent )
|
||||||
|
{
|
||||||
|
initSizePolicy( QskSizePolicy::Fixed, QskSizePolicy::Fixed );
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class Header : public QskLinearBox
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
Header( QQuickItem* parent = nullptr )
|
||||||
|
: QskLinearBox( Qt::Horizontal, parent )
|
||||||
|
{
|
||||||
|
initSizePolicy( QskSizePolicy::Ignored, QskSizePolicy::Fixed );
|
||||||
|
|
||||||
|
setPaddingHint( QskBox::Panel, 5 );
|
||||||
|
|
||||||
|
setPanel( true );
|
||||||
|
|
||||||
|
auto rowButton = new QskPushButton( "Toggle Row" );
|
||||||
|
auto submitButton = new QskPushButton( "Submit Changes" );
|
||||||
|
|
||||||
|
connect( rowButton, &QskPushButton::clicked,
|
||||||
|
this, &Header::rowClicked );
|
||||||
|
|
||||||
|
connect( submitButton, &QskPushButton::clicked,
|
||||||
|
this, &Header::submitClicked );
|
||||||
|
|
||||||
|
addItem( rowButton );
|
||||||
|
addItem( submitButton );
|
||||||
|
addStretch( 1 );
|
||||||
|
}
|
||||||
|
|
||||||
|
Q_SIGNALS:
|
||||||
|
void rowClicked();
|
||||||
|
void submitClicked();
|
||||||
|
};
|
||||||
|
|
||||||
|
class Model : public QStandardItemModel
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Model( QObject* parent = nullptr )
|
||||||
|
: QStandardItemModel( 2, 2, parent )
|
||||||
|
{
|
||||||
|
initValue( 0, 0, 1.0 );
|
||||||
|
initValue( 0, 1, "HELLO" );
|
||||||
|
|
||||||
|
initValue( 1, 0, 2.0 );
|
||||||
|
initValue( 1, 1, "WORLD" );
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void initValue( int row, int col, const QVariant& value )
|
||||||
|
{
|
||||||
|
setData( index( row, col ), value, Qt::EditRole );
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class DisplayBox : public QskLinearBox
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
DisplayBox( QQuickItem* parent = nullptr )
|
||||||
|
: QskLinearBox( Qt::Horizontal, parent )
|
||||||
|
{
|
||||||
|
setMargins( 10, 0, 10, 0 );
|
||||||
|
initSizePolicy( QskSizePolicy::MinimumExpanding, QskSizePolicy::Fixed );
|
||||||
|
|
||||||
|
addItem( new SpinBox() );
|
||||||
|
addItem( new QskTextField() );
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class ModelBox : public QskLinearBox
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ModelBox( QAbstractItemModel* model )
|
||||||
|
: QskLinearBox( Qt::Horizontal, model->columnCount() )
|
||||||
|
, m_model( model )
|
||||||
|
{
|
||||||
|
setMargins( 10, 0, 10, 0 );
|
||||||
|
setExtraSpacingAt( Qt::BottomEdge );
|
||||||
|
|
||||||
|
for ( int row = 0; row < model->rowCount(); row++ )
|
||||||
|
{
|
||||||
|
for ( int col = 0; col < model->columnCount(); col++ )
|
||||||
|
{
|
||||||
|
const auto value = model->data(
|
||||||
|
model->index( row, col ), Qt::EditRole );
|
||||||
|
|
||||||
|
if ( value.userType() == QVariant::Double )
|
||||||
|
{
|
||||||
|
auto spinBox = new SpinBox( this );
|
||||||
|
connect( spinBox, &QskSpinBox::valueChanged,
|
||||||
|
this, &ModelBox::updateModel );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
auto textField = new QskTextField( this );
|
||||||
|
connect( textField, &QskTextField::textChanged,
|
||||||
|
this, &ModelBox::updateModel );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
updateDisplay();
|
||||||
|
|
||||||
|
connect( m_model, &Model::dataChanged, this, &ModelBox::updateDisplay );
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void updateModel()
|
||||||
|
{
|
||||||
|
if ( auto item = qobject_cast< const QQuickItem* >( sender() ) )
|
||||||
|
{
|
||||||
|
const int index = indexOf( item );
|
||||||
|
|
||||||
|
const auto modelIndex = m_model->index(
|
||||||
|
index / dimension(), index % dimension() );
|
||||||
|
|
||||||
|
const auto property = item->metaObject()->userProperty();
|
||||||
|
m_model->setData( modelIndex, property.read( item ), Qt::EditRole );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void updateDisplay() const
|
||||||
|
{
|
||||||
|
for ( int row = 0; row < m_model->rowCount(); row++ )
|
||||||
|
{
|
||||||
|
for ( int col = 0; col < m_model->columnCount(); col++ )
|
||||||
|
{
|
||||||
|
const auto index = m_model->index( row, col );
|
||||||
|
|
||||||
|
if ( auto item = itemAtIndex( row * dimension() + col ) )
|
||||||
|
{
|
||||||
|
const auto property = item->metaObject()->userProperty();
|
||||||
|
property.write( item, m_model->data( index, Qt::EditRole ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QPointer< QAbstractItemModel > m_model;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
MainView::MainView( QQuickItem* parent )
|
||||||
|
: QskMainView( parent )
|
||||||
|
{
|
||||||
|
m_binder = new QskModelObjectBinder( new Model( this ), this );
|
||||||
|
|
||||||
|
auto header = new Header();
|
||||||
|
|
||||||
|
auto displayBox = new DisplayBox();
|
||||||
|
for ( int i = 0; i < displayBox->elementCount(); i++ )
|
||||||
|
m_binder->bindObject( displayBox->itemAtIndex( i ), i );
|
||||||
|
|
||||||
|
auto box = new QskLinearBox( Qt::Vertical );
|
||||||
|
|
||||||
|
box->addItem( new TitleLabel( "Editor:" ) );
|
||||||
|
box->addItem( displayBox );
|
||||||
|
box->addItem( new QskSeparator() );
|
||||||
|
box->addItem( new TitleLabel( "Model:" ) );
|
||||||
|
box->addItem( new ModelBox( m_binder->model() ) );
|
||||||
|
|
||||||
|
setHeader( header );
|
||||||
|
setBody( box );
|
||||||
|
|
||||||
|
connect( header, &Header::rowClicked,
|
||||||
|
this, &MainView::toogleRow );
|
||||||
|
|
||||||
|
connect( header, &Header::submitClicked,
|
||||||
|
m_binder, &QskModelObjectBinder::submit );
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainView::toogleRow()
|
||||||
|
{
|
||||||
|
m_binder->setCurrentRow( m_binder->currentRow() == 0 ? 1 : 0 );
|
||||||
|
}
|
||||||
|
|
||||||
|
#include "MainView.moc"
|
|
@ -0,0 +1,21 @@
|
||||||
|
/******************************************************************************
|
||||||
|
* QSkinny - Copyright (C) The authors
|
||||||
|
* SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <QskMainView.h>
|
||||||
|
|
||||||
|
class QskModelObjectBinder;
|
||||||
|
|
||||||
|
class MainView : public QskMainView
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
MainView( QQuickItem* = nullptr );
|
||||||
|
|
||||||
|
private:
|
||||||
|
void toogleRow();
|
||||||
|
|
||||||
|
QskModelObjectBinder* m_binder;
|
||||||
|
};
|
|
@ -0,0 +1,37 @@
|
||||||
|
/******************************************************************************
|
||||||
|
* QSkinny - Copyright (C) The authors
|
||||||
|
* SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
#include "MainView.h"
|
||||||
|
|
||||||
|
#include <SkinnyShortcut.h>
|
||||||
|
|
||||||
|
#include <QskObjectCounter.h>
|
||||||
|
#include <QskFocusIndicator.h>
|
||||||
|
#include <QskWindow.h>
|
||||||
|
|
||||||
|
#include <QGuiApplication>
|
||||||
|
|
||||||
|
int main( int argc, char* argv[] )
|
||||||
|
{
|
||||||
|
#ifdef ITEM_STATISTICS
|
||||||
|
QskObjectCounter counter( true );
|
||||||
|
#endif
|
||||||
|
|
||||||
|
QGuiApplication app( argc, argv );
|
||||||
|
|
||||||
|
SkinnyShortcut::enable( SkinnyShortcut::AllShortcuts );
|
||||||
|
|
||||||
|
QskWindow window;
|
||||||
|
window.resize( 600, 400 );
|
||||||
|
|
||||||
|
auto focusIndicator = new QskFocusIndicator();
|
||||||
|
focusIndicator->setObjectName( "FocusIndicator" );
|
||||||
|
|
||||||
|
window.addItem( focusIndicator );
|
||||||
|
window.addItem( new MainView() );
|
||||||
|
window.show();
|
||||||
|
|
||||||
|
return app.exec();
|
||||||
|
}
|
|
@ -233,6 +233,7 @@ list(APPEND HEADERS
|
||||||
controls/QskListViewSkinlet.h
|
controls/QskListViewSkinlet.h
|
||||||
controls/QskMenu.h
|
controls/QskMenu.h
|
||||||
controls/QskMenuSkinlet.h
|
controls/QskMenuSkinlet.h
|
||||||
|
controls/QskModelObjectBinder.h
|
||||||
controls/QskObjectTree.h
|
controls/QskObjectTree.h
|
||||||
controls/QskPageIndicator.h
|
controls/QskPageIndicator.h
|
||||||
controls/QskPageIndicatorSkinlet.h
|
controls/QskPageIndicatorSkinlet.h
|
||||||
|
@ -345,6 +346,7 @@ list(APPEND SOURCES
|
||||||
controls/QskListViewSkinlet.cpp
|
controls/QskListViewSkinlet.cpp
|
||||||
controls/QskMenuSkinlet.cpp
|
controls/QskMenuSkinlet.cpp
|
||||||
controls/QskMenu.cpp
|
controls/QskMenu.cpp
|
||||||
|
controls/QskModelObjectBinder.cpp
|
||||||
controls/QskObjectTree.cpp
|
controls/QskObjectTree.cpp
|
||||||
controls/QskPageIndicator.cpp
|
controls/QskPageIndicator.cpp
|
||||||
controls/QskPageIndicatorSkinlet.cpp
|
controls/QskPageIndicatorSkinlet.cpp
|
||||||
|
|
|
@ -0,0 +1,274 @@
|
||||||
|
/******************************************************************************
|
||||||
|
* QSkinny - Copyright (C) The authors
|
||||||
|
* SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
#include "QskModelObjectBinder.h"
|
||||||
|
|
||||||
|
#include <qmetaobject.h>
|
||||||
|
#include <qabstractitemmodel.h>
|
||||||
|
#include <qpointer.h>
|
||||||
|
|
||||||
|
static inline QMetaProperty qskMetaProperty(
|
||||||
|
const QMetaObject* metaObject, const QByteArray& name )
|
||||||
|
{
|
||||||
|
if ( name.isEmpty() )
|
||||||
|
return metaObject->userProperty();
|
||||||
|
|
||||||
|
const auto idx = metaObject->indexOfProperty( name );
|
||||||
|
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
|
||||||
|
{
|
||||||
|
Binding( int column, const QMetaProperty& property )
|
||||||
|
: property( property )
|
||||||
|
, column( column )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
QMetaProperty property;
|
||||||
|
int column;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
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 ( !( 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.constBegin(); it != bindings.constEnd(); ++it )
|
||||||
|
{
|
||||||
|
const int col = it.value().column;
|
||||||
|
|
||||||
|
if( topLeft.column() <= col && col <= bottomRight.column() )
|
||||||
|
updateObjectProperty( it.key(), it.value() );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void updateObjectProperty( QObject* object, const Binding& binding )
|
||||||
|
{
|
||||||
|
const auto index = model->index( currentRowIndex.row(), binding.column );
|
||||||
|
binding.property.write( object, index.data( Qt::EditRole ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
QMap< QObject*, Binding > bindings;
|
||||||
|
QPointer< QAbstractItemModel > model;
|
||||||
|
QPersistentModelIndex currentRowIndex;
|
||||||
|
};
|
||||||
|
|
||||||
|
QskModelObjectBinder::QskModelObjectBinder( QObject* parent )
|
||||||
|
: QObject( parent )
|
||||||
|
, m_data( new PrivateData() )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
QskModelObjectBinder::QskModelObjectBinder( QAbstractItemModel* model, QObject* parent )
|
||||||
|
: QskModelObjectBinder( parent )
|
||||||
|
{
|
||||||
|
setModel( model );
|
||||||
|
}
|
||||||
|
|
||||||
|
QskModelObjectBinder::~QskModelObjectBinder()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void QskModelObjectBinder::bindObject(
|
||||||
|
QObject* object, int column, const QByteArray& propertyName )
|
||||||
|
{
|
||||||
|
if( object == nullptr )
|
||||||
|
return;
|
||||||
|
|
||||||
|
// does not work with dynamic properties ...
|
||||||
|
|
||||||
|
const auto metaProperty = qskMetaProperty( object->metaObject(), propertyName );
|
||||||
|
Q_ASSERT( metaProperty.isValid() );
|
||||||
|
|
||||||
|
if ( metaProperty.isValid() )
|
||||||
|
{
|
||||||
|
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 );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void QskModelObjectBinder::unbindObject( QObject* object )
|
||||||
|
{
|
||||||
|
auto& bindings = m_data->bindings;
|
||||||
|
|
||||||
|
auto it = bindings.find( object );
|
||||||
|
if ( it != bindings.end() )
|
||||||
|
{
|
||||||
|
qskEnableConnections( object, this, false );
|
||||||
|
bindings.erase( it );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void QskModelObjectBinder::clearBindings()
|
||||||
|
{
|
||||||
|
auto& bindings = m_data->bindings;
|
||||||
|
|
||||||
|
for ( auto it = bindings.constBegin(); it != bindings.constEnd(); ++it )
|
||||||
|
qskEnableConnections( it.key(), this, false );
|
||||||
|
|
||||||
|
bindings.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
QObjectList QskModelObjectBinder::boundObjects() const
|
||||||
|
{
|
||||||
|
auto& bindings = m_data->bindings;
|
||||||
|
|
||||||
|
QObjectList objects;
|
||||||
|
objects.reserve( bindings.count() );
|
||||||
|
|
||||||
|
for ( auto it = bindings.constBegin(); it != bindings.constEnd(); ++it )
|
||||||
|
objects += it.key();
|
||||||
|
|
||||||
|
return objects;
|
||||||
|
}
|
||||||
|
|
||||||
|
QMetaProperty QskModelObjectBinder::boundProperty( const QObject* object ) const
|
||||||
|
{
|
||||||
|
auto it = m_data->bindings.constFind( const_cast< QObject* >( object ) );
|
||||||
|
if ( it != m_data->bindings.constEnd() )
|
||||||
|
return it.value().property;
|
||||||
|
|
||||||
|
return QMetaProperty();
|
||||||
|
}
|
||||||
|
|
||||||
|
void QskModelObjectBinder::setModel( QAbstractItemModel* model )
|
||||||
|
{
|
||||||
|
if ( model == m_data->model )
|
||||||
|
return;
|
||||||
|
|
||||||
|
if ( m_data->model )
|
||||||
|
{
|
||||||
|
disconnect( m_data->model, &QAbstractItemModel::dataChanged, this, nullptr );
|
||||||
|
|
||||||
|
m_data->model = nullptr;
|
||||||
|
m_data->currentRowIndex = QModelIndex();
|
||||||
|
|
||||||
|
clearBindings();
|
||||||
|
}
|
||||||
|
|
||||||
|
m_data->model = model;
|
||||||
|
|
||||||
|
if( model )
|
||||||
|
{
|
||||||
|
auto updateProperties = [this](
|
||||||
|
const QModelIndex& topLeft, const QModelIndex& bottomRight,
|
||||||
|
const QVector< int >& roles )
|
||||||
|
{
|
||||||
|
m_data->updateProperties( topLeft, bottomRight, roles );
|
||||||
|
};
|
||||||
|
|
||||||
|
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 )
|
||||||
|
{
|
||||||
|
auto model = m_data->model.data();
|
||||||
|
auto& bindings = m_data->bindings;
|
||||||
|
|
||||||
|
Q_ASSERT( model != nullptr );
|
||||||
|
|
||||||
|
if ( model && row >= 0 && row < model->rowCount() )
|
||||||
|
{
|
||||||
|
m_data->currentRowIndex = model->index( row, 0 );
|
||||||
|
|
||||||
|
for ( auto it = bindings.constBegin(); it != bindings.constEnd(); ++it )
|
||||||
|
m_data->updateObjectProperty( it.key(), it.value() );
|
||||||
|
|
||||||
|
Q_EMIT currentRowChanged( row );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int QskModelObjectBinder::currentRow() const
|
||||||
|
{
|
||||||
|
return m_data->currentRowIndex.row();
|
||||||
|
}
|
||||||
|
|
||||||
|
void QskModelObjectBinder::submit()
|
||||||
|
{
|
||||||
|
if ( auto model = m_data->model )
|
||||||
|
{
|
||||||
|
const auto& bindings = m_data->bindings;
|
||||||
|
|
||||||
|
for ( auto it = bindings.begin(); it != bindings.end(); ++it )
|
||||||
|
{
|
||||||
|
const auto value = it.value().property.read( it.key() );
|
||||||
|
|
||||||
|
const auto row = m_data->currentRowIndex.row();
|
||||||
|
const auto index = model->index( row, it.value().column );
|
||||||
|
|
||||||
|
model->setData( index, value );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void QskModelObjectBinder::revert()
|
||||||
|
{
|
||||||
|
m_data->updateProperties();
|
||||||
|
}
|
||||||
|
|
||||||
|
#include "moc_QskModelObjectBinder.cpp"
|
|
@ -0,0 +1,61 @@
|
||||||
|
/******************************************************************************
|
||||||
|
* QSkinny - Copyright (C) The authors
|
||||||
|
* SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
#ifndef QSK_MODEL_OBJECT_BINDER_H
|
||||||
|
#define QSK_MODEL_OBJECT_BINDER_H
|
||||||
|
|
||||||
|
#include "QskGlobal.h"
|
||||||
|
|
||||||
|
#include <qobject.h>
|
||||||
|
#include <qbytearray.h>
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
class QAbstractItemModel;
|
||||||
|
class QMetaProperty;
|
||||||
|
|
||||||
|
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 );
|
||||||
|
|
||||||
|
~QskModelObjectBinder() override;
|
||||||
|
|
||||||
|
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* );
|
||||||
|
|
||||||
|
QMetaProperty boundProperty( const QObject* ) const;
|
||||||
|
QObjectList boundObjects() const;
|
||||||
|
|
||||||
|
Q_SIGNALS:
|
||||||
|
void currentRowChanged( int );
|
||||||
|
|
||||||
|
public Q_SLOTS:
|
||||||
|
void submit();
|
||||||
|
void revert();
|
||||||
|
void clearBindings();
|
||||||
|
|
||||||
|
private:
|
||||||
|
class PrivateData;
|
||||||
|
std::unique_ptr< PrivateData > m_data;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
Loading…
Reference in New Issue