Squashed commit of the following:
Merge:f614117d
f0d49d9e
Author: Uwe Rathmann <Uwe.Rathmann@tigertal.de> Date: Sun Feb 25 09:11:12 2024 +0100 Merge branch 'master' of https://github.com/ovenpasta/qskinny into models ( Author: Aldo Nicolas Bruno <ovenpasta@pizzahack.eu> )
This commit is contained in:
parent
f614117d96
commit
6ea2126638
|
@ -54,11 +54,11 @@ macro(qsk_setup_Qt)
|
||||||
# C++, but QSkinny itself does not need the WebEngine at all.
|
# C++, but QSkinny itself does not need the WebEngine at all.
|
||||||
|
|
||||||
if (QT_VERSION_MAJOR VERSION_LESS 6)
|
if (QT_VERSION_MAJOR VERSION_LESS 6)
|
||||||
find_package(Qt${QT_VERSION_MAJOR} QUIET OPTIONAL_COMPONENTS WebEngine)
|
find_package(Qt${QT_VERSION_MAJOR} QUIET OPTIONAL_COMPONENTS WebEngine Sql)
|
||||||
set( Qt5WebEngineQuick_FOUND ${Qt5WebEngine_FOUND} )
|
set( Qt5WebEngineQuick_FOUND ${Qt5WebEngine_FOUND} )
|
||||||
else()
|
else()
|
||||||
find_package(Qt${QT_VERSION_MAJOR} QUIET
|
find_package(Qt${QT_VERSION_MAJOR} QUIET
|
||||||
OPTIONAL_COMPONENTS WebEngineCore WebEngineQuick)
|
OPTIONAL_COMPONENTS WebEngineCore WebEngineQuick Sql)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if( NOT Qt${QT_VERSION_MAJOR}WebEngineQuick_FOUND)
|
if( NOT Qt${QT_VERSION_MAJOR}WebEngineQuick_FOUND)
|
||||||
|
|
|
@ -32,3 +32,7 @@ endif()
|
||||||
if(TARGET Qt::QuickWidgets)
|
if(TARGET Qt::QuickWidgets)
|
||||||
add_subdirectory(grids)
|
add_subdirectory(grids)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if(TARGET Qt::Sql)
|
||||||
|
add_subdirectory(models)
|
||||||
|
endif()
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
############################################################################
|
||||||
|
# QSkinny - Copyright (C) The authors
|
||||||
|
# SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
############################################################################
|
||||||
|
|
||||||
|
qsk_add_example(models QskModelObjectBinder.cpp QskModelObjectBinder.h Window.h Window.cpp main.cpp)
|
||||||
|
|
||||||
|
target_link_libraries(models PRIVATE Qt::Sql)
|
|
@ -0,0 +1,157 @@
|
||||||
|
//
|
||||||
|
// Created by aldo on 27/01/21.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "QskModelObjectBinder.h"
|
||||||
|
#include <QMetaProperty>
|
||||||
|
#include <QPointer>
|
||||||
|
#include <qassert.h>
|
||||||
|
|
||||||
|
class QskModelObjectBinder::PrivateData
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
PrivateData( )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Item {
|
||||||
|
Item() :valid(false), column(-1) {};
|
||||||
|
Item(QObject *obj, int column, const QByteArray& property)
|
||||||
|
: valid (true), object( obj ), column( column ), property( property )
|
||||||
|
{
|
||||||
|
};
|
||||||
|
bool valid;
|
||||||
|
QObject* object;
|
||||||
|
int column;
|
||||||
|
QByteArray property;
|
||||||
|
};
|
||||||
|
|
||||||
|
void updateObjectProperty(Item & x)
|
||||||
|
{
|
||||||
|
Q_ASSERT( x.object != nullptr );
|
||||||
|
Q_ASSERT( ! x.property.isEmpty() );
|
||||||
|
x.object->setProperty(x.property,
|
||||||
|
m->index(currentRowIndex.row(),x.column).data(Qt::EditRole));
|
||||||
|
}
|
||||||
|
|
||||||
|
void updateAllObjects()
|
||||||
|
{
|
||||||
|
for (auto it = items.begin(); it != items.end(); ++it) {
|
||||||
|
updateObjectProperty(it.value());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void updateModelField(Item& x)
|
||||||
|
{
|
||||||
|
Q_ASSERT( x.valid );
|
||||||
|
Q_ASSERT( x.object != nullptr );
|
||||||
|
auto prop =x.object->property( x.property );
|
||||||
|
Q_ASSERT( prop.isValid() );
|
||||||
|
|
||||||
|
m->setData(m->index(currentRowIndex.row(),x.column),prop);
|
||||||
|
}
|
||||||
|
|
||||||
|
void updateModelFields()
|
||||||
|
{
|
||||||
|
for (auto it = items.begin(); it != items.end(); ++it)
|
||||||
|
{
|
||||||
|
updateModelField( it.value() );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
QMap<QObject*,Item> items;
|
||||||
|
QAbstractItemModel* m;
|
||||||
|
QPersistentModelIndex currentRowIndex;
|
||||||
|
};
|
||||||
|
|
||||||
|
QskModelObjectBinder::QskModelObjectBinder(QObject* parent)
|
||||||
|
: QObject( parent )
|
||||||
|
{
|
||||||
|
m_data=std::make_unique<PrivateData>( );
|
||||||
|
}
|
||||||
|
|
||||||
|
QskModelObjectBinder::QskModelObjectBinder(QAbstractItemModel *model, QObject* parent)
|
||||||
|
: QObject( parent )
|
||||||
|
{
|
||||||
|
m_data=std::make_unique<PrivateData>();
|
||||||
|
bindModel(model);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void QskModelObjectBinder::bindObject(QObject *obj, int column, const QByteArray &propertyName)
|
||||||
|
{
|
||||||
|
Q_ASSERT( obj != nullptr );
|
||||||
|
|
||||||
|
if(obj == nullptr)
|
||||||
|
return;
|
||||||
|
|
||||||
|
QMetaProperty prop;
|
||||||
|
auto meta = obj->metaObject();
|
||||||
|
if (propertyName.isEmpty())
|
||||||
|
{
|
||||||
|
prop = meta->userProperty();
|
||||||
|
}else
|
||||||
|
{
|
||||||
|
auto idx = meta->indexOfProperty( propertyName );
|
||||||
|
if(idx>=0)
|
||||||
|
{
|
||||||
|
prop=meta->property(idx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Q_ASSERT(! prop.isValid());
|
||||||
|
|
||||||
|
PrivateData::Item item(obj,column,prop.name());
|
||||||
|
m_data->items[obj]=item;
|
||||||
|
}
|
||||||
|
|
||||||
|
void QskModelObjectBinder::unbindObject(QObject *obj)
|
||||||
|
{
|
||||||
|
m_data->items.remove(obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
void QskModelObjectBinder::bindModel(QAbstractItemModel *model)
|
||||||
|
{
|
||||||
|
m_data->m=model;
|
||||||
|
m_data->currentRowIndex=QModelIndex();
|
||||||
|
if(model) {
|
||||||
|
connect(m_data->m,&QAbstractItemModel::dataChanged,this,
|
||||||
|
&QskModelObjectBinder::modelDataChanged);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void QskModelObjectBinder::modelDataChanged(const QModelIndex & topLeft, const QModelIndex & bottomRight, const QVector<int> &)
|
||||||
|
{
|
||||||
|
const int row = m_data->currentRowIndex.row();
|
||||||
|
for (auto it = m_data->items.begin(); it != m_data->items.end(); ++it) {
|
||||||
|
auto & x = it.value();
|
||||||
|
const int col = x.column;
|
||||||
|
if( qBound( topLeft.row(),row,bottomRight.row()) == row
|
||||||
|
&& qBound( topLeft.column(), col, bottomRight.column()) == col) {
|
||||||
|
m_data->updateObjectProperty(x);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void QskModelObjectBinder::selectRow( int row )
|
||||||
|
{
|
||||||
|
Q_ASSERT( m_data->m != nullptr );
|
||||||
|
|
||||||
|
if ( !m_data->m )
|
||||||
|
return;
|
||||||
|
|
||||||
|
m_data->currentRowIndex = m_data->m->index( row, 0 );
|
||||||
|
m_data->updateAllObjects();
|
||||||
|
}
|
||||||
|
|
||||||
|
int QskModelObjectBinder::currentRow() const
|
||||||
|
{
|
||||||
|
return m_data->currentRowIndex.row();
|
||||||
|
}
|
||||||
|
|
||||||
|
void QskModelObjectBinder::updateModel()
|
||||||
|
{
|
||||||
|
m_data->updateModelFields();
|
||||||
|
}
|
||||||
|
|
||||||
|
#include "moc_QskModelObjectBinder.cpp"
|
|
@ -0,0 +1,32 @@
|
||||||
|
#ifndef QSKDATACONTROLMAPPER_H
|
||||||
|
#define QSKDATACONTROLMAPPER_H
|
||||||
|
|
||||||
|
#include <QAbstractItemModel>
|
||||||
|
|
||||||
|
class QskModelObjectBinder : public QObject {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
QskModelObjectBinder(QObject *parent=nullptr);
|
||||||
|
QskModelObjectBinder(QAbstractItemModel* model, QObject *parent=nullptr);
|
||||||
|
|
||||||
|
void bindObject(QObject*, int column, const QByteArray &propertyName="");
|
||||||
|
void unbindObject(QObject*o);
|
||||||
|
|
||||||
|
void bindModel(QAbstractItemModel* model);
|
||||||
|
|
||||||
|
void selectRow(int row);
|
||||||
|
[[nodiscard]] int currentRow() const;
|
||||||
|
|
||||||
|
void updateModel();
|
||||||
|
|
||||||
|
private Q_SLOTS:
|
||||||
|
void modelDataChanged(const QModelIndex & topLeft, const QModelIndex & bottomRight, const QVector<int> &);
|
||||||
|
|
||||||
|
private:
|
||||||
|
class PrivateData;
|
||||||
|
std::unique_ptr< PrivateData > m_data;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif //QSKDATACONTROLMAPPER_H
|
|
@ -0,0 +1,82 @@
|
||||||
|
/******************************************************************************
|
||||||
|
* QSkinny - Copyright (C) The authors
|
||||||
|
* SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
#include "Window.h"
|
||||||
|
|
||||||
|
#include <QskDialogButtonBox.h>
|
||||||
|
#include <QskLinearBox.h>
|
||||||
|
#include <QskPushButton.h>
|
||||||
|
#include <QskTextInput.h>
|
||||||
|
#include <QskSpinBox.h>
|
||||||
|
|
||||||
|
#include <QskModelObjectBinder.h>
|
||||||
|
|
||||||
|
#include <QSqlDatabase>
|
||||||
|
#include <QSqlQuery>
|
||||||
|
#include <QSqlTableModel>
|
||||||
|
#include <QSqlRecord>
|
||||||
|
|
||||||
|
Window::Window( )
|
||||||
|
|
||||||
|
{
|
||||||
|
auto db = QSqlDatabase::addDatabase("QSQLITE");
|
||||||
|
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');");
|
||||||
|
|
||||||
|
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);
|
||||||
|
/*
|
||||||
|
Not needed if we set USER true for the corresponding Q_PROPERTY in QskBoundedInput and QskTextInput
|
||||||
|
maybe could be done also for other controls
|
||||||
|
mapper->bindControl(spin, 0,"value");
|
||||||
|
mapper->bindControl(txt, 1, "text");
|
||||||
|
*/
|
||||||
|
mapper->bindObject(spin, 0); // needs USER=true for value in QskBoundedInput
|
||||||
|
mapper->bindObject(txt, 1); // needs USER=true for text in QskTextInput
|
||||||
|
|
||||||
|
// this loads the record from the first row and updates the controls data.
|
||||||
|
mapper->selectRow(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->selectRow( 0 ); });
|
||||||
|
connect(next,&QskPushButton::clicked,[=]() { mapper->selectRow( 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 );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#include "moc_Window.cpp"
|
|
@ -0,0 +1,22 @@
|
||||||
|
/******************************************************************************
|
||||||
|
* QSkinny - Copyright (C) The authors
|
||||||
|
* SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <QskDialog.h>
|
||||||
|
#include <QskWindow.h>
|
||||||
|
|
||||||
|
class QskDialogButtonBox;
|
||||||
|
class QskLinearBox;
|
||||||
|
|
||||||
|
class Window : public QskWindow
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
Window();
|
||||||
|
|
||||||
|
|
||||||
|
};
|
|
@ -0,0 +1,35 @@
|
||||||
|
/******************************************************************************
|
||||||
|
* QSkinny - Copyright (C) The authors
|
||||||
|
* SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
#include "Window.h"
|
||||||
|
|
||||||
|
#include <SkinnyShortcut.h>
|
||||||
|
|
||||||
|
#include <QskFocusIndicator.h>
|
||||||
|
#include <QskObjectCounter.h>
|
||||||
|
|
||||||
|
#include <QGuiApplication>
|
||||||
|
|
||||||
|
int main( int argc, char* argv[] )
|
||||||
|
{
|
||||||
|
#ifdef ITEM_STATISTICS
|
||||||
|
QskObjectCounter counter( true );
|
||||||
|
#endif
|
||||||
|
|
||||||
|
QGuiApplication app( argc, argv );
|
||||||
|
|
||||||
|
SkinnyShortcut::enable( SkinnyShortcut::AllShortcuts );
|
||||||
|
|
||||||
|
Window window;
|
||||||
|
window.resize( 600, 400 );
|
||||||
|
|
||||||
|
auto focusIndicator = new QskFocusIndicator();
|
||||||
|
focusIndicator->setObjectName( "FocusIndicator" );
|
||||||
|
|
||||||
|
window.addItem( focusIndicator );
|
||||||
|
window.show();
|
||||||
|
|
||||||
|
return app.exec();
|
||||||
|
}
|
Loading…
Reference in New Issue