first commit

This commit is contained in:
bing
2026-04-03 11:32:07 +08:00
commit 003be19522
1142 changed files with 185854 additions and 0 deletions

View File

@@ -0,0 +1,374 @@
/****************************************************************************
**
** https://www.qxorm.com/
** Copyright (C) 2013 XDL Team (ic-east.com)
**
** This file is part of the QxOrm library
**
** This software is provided 'as-is', without any express or implied
** warranty. In no event will the authors be held liable for any
** damages arising from the use of this software
**
** Commercial Usage
** Licensees holding valid commercial QxOrm licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and XDL Team
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3.0 as published by the Free Software
** Foundation and appearing in the file 'license.gpl3.txt' included in the
** packaging of this file. Please review the following information to
** ensure the GNU General Public License version 3.0 requirements will be
** met : http://www.gnu.org/copyleft/gpl.html
**
** If you are unsure which license is appropriate for your use, or
** if you have questions regarding the use of this file, please contact :
** ic-east.com
**
****************************************************************************/
#ifndef _IX_MODEL_H_
#define _IX_MODEL_H_
#ifdef _MSC_VER
#pragma once
#endif
/*!
* \file IxModel.h
* \author XDL Team
* \ingroup QxModelView
* \brief Interface to manage Qt model/view architecture with classes registered into QxOrm context (Qt widgets and/or QML views)
*/
#ifdef _QX_NO_PRECOMPILED_HEADER
#ifndef Q_MOC_RUN
#include <QxPrecompiled.h> // Need to include precompiled header for the generated moc file
#endif // Q_MOC_RUN
#endif // _QX_NO_PRECOMPILED_HEADER
#include <QtCore/qabstractitemmodel.h>
#ifndef Q_MOC_RUN
#include <QxRegister/IxClass.h>
#include <QxDataMember/IxDataMemberX.h>
#include <QxCollection/QxCollection.h>
#include <QxDao/IxSqlRelation.h>
#include <QxDao/QxSqlQuery.h>
#include <QxDao/QxDao.h>
#include <QxValidator/QxInvalidValueX.h>
#include <QxValidator/QxValidatorFct.h>
#endif // Q_MOC_RUN
namespace qx
{
namespace model_view
{
namespace detail
{
template <class T, class M>
struct QxNestedModel;
template <class T, class M>
struct QxNestedModel_Generic;
template <class T, class M>
struct QxNestedModel_Container;
} // namespace detail
} // namespace model_view
} // namespace qx
namespace qx
{
/*!
* \ingroup QxModelView
* \brief qx::IxModel : interface to manage Qt model/view architecture with classes registered into QxOrm context (Qt widgets and/or QML views)
*
* <b>QxModelView</b> module provides an easy way to work with Qt model/view engine with all classes registered into QxOrm context :
* - Qt widgets : QTableView or QListView for example to display/modify a database table content ;
* - QML : each property defined in QxOrm context is exposed to QML engine : QxModelView module makes easier integration between QML and databases.
*
* qx::IxModel interface provides a generic way for all models linked to persistents classes registered into QxOrm context. All methods of this class prefixed by <i>qx</i> call functions from qx::dao namespace and then communicate with database.
*
* The <i>qxBlogModelView</i> sample project in <i>./test/</i> directory of QxOrm package shows how to create quickly a model and associate it to the Qt model/view engine (first with a Qt widget, then with a QML view).
*
* 1- Here is an example to display/modify data from 'author' table (go to qxBlog tutorial for 'author' class definition) in a QTableView :
* \code
// Create a model and fetch all data from database
qx::IxModel * pModel = new qx::QxModel<author>();
pModel->qxFetchAll();
// Associate the model to a QTableView and display it
QTableView tableView;
tableView.setModel(pModel);
tableView.show();
* \endcode
*
* 2- Here is another example in QML (with Qt5, QxModelView module works fine with Qt4 too) :
* \code
// Create a model and fetch all data from database
qx::IxModel * pModel = new qx::QxModel<author>();
pModel->qxFetchAll();
// Associate the model to a QML view and display it
QQuickView qmlView;
qmlView.rootContext()->setContextProperty("myModel", pModel);
qmlView.setSource(QUrl("qrc:/documents/main.qml"));
qmlView.show();
* \endcode
*
* And here is the 'main.qml' file content :
* \code
import QtQuick 2.1
import QtQuick.Controls 1.0
Item {
width: 400
height: 300
Row {
height: 20
spacing: 20
Button {
text: "Clear"
onClicked: myModel.clear()
}
Button {
text: "Fetch All"
onClicked: myModel.qxFetchAll_()
}
Button {
text: "Save"
onClicked: myModel.qxSave_()
}
}
ListView {
y: 30
height: 270
model: myModel
delegate: Row {
height: 20
spacing: 10
Text { text: "id: " + author_id }
TextField {
text: name
onTextChanged: name = text
}
}
}
}
* \endcode
*
* As you can see in the 'main.qml' file, 'author_id' and 'name' properties of 'author' model ('myModel' variable) can be automatically read and write (because they are registered into QxOrm context).
* Moreover, qx::IxModel interface provides a list of methods for QML side (Q_INVOKABLE) to communicate with database : for example, the 'Save' button will save the model in database without having to write a C++ function.
*
* <b>Note :</b> a <b>QxEntityEditor</b> plugin generates automatically the code to manage models with relationships. Then it is possible to work with nested C++ models.
*/
class QX_DLL_EXPORT IxModel : public QAbstractItemModel
{
Q_OBJECT
template <typename U, typename V>
friend struct qx::model_view::detail::QxNestedModel;
template <typename U, typename V>
friend struct qx::model_view::detail::QxNestedModel_Generic;
template <typename U, typename V>
friend struct qx::model_view::detail::QxNestedModel_Container;
public:
enum e_auto_update_database
{
e_no_auto_update,
e_auto_update_on_field_change
};
typedef QHash<QString, IxModel *> type_relation_by_name;
typedef QList<type_relation_by_name> type_lst_relation_by_name;
typedef QHash<IxModel *, QPair<int, QString>> type_child_to_its_relation;
protected:
IxClass *m_pClass; //!< Class introspection registered into QxOrm context associated to the model
IxClass *m_pModelClass; //!< If model itself is registered into QxOrm context, then you can use this property to work with introspection engine
IxDataMemberX *m_pDataMemberX; //!< List of properties defined into QxOrm context
IxDataMember *m_pDataMemberId; //!< Primary key (property id) defined into QxOrm context
IxCollection *m_pCollection; //!< Interface to store a list of items
QHash<int, QByteArray> m_lstRoleNames; //!< List of model's role names to expose data to QML
QList<IxDataMember *> m_lstDataMember; //!< List of data member exposed by the model
QHash<QString, int> m_lstDataMemberByKey; //!< List of data member key to get column index in model
QHash<QString, QVariant> m_lstHeadersData; //!< List of headers data by role and data member key
QStringList m_lstColumns; //!< List of columns exposed by the model (if empty, all columns)
QSqlDatabase m_database; //!< Database connexion to execute SQL queries (if empty, default database connexion)
QSqlError m_lastError; //!< Last SQL error
IxModel *m_pParent; //!< Parent model, NULL if current model is the root model
type_lst_relation_by_name m_lstChild; //!< List of child model : QxEntityEditor uses this property to manage relationships and create complex data structure
type_child_to_its_relation m_hChild; //!< Reverse link to m_lstChild, used in setData() to save relations
e_auto_update_database m_eAutoUpdateDatabase; //!< Auto-update database on field change (detected by the setData() method)
IxDataMember *m_pDataMemberRelationToParent; //!< The data member holding relationship to its parent model (if one exists), used only by nested models
long m_lManualInsertIndex; //!< Index to insert manually items to the collection
QHash<QString, QVariant> m_hCustomProperties; //!< Use this generic hash-table to define extra-properties in your custom classes which inherit from qx::IxModel interface (instead of creating new properties) ==> this will ensure that sizeof(qx::IxModel) == sizeof(YourCustomClass), this is important with nested models feature
public:
IxModel(QObject *parent = 0);
virtual ~IxModel();
IxClass *getClass() const;
IxClass *getModelClass() const;
IxCollection *getCollection() const;
QSqlDatabase getDatabase() const;
QSqlError getLastError() const;
Q_INVOKABLE QString getLastErrorAsString() const;
Q_INVOKABLE QStringList getListOfColumns() const;
QHash<QString, QString> getListOfHeaders() const; //!< Obsolete : use headerData() instead
IxDataMember *getDataMember(int column) const;
Q_INVOKABLE QString getDataMemberKey(int column) const;
Q_INVOKABLE int getRowCount() const;
Q_INVOKABLE QVariant getModelValue(int row, const QString &column) const;
Q_INVOKABLE int getColumnIndex(const QString &sColumnName) const;
Q_INVOKABLE int getAutoUpdateDatabase_() const;
e_auto_update_database getAutoUpdateDatabase() const;
Q_INVOKABLE virtual bool getShowEmptyLine() const = 0; //!< Can be useful when a model is displayed in a table (QTableView for example) to add automatically an empty row at the end of the table to insert quickly new items (for example, same style like QxEntityEditor list of properties/relationships)
Q_INVOKABLE QVariant getCustomProperty(const QString &key) const;
Q_INVOKABLE QObject *getParentModel() const; //!< Can be used to figure out whether this model has a parent model (used only by nested models)
Q_INVOKABLE void dumpModel(bool bJsonFormat = true) const;
Q_INVOKABLE QObject *cloneModel();
void setDatabase(const QSqlDatabase &db);
Q_INVOKABLE void setListOfColumns(const QStringList &lst);
void setListOfHeaders(const QHash<QString, QString> &lst); //!< Obsolete : use setHeaderData() instead
Q_INVOKABLE bool setModelValue(int row, const QString &column, const QVariant &value);
void setParentModel(IxModel *pParent);
Q_INVOKABLE void setAutoUpdateDatabase_(int i);
void setAutoUpdateDatabase(e_auto_update_database e);
Q_INVOKABLE virtual void setShowEmptyLine(bool b) = 0;
Q_INVOKABLE void setCustomProperty(const QString &key, const QVariant &val);
Q_INVOKABLE QString toJson(int row = -1) const; //!< On QML side, use JSON.parse() to create a javascript object after calling this qx::IxModel::toJson() method
Q_INVOKABLE bool fromJson(const QString &json, int row = -1); //!< On QML side, use JSON.stringify() on a javascript object before calling this qx::IxModel::fromJson() method
Q_INVOKABLE QVariant getRelationshipValues(int row, const QString &relation, bool bLoadFromDatabase = false, const QString &sAppendRelations = QString()); //!< Depending on relationship type (1-1, 1-n, n-1, n-n) : can return a QVariantMap type or a QVariantList type
Q_INVOKABLE bool setRelationshipValues(int row, const QString &relation, const QVariant &values); //!< Depending on relationship type (1-1, 1-n, n-1, n-n) : values parameter can be a QVariantMap type or a QVariantList type
virtual long qxCount(const qx::QxSqlQuery &query = qx::QxSqlQuery(), QSqlDatabase *pDatabase = NULL) = 0;
virtual QSqlError qxCount(long &lCount, const qx::QxSqlQuery &query = qx::QxSqlQuery(), QSqlDatabase *pDatabase = NULL) = 0;
virtual QSqlError qxFetchById(const QVariant &id, const QStringList &relation = QStringList(), QSqlDatabase *pDatabase = NULL) = 0;
virtual QSqlError qxFetchAll(const QStringList &relation = QStringList(), QSqlDatabase *pDatabase = NULL) = 0;
virtual QSqlError qxFetchByQuery(const qx::QxSqlQuery &query, const QStringList &relation = QStringList(), QSqlDatabase *pDatabase = NULL) = 0;
virtual QSqlError qxFetchRow(int row, const QStringList &relation = QStringList(), QSqlDatabase *pDatabase = NULL) = 0;
virtual QSqlError qxInsert(const QStringList &relation = QStringList(), QSqlDatabase *pDatabase = NULL, bool bUseExecBatch = false) = 0;
virtual QSqlError qxInsertRow(int row, const QStringList &relation = QStringList(), QSqlDatabase *pDatabase = NULL) = 0;
virtual QSqlError qxUpdate(const qx::QxSqlQuery &query = qx::QxSqlQuery(), const QStringList &relation = QStringList(), QSqlDatabase *pDatabase = NULL, bool bUseExecBatch = false) = 0;
virtual QSqlError qxUpdateRow(int row, const qx::QxSqlQuery &query = qx::QxSqlQuery(), const QStringList &relation = QStringList(), QSqlDatabase *pDatabase = NULL) = 0;
virtual QSqlError qxSave(const QStringList &relation = QStringList(), QSqlDatabase *pDatabase = NULL) = 0;
virtual QSqlError qxSaveRow(int row, const QStringList &relation = QStringList(), QSqlDatabase *pDatabase = NULL) = 0;
virtual QSqlError qxSaveRowData(int row, const QStringList &column = QStringList(), QSqlDatabase *pDatabase = NULL) = 0;
virtual QSqlError qxDeleteById(const QVariant &id, QSqlDatabase *pDatabase = NULL) = 0;
virtual QSqlError qxDeleteAll(QSqlDatabase *pDatabase = NULL) = 0;
virtual QSqlError qxDeleteByQuery(const qx::QxSqlQuery &query, QSqlDatabase *pDatabase = NULL) = 0;
virtual QSqlError qxDeleteRow(int row, QSqlDatabase *pDatabase = NULL) = 0;
virtual QSqlError qxDestroyById(const QVariant &id, QSqlDatabase *pDatabase = NULL) = 0;
virtual QSqlError qxDestroyAll(QSqlDatabase *pDatabase = NULL) = 0;
virtual QSqlError qxDestroyByQuery(const qx::QxSqlQuery &query, QSqlDatabase *pDatabase = NULL) = 0;
virtual QSqlError qxDestroyRow(int row, QSqlDatabase *pDatabase = NULL) = 0;
virtual QSqlError qxExecuteQuery(qx::QxSqlQuery &query, QSqlDatabase *pDatabase = NULL) = 0;
virtual qx_bool qxExist(const QVariant &id, QSqlDatabase *pDatabase = NULL) = 0;
virtual qx::QxInvalidValueX qxValidate(const QStringList &groups = QStringList()) = 0;
virtual qx::QxInvalidValueX qxValidateRow(int row, const QStringList &groups = QStringList()) = 0;
Q_INVOKABLE int qxCount_(const QString &sQuery);
Q_INVOKABLE bool qxFetchById_(const QVariant &id, const QStringList &relation = QStringList());
Q_INVOKABLE bool qxFetchAll_(const QStringList &relation = QStringList());
Q_INVOKABLE bool qxFetchByQuery_(const QString &sQuery, const QStringList &relation = QStringList());
Q_INVOKABLE bool qxFetchRow_(int row, const QStringList &relation = QStringList());
Q_INVOKABLE bool qxInsert_(const QStringList &relation = QStringList(), bool bUseExecBatch = false);
Q_INVOKABLE bool qxInsertRow_(int row, const QStringList &relation = QStringList());
Q_INVOKABLE bool qxUpdate_(const QString &sQuery, const QStringList &relation = QStringList(), bool bUseExecBatch = false);
Q_INVOKABLE bool qxUpdateRow_(int row, const QString &sQuery, const QStringList &relation = QStringList());
Q_INVOKABLE bool qxSave_(const QStringList &relation = QStringList());
Q_INVOKABLE bool qxSaveRow_(int row, const QStringList &relation = QStringList());
Q_INVOKABLE bool qxDeleteById_(const QVariant &id);
Q_INVOKABLE bool qxDeleteAll_();
Q_INVOKABLE bool qxDeleteByQuery_(const QString &sQuery);
Q_INVOKABLE bool qxDeleteRow_(int row);
Q_INVOKABLE bool qxDestroyById_(const QVariant &id);
Q_INVOKABLE bool qxDestroyAll_();
Q_INVOKABLE bool qxDestroyByQuery_(const QString &sQuery);
Q_INVOKABLE bool qxDestroyRow_(int row);
Q_INVOKABLE bool qxExecuteQuery_(const QString &sQuery);
Q_INVOKABLE bool qxExist_(const QVariant &id);
Q_INVOKABLE QString qxValidate_(const QStringList &groups = QStringList());
Q_INVOKABLE QString qxValidateRow_(int row, const QStringList &groups = QStringList());
QSqlError saveChildRelations(IxModel *pChild);
QVariant getIdFromChild(IxModel *pChild) const; //!< Used to save foreign key in a nested model
QPair<int, QString> getChildPosition(IxModel *pChild) const;
protected:
void raiseEvent_headerDataChanged(Qt::Orientation orientation, int first, int last);
#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))
void raiseEvent_dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector<int> &roles = QVector<int>());
void raiseEvent_layoutAboutToBeChanged(const QList<QPersistentModelIndex> &parents = QList<QPersistentModelIndex>(), QAbstractItemModel::LayoutChangeHint hint = QAbstractItemModel::NoLayoutChangeHint);
void raiseEvent_layoutChanged(const QList<QPersistentModelIndex> &parents = QList<QPersistentModelIndex>(), QAbstractItemModel::LayoutChangeHint hint = QAbstractItemModel::NoLayoutChangeHint);
#else // (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))
void raiseEvent_dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight);
void raiseEvent_layoutAboutToBeChanged();
void raiseEvent_layoutChanged();
#endif // (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))
public:
Q_INVOKABLE void clear(bool bUpdateColumns = false);
virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
virtual bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole);
virtual int rowCount(const QModelIndex &parent = QModelIndex()) const;
virtual int columnCount(const QModelIndex &parent = QModelIndex()) const;
virtual QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const;
virtual QModelIndex parent(const QModelIndex &index) const;
virtual bool hasChildren(const QModelIndex &parent = QModelIndex()) const;
virtual QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const;
virtual Qt::ItemFlags flags(const QModelIndex &index) const;
virtual Qt::DropActions supportedDropActions() const;
virtual bool removeRows(int row, int count, const QModelIndex &parent = QModelIndex());
virtual bool setHeaderData(int section, Qt::Orientation orientation, const QVariant &value, int role = Qt::EditRole);
bool setHeaderData(const QString &sColumnName, const QVariant &value, int role = Qt::EditRole);
#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))
virtual QHash<int, QByteArray> roleNames() const;
virtual Qt::DropActions supportedDragActions() const;
#endif // (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))
protected:
virtual QObject *cloneModelImpl() = 0;
virtual void dumpModelImpl(bool bJsonFormat) const = 0;
virtual void *getRowItemAsVoidPtr(int row) const = 0;
virtual bool isDirtyRow(int row) const = 0;
virtual void insertDirtyRowToModel() = 0;
virtual void updateShowEmptyLine() = 0;
virtual void syncNestedModel(int row, const QStringList &relation);
virtual void syncAllNestedModel(const QStringList &relation);
void syncNestedModelRecursive(IxModel *pNestedModel, const QStringList &relation);
void generateRoleNames();
QSqlDatabase *database(QSqlDatabase *other);
IxModel *getChild(long row, const QString &relation);
void insertChild(long row, const QString &relation, IxModel *pChild);
void removeListOfChild(long row);
bool removeRowsGeneric(int row, int count);
bool removeRowsAutoUpdateOnFieldChange(int row, int count);
#ifndef _QX_NO_JSON
virtual QString toJson_Helper(int row) const = 0;
virtual bool fromJson_Helper(const QString &json, int row) = 0;
virtual QVariant getRelationshipValues_Helper(int row, const QString &relation, bool bLoadFromDatabase, const QString &sAppendRelations) = 0;
virtual bool setRelationshipValues_Helper(int row, const QString &relation, const QVariant &values) = 0;
#endif // _QX_NO_JSON
};
} // namespace qx
#endif // _IX_MODEL_H_

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,83 @@
/****************************************************************************
**
** https://www.qxorm.com/
** Copyright (C) 2013 XDL Team (ic-east.com)
**
** This file is part of the QxOrm library
**
** This software is provided 'as-is', without any express or implied
** warranty. In no event will the authors be held liable for any
** damages arising from the use of this software
**
** Commercial Usage
** Licensees holding valid commercial QxOrm licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and XDL Team
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3.0 as published by the Free Software
** Foundation and appearing in the file 'license.gpl3.txt' included in the
** packaging of this file. Please review the following information to
** ensure the GNU General Public License version 3.0 requirements will be
** met : http://www.gnu.org/copyleft/gpl.html
**
** If you are unsure which license is appropriate for your use, or
** if you have questions regarding the use of this file, please contact :
** ic-east.com
**
****************************************************************************/
#ifndef _QX_MODEL_ROW_COMPARE_H_
#define _QX_MODEL_ROW_COMPARE_H_
#ifdef _MSC_VER
#pragma once
#endif
/*!
* \file QxModelRowCompare.h
* \author XDL Team
* \ingroup QxModelView
* \brief Functor used to provide sort feature for all models based on qx::IxModel interface (please note that you can also use QSortFilterProxyModel Qt class to sort your model)
*/
#include <QxDataMember/IxDataMember.h>
namespace qx
{
namespace model_view
{
QX_DLL_EXPORT bool compareQVariant(const QVariant &v1, const QVariant &v2, bool bAscending) QX_USED;
/*!
* \ingroup QxModelView
* \brief qx::QxModelRowCompare : functor used to provide sort feature for all models based on qx::IxModel interface (please note that you can also use QSortFilterProxyModel Qt class to sort your model)
*/
template <typename T>
struct QxModelRowCompare
{
bool m_bAscendingOrder; //!< Sort your model using ascending or descending order
qx::IxDataMember *m_pDataMember; //!< Data member associated to the model column to sort
QxModelRowCompare(bool bAscendingOrder, qx::IxDataMember *pDataMember) : m_bAscendingOrder(bAscendingOrder), m_pDataMember(pDataMember) { qAssert(m_pDataMember != NULL); }
bool operator()(const T &t1, const T &t2) const
{
if (!m_pDataMember || !t1.second || !t2.second)
{
return false;
}
QVariant v1 = m_pDataMember->toVariant(&(*t1.second));
QVariant v2 = m_pDataMember->toVariant(&(*t2.second));
return qx::model_view::compareQVariant(v1, v2, m_bAscendingOrder);
}
};
} // namespace model_view
} // namespace qx
#endif // _QX_MODEL_ROW_COMPARE_H_

View File

@@ -0,0 +1,577 @@
/****************************************************************************
**
** https://www.qxorm.com/
** Copyright (C) 2013 XDL Team (ic-east.com)
**
** This file is part of the QxOrm library
**
** This software is provided 'as-is', without any express or implied
** warranty. In no event will the authors be held liable for any
** damages arising from the use of this software
**
** Commercial Usage
** Licensees holding valid commercial QxOrm licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and XDL Team
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3.0 as published by the Free Software
** Foundation and appearing in the file 'license.gpl3.txt' included in the
** packaging of this file. Please review the following information to
** ensure the GNU General Public License version 3.0 requirements will be
** met : http://www.gnu.org/copyleft/gpl.html
**
** If you are unsure which license is appropriate for your use, or
** if you have questions regarding the use of this file, please contact :
** ic-east.com
**
****************************************************************************/
#ifndef _QX_MODEL_SERVICE_H_
#define _QX_MODEL_SERVICE_H_
#ifdef _MSC_VER
#pragma once
#endif
/*!
* \file QxModelService.h
* \author XDL Team
* \ingroup QxModelView
* \brief qx::QxModelService<T, S> provides an easy way to connect your model to the QxService module (all queries are executed over network using client/server communication)
*/
#include <QxModelView/QxModel.h>
namespace qx
{
/*!
* \ingroup QxModelView
* \brief qx::QxModelService<T, S> : provides an easy way to connect your model to the QxService module (all queries are executed over network using client/server communication)
*
* T template parameter is a persistent class registered into QxOrm context
* S template parameter is a service class generated by QxEntityEditor (or your own service class providing all methods)
*/
template <class T, class S, class B = qx::IxModel>
class QxModelService : public qx::QxModel<T, B>
{
public:
typedef typename qx::QxModel<T, B>::type_ptr type_ptr;
typedef typename qx::QxModel<T, B>::type_primary_key type_primary_key;
typedef typename qx::QxModel<T, B>::type_collection type_collection;
typedef std::shared_ptr<type_collection> type_collection_ptr;
typedef B type_base_class;
public:
QxModelService(QObject *parent = 0) : qx::QxModel<T, B>(parent) { ; }
QxModelService(qx::IxModel *other, QObject *parent) : qx::QxModel<T, B>(other, parent) { ; }
virtual ~QxModelService() { ; }
virtual long qxCount(const qx::QxSqlQuery &query = qx::QxSqlQuery(), QSqlDatabase *pDatabase = NULL)
{
long lCount = 0;
this->qxCount(lCount, query, pDatabase);
return lCount;
}
virtual QSqlError qxCount(long &lCount, const qx::QxSqlQuery &query = qx::QxSqlQuery(), QSqlDatabase *pDatabase = NULL)
{
Q_UNUSED(pDatabase);
S services;
this->m_lastError = services.count(lCount, query);
return this->m_lastError;
}
virtual QSqlError qxFetchById(const QVariant &id, const QStringList &relation = QStringList(), QSqlDatabase *pDatabase = NULL)
{
Q_UNUSED(pDatabase);
this->clear();
type_ptr pItem = type_ptr(new T());
if (!this->m_pDataMemberId)
{
qDebug("[QxOrm] problem with 'qxFetchById()' method : '%s'", "data member id not registered");
qAssert(false);
}
if (!this->m_pDataMemberId)
{
this->m_lastError = QSqlError("[QxOrm] problem with 'qxFetchById()' method : 'data member id not registered'", "", QSqlError::UnknownError);
return this->m_lastError;
}
this->m_pDataMemberId->fromVariant(pItem.get(), id);
type_primary_key primaryKey;
qx::cvt::from_variant(id, primaryKey);
this->beginInsertRows(QModelIndex(), 0, 0);
this->m_model.insert(primaryKey, pItem);
S services;
this->m_lastError = services.fetchById(pItem, this->m_lstColumns, relation);
this->updateShowEmptyLine();
this->endInsertRows();
return this->m_lastError;
}
virtual QSqlError qxFetchAll(const QStringList &relation = QStringList(), QSqlDatabase *pDatabase = NULL)
{
Q_UNUSED(pDatabase);
this->clear();
S services;
type_collection_ptr tmp = std::make_shared<type_collection>();
this->m_lastError = services.fetchAll(tmp, this->m_lstColumns, relation);
if (tmp->count() <= 0)
{
return this->m_lastError;
}
this->beginResetModel();
this->m_model = (*tmp);
this->updateShowEmptyLine();
this->endResetModel();
return this->m_lastError;
}
virtual QSqlError qxFetchByQuery(const qx::QxSqlQuery &query, const QStringList &relation = QStringList(), QSqlDatabase *pDatabase = NULL)
{
Q_UNUSED(pDatabase);
this->clear();
S services;
type_collection_ptr tmp = std::make_shared<type_collection>();
this->m_lastError = services.fetchByQuery(query, tmp, this->m_lstColumns, relation);
if (tmp->count() <= 0)
{
return this->m_lastError;
}
this->beginResetModel();
this->m_model = (*tmp);
this->updateShowEmptyLine();
this->endResetModel();
return this->m_lastError;
}
virtual QSqlError qxFetchRow(int row, const QStringList &relation = QStringList(), QSqlDatabase *pDatabase = NULL)
{
Q_UNUSED(pDatabase);
if ((row < 0) || (row >= this->m_model.count()))
{
return QSqlError();
}
type_ptr pItem = this->m_model.getByIndex(row);
if (!pItem)
{
return QSqlError();
}
S services;
this->m_lastError = services.fetchById(pItem, this->m_lstColumns, relation);
if (this->m_lastError.isValid())
{
return this->m_lastError;
}
QModelIndex idxTopLeft = this->index(row, 0);
QModelIndex idxBottomRight = this->index(row, (this->m_lstDataMember.count() - 1));
this->raiseEvent_dataChanged(idxTopLeft, idxBottomRight);
this->updateKey(row);
return this->m_lastError;
}
virtual QSqlError qxInsert(const QStringList &relation = QStringList(), QSqlDatabase *pDatabase = NULL, bool bUseExecBatch = false)
{
Q_UNUSED(pDatabase);
Q_UNUSED(bUseExecBatch);
if (relation.count() > 0)
{
this->syncAllNestedModel(relation);
}
type_collection_ptr tmp = std::make_shared<type_collection>();
(*tmp) = this->m_model;
S services;
this->m_lastError = services.insert(tmp, relation);
if (!this->m_lastError.isValid())
{
this->updateAllKeys();
}
return this->m_lastError;
}
virtual QSqlError qxInsertRow(int row, const QStringList &relation = QStringList(), QSqlDatabase *pDatabase = NULL)
{
Q_UNUSED(pDatabase);
if ((row < 0) || (row >= this->m_model.count()))
{
return QSqlError();
}
if (relation.count() > 0)
{
this->syncNestedModel(row, relation);
}
type_ptr pItem = this->m_model.getByIndex(row);
if (!pItem)
{
return QSqlError();
}
S services;
this->m_lastError = services.insert(pItem, relation);
if (!this->m_lastError.isValid())
{
this->updateKey(row);
}
return this->m_lastError;
}
virtual QSqlError qxUpdate(const qx::QxSqlQuery &query = qx::QxSqlQuery(), const QStringList &relation = QStringList(), QSqlDatabase *pDatabase = NULL, bool bUseExecBatch = false)
{
Q_UNUSED(pDatabase);
Q_UNUSED(bUseExecBatch);
if (relation.count() > 0)
{
this->syncAllNestedModel(relation);
}
type_collection_ptr tmp = std::make_shared<type_collection>();
(*tmp) = this->m_model;
S services;
this->m_lastError = services.update(tmp, query, this->m_lstColumns, relation);
if (!this->m_lastError.isValid())
{
this->updateAllKeys();
}
return this->m_lastError;
}
virtual QSqlError qxUpdateRow(int row, const qx::QxSqlQuery &query = qx::QxSqlQuery(), const QStringList &relation = QStringList(), QSqlDatabase *pDatabase = NULL)
{
Q_UNUSED(pDatabase);
if ((row < 0) || (row >= this->m_model.count()))
{
return QSqlError();
}
if (relation.count() > 0)
{
this->syncNestedModel(row, relation);
}
type_ptr pItem = this->m_model.getByIndex(row);
if (!pItem)
{
return QSqlError();
}
S services;
this->m_lastError = services.update(pItem, query, this->m_lstColumns, relation);
if (!this->m_lastError.isValid())
{
this->updateKey(row);
}
return this->m_lastError;
}
virtual QSqlError qxSave(const QStringList &relation = QStringList(), QSqlDatabase *pDatabase = NULL)
{
Q_UNUSED(pDatabase);
if (relation.count() > 0)
{
this->syncAllNestedModel(relation);
}
type_collection_ptr tmp = std::make_shared<type_collection>();
(*tmp) = this->m_model;
S services;
this->m_lastError = services.save(tmp, relation);
if (!this->m_lastError.isValid())
{
this->updateAllKeys();
}
return this->m_lastError;
}
virtual QSqlError qxSaveRow(int row, const QStringList &relation = QStringList(), QSqlDatabase *pDatabase = NULL)
{
Q_UNUSED(pDatabase);
if ((row < 0) || (row >= this->m_model.count()))
{
return QSqlError();
}
if (relation.count() > 0)
{
this->syncNestedModel(row, relation);
}
type_ptr pItem = this->m_model.getByIndex(row);
if (!pItem)
{
return QSqlError();
}
S services;
this->m_lastError = services.save(pItem, relation);
if (!this->m_lastError.isValid())
{
this->updateKey(row);
}
return this->m_lastError;
}
virtual QSqlError qxDeleteById(const QVariant &id, QSqlDatabase *pDatabase = NULL)
{
Q_UNUSED(pDatabase);
type_ptr pItem = type_ptr(new T());
if (!this->m_pDataMemberId)
{
qDebug("[QxOrm] problem with 'qxDeleteById()' method : '%s'", "data member id not registered");
qAssert(false);
}
if (!this->m_pDataMemberId)
{
this->m_lastError = QSqlError("[QxOrm] problem with 'qxDeleteById()' method : 'data member id not registered'", "", QSqlError::UnknownError);
return this->m_lastError;
}
this->m_pDataMemberId->fromVariant(pItem.get(), id);
S services;
this->m_lastError = services.deleteById(pItem);
return this->m_lastError;
}
virtual QSqlError qxDeleteAll(QSqlDatabase *pDatabase = NULL)
{
Q_UNUSED(pDatabase);
S services;
this->m_lastError = services.deleteAll();
return this->m_lastError;
}
virtual QSqlError qxDeleteByQuery(const qx::QxSqlQuery &query, QSqlDatabase *pDatabase = NULL)
{
Q_UNUSED(pDatabase);
S services;
this->m_lastError = services.deleteByQuery(query);
return this->m_lastError;
}
virtual QSqlError qxDeleteRow(int row, QSqlDatabase *pDatabase = NULL)
{
Q_UNUSED(pDatabase);
if ((row < 0) || (row >= this->m_model.count()))
{
return QSqlError();
}
type_ptr pItem = this->m_model.getByIndex(row);
if (!pItem)
{
return QSqlError();
}
S services;
this->m_lastError = services.deleteById(pItem);
return this->m_lastError;
}
virtual QSqlError qxDestroyById(const QVariant &id, QSqlDatabase *pDatabase = NULL)
{
Q_UNUSED(pDatabase);
type_ptr pItem = type_ptr(new T());
if (!this->m_pDataMemberId)
{
qDebug("[QxOrm] problem with 'qxDeleteById()' method : '%s'", "data member id not registered");
qAssert(false);
}
if (!this->m_pDataMemberId)
{
this->m_lastError = QSqlError("[QxOrm] problem with 'qxDeleteById()' method : 'data member id not registered'", "", QSqlError::UnknownError);
return this->m_lastError;
}
this->m_pDataMemberId->fromVariant(pItem.get(), id);
S services;
this->m_lastError = services.destroyById(pItem);
return this->m_lastError;
}
virtual QSqlError qxDestroyAll(QSqlDatabase *pDatabase = NULL)
{
Q_UNUSED(pDatabase);
S services;
this->m_lastError = services.destroyAll();
return this->m_lastError;
}
virtual QSqlError qxDestroyByQuery(const qx::QxSqlQuery &query, QSqlDatabase *pDatabase = NULL)
{
Q_UNUSED(pDatabase);
S services;
this->m_lastError = services.destroyByQuery(query);
return this->m_lastError;
}
virtual QSqlError qxDestroyRow(int row, QSqlDatabase *pDatabase = NULL)
{
Q_UNUSED(pDatabase);
if ((row < 0) || (row >= this->m_model.count()))
{
return QSqlError();
}
type_ptr pItem = this->m_model.getByIndex(row);
if (!pItem)
{
return QSqlError();
}
S services;
this->m_lastError = services.destroyById(pItem);
return this->m_lastError;
}
virtual QSqlError qxExecuteQuery(qx::QxSqlQuery &query, QSqlDatabase *pDatabase = NULL)
{
Q_UNUSED(pDatabase);
this->clear();
S services;
type_collection_ptr tmp = std::make_shared<type_collection>();
this->m_lastError = services.executeQuery(query, tmp);
if (tmp->count() <= 0)
{
return this->m_lastError;
}
this->beginResetModel();
this->m_model = (*tmp);
this->updateShowEmptyLine();
this->endResetModel();
return this->m_lastError;
}
virtual qx_bool qxExist(const QVariant &id, QSqlDatabase *pDatabase = NULL)
{
Q_UNUSED(pDatabase);
type_ptr pItem = type_ptr(new T());
if (!this->m_pDataMemberId)
{
qDebug("[QxOrm] problem with 'qxExist()' method : '%s'", "data member id not registered");
qAssert(false);
}
if (!this->m_pDataMemberId)
{
return qx_bool(false);
}
this->m_pDataMemberId->fromVariant(pItem.get(), id);
S services;
return services.exist(pItem);
}
virtual qx::QxInvalidValueX qxValidate(const QStringList &groups = QStringList())
{
Q_UNUSED(groups);
S services;
type_collection_ptr tmp = std::make_shared<type_collection>();
(*tmp) = this->m_model;
return services.isValid(tmp);
}
virtual qx::QxInvalidValueX qxValidateRow(int row, const QStringList &groups = QStringList())
{
Q_UNUSED(groups);
if ((row < 0) || (row >= this->m_model.count()))
{
return qx::QxInvalidValueX();
}
type_ptr pItem = this->m_model.getByIndex(row);
if (!pItem)
{
return qx::QxInvalidValueX();
}
S services;
return services.isValid(pItem);
}
protected:
#ifndef _QX_NO_JSON
virtual QVariant getRelationshipValues_Helper(int row, const QString &relation, bool bLoadFromDatabase, const QString &sAppendRelations)
{
if ((row < 0) || (row >= this->m_model.count()))
{
return QVariant();
}
if (!this->m_pDataMemberId || !this->m_pDataMemberX || !this->m_pDataMemberX->exist(relation))
{
return QVariant();
}
IxDataMember *pDataMember = this->m_pDataMemberX->get_WithDaoStrategy(relation);
if (!pDataMember)
{
return QVariant();
}
IxSqlRelation *pRelation = (pDataMember->hasSqlRelation() ? pDataMember->getSqlRelation() : NULL);
if (!pRelation)
{
return QVariant();
}
type_ptr pItem = this->m_model.getByIndex(row);
if (!pItem)
{
return QVariant();
}
type_ptr pItemTemp = pItem;
if (bLoadFromDatabase)
{
QString sRelation = relation;
if (!sAppendRelations.isEmpty() && !sAppendRelations.startsWith("->") && !sAppendRelations.startsWith(">>"))
{
sRelation += "->" + sAppendRelations;
}
else if (!sAppendRelations.isEmpty())
{
sRelation += sAppendRelations;
}
pItemTemp = type_ptr(new T());
QVariant id = this->m_pDataMemberId->toVariant(pItem.get());
this->m_pDataMemberId->fromVariant(pItemTemp.get(), id);
S services;
QStringList columns;
QSqlError daoError = services.fetchById(pItemTemp, columns, QStringList() << sRelation);
if (daoError.isValid())
{
return QVariant();
}
}
QJsonValue json = pDataMember->toJson(pItemTemp.get());
if (json.isNull())
{
return QVariant();
}
if (json.isArray())
{
return json.toArray().toVariantList();
}
return json.toObject().toVariantMap();
}
#endif // _QX_NO_JSON
};
} // namespace qx
#endif // _QX_MODEL_SERVICE_H_

View File

@@ -0,0 +1,483 @@
/****************************************************************************
**
** https://www.qxorm.com/
** Copyright (C) 2013 XDL Team (ic-east.com)
**
** This file is part of the QxOrm library
**
** This software is provided 'as-is', without any express or implied
** warranty. In no event will the authors be held liable for any
** damages arising from the use of this software
**
** Commercial Usage
** Licensees holding valid commercial QxOrm licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and XDL Team
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3.0 as published by the Free Software
** Foundation and appearing in the file 'license.gpl3.txt' included in the
** packaging of this file. Please review the following information to
** ensure the GNU General Public License version 3.0 requirements will be
** met : http://www.gnu.org/copyleft/gpl.html
**
** If you are unsure which license is appropriate for your use, or
** if you have questions regarding the use of this file, please contact :
** ic-east.com
**
****************************************************************************/
#ifndef _QX_NESTED_MODEL_H_
#define _QX_NESTED_MODEL_H_
#ifdef _MSC_VER
#pragma once
#endif
/*!
* \file QxNestedModel.h
* \author XDL Team
* \ingroup QxModelView
* \brief qx::model_view::create_nested_model is used by QxEntityEditor to manage complex data structure to work with relationships in QML views and Qt model/view architecture
*/
#include <QxConvert/QxConvert.h>
#include <QxCollection/QxCollection.h>
#include <QxTraits/is_qx_registered.h>
#include <QxTraits/is_container.h>
#include <QxTraits/is_smart_ptr.h>
#include <QxTraits/get_base_class.h>
#include <QxTraits/get_class_name_primitive.h>
#include <QxTraits/construct_ptr.h>
#include <QxTraits/generic_container.h>
#include <QxTraits/is_valid_primary_key.h>
#include <QxSerialize/QxClone.h>
#include <QxModelView/IxModel.h>
#include <QxModelView/QxModel.h>
namespace qx
{
namespace model_view
{
template <class T>
qx::IxModel *create_nested_model(qx::IxModel *pParent, const QModelIndex &idxParent, T &t);
template <class T, class M>
qx::IxModel *create_nested_model_with_type(qx::IxModel *pParent, const QModelIndex &idxParent, T &t, M *pModelType);
template <class T>
void sync_nested_model(qx::IxModel *pModel, T &t);
} // namespace model_view
} // namespace qx
namespace qx
{
namespace model_view
{
namespace detail
{
template <class T, class M /* = void */>
struct QxNestedModel;
template <class T, bool bIsQObject /* = false */>
struct QxNestedModel_Helper
{
static std::shared_ptr<T> clone(T &t)
{
std::shared_ptr<T> p = std::make_shared<T>();
(*p) = t;
return p;
}
static void synchronize(T &t1, T &t2)
{
t1 = t2;
}
};
template <class T>
struct QxNestedModel_Helper<T, true>
{
static std::shared_ptr<T> clone(T &t)
{
std::shared_ptr<T> p;
p.reset(qx::clone_to_nude_ptr(t));
qAssert(p);
return p;
}
static void synchronize(T &t1, T &t2)
{
qx::IxClass *pClass = qx::QxClass<T>::getSingleton();
qx::IxDataMemberX *pDataMemberX = (pClass ? pClass->getDataMemberX() : NULL);
for (long l = 0; (pDataMemberX && (l < pDataMemberX->count_WithDaoStrategy())); l++)
{
qx::IxDataMember *pDataMember = pDataMemberX->get_WithDaoStrategy(l);
if (!pDataMember)
{
continue;
}
QVariant value = pDataMember->toVariant(&t2);
pDataMember->fromVariant((&t1), value);
}
}
};
template <class T, class M, bool bIsTypeVoid /* = false */>
struct QxNestedModel_Creator
{
static qx::IxModel *newModel(qx::IxModel *pParent) { return new M(pParent); }
};
template <class T, class M>
struct QxNestedModel_Creator<T, M, true>
{
static qx::IxModel *newModel(qx::IxModel *pParent) { return new qx::QxModel<T>(pParent); }
};
template <class T, class M /* = void */>
struct QxNestedModel_Generic
{
typedef typename qx::QxModel<T>::type_collection type_collection;
typedef typename qx::QxModel<T>::type_primary_key type_primary_key;
typedef typename qx::QxModel<T>::type_ptr type_ptr;
enum
{
is_valid = qx::trait::is_qx_registered<T>::value
};
static inline qx::IxModel *create(qx::IxModel *pParent, const QModelIndex &idxParent, T &t)
{
static_assert(is_valid, "is_valid");
qx::IxModel *pModel = qx::model_view::detail::QxNestedModel_Creator<T, M, std::is_same<M, void>::value>::newModel(pParent);
pModel->setParentModel(pParent);
type_collection *pListOfItems = static_cast<type_collection *>(pModel->getCollection());
long &idx = pModel->m_lManualInsertIndex;
type_primary_key key;
pModel->beginInsertRows(idxParent, 0, 0);
type_ptr ptr = qx::model_view::detail::QxNestedModel_Helper<T, std::is_base_of<QObject, T>::value>::clone(t);
qx::IxDataMember *pDataMemberId = pModel->m_pDataMemberId;
if (!pDataMemberId)
{
qAssert(false);
pModel->endInsertRows();
return pModel;
}
QVariant value = pDataMemberId->toVariant(&t);
if (!qx::trait::is_valid_primary_key(value))
{
idx--;
value = QVariant(static_cast<qlonglong>(idx));
}
qx::cvt::from_variant(value, key);
pListOfItems->insert(0, key, ptr);
pModel->endInsertRows();
return pModel;
}
static inline void synchronize(qx::IxModel *pModel, T &t)
{
if (!pModel)
{
qAssert(false);
return;
}
type_collection *pListOfItems = static_cast<type_collection *>(pModel->getCollection());
if (!pListOfItems || (pListOfItems->count() <= 0))
{
return;
}
type_ptr ptr = pListOfItems->getByIndex(0);
if (!ptr)
{
return;
}
qx::model_view::detail::QxNestedModel_Helper<T, std::is_base_of<QObject, T>::value>::synchronize(t, (*ptr));
}
};
template <class T, class M /* = void */>
struct QxNestedModel_Container
{
typedef qx::trait::generic_container<T> type_generic_container;
typedef typename type_generic_container::type_value_qx type_data;
typedef typename type_generic_container::type_item type_item;
typedef typename qx::QxModel<type_data>::type_collection type_collection;
typedef typename qx::QxModel<type_data>::type_primary_key type_primary_key;
typedef typename qx::QxModel<type_data>::type_ptr type_ptr;
enum
{
is_valid = qx::trait::is_qx_registered<type_data>::value
};
static inline qx::IxModel *create(qx::IxModel *pParent, const QModelIndex &idxParent, T &t)
{
int iCurrRow = 0;
static_assert(is_valid, "is_valid");
qx::IxModel *pModel = qx::model_view::detail::QxNestedModel_Creator<type_data, M, std::is_same<M, void>::value>::newModel(pParent);
pModel->setParentModel(pParent);
long lCount = static_cast<long>(type_generic_container::size(t));
if (lCount <= 0)
{
return pModel;
}
pModel->beginInsertRows(idxParent, 0, (lCount - 1));
for (typename T::iterator it = t.begin(); it != t.end(); ++it)
{
insertItem(pModel, (*it), iCurrRow);
iCurrRow++;
}
pModel->endInsertRows();
return pModel;
}
template <typename U>
static inline bool insert(qx::IxModel *pModel, U &item, int iRow)
{
if (!pModel)
{
qAssert(false);
return false;
}
type_collection *pListOfItems = static_cast<type_collection *>(pModel->getCollection());
long &idx = pModel->m_lManualInsertIndex;
type_primary_key key;
type_ptr ptr = qx::model_view::detail::QxNestedModel_Helper<U, std::is_base_of<QObject, U>::value>::clone(item);
qx::IxDataMember *pDataMemberId = pModel->m_pDataMemberId;
if (!pDataMemberId)
{
qAssert(false);
return false;
}
QVariant value = pDataMemberId->toVariant(&item);
if (!qx::trait::is_valid_primary_key(value))
{
idx--;
value = QVariant(static_cast<qlonglong>(idx));
}
qx::cvt::from_variant(value, key);
pListOfItems->insert(iRow, key, ptr);
return true;
}
static inline void synchronize(qx::IxModel *pModel, T &t)
{
if (!pModel)
{
qAssert(false);
return;
}
type_generic_container::clear(t);
type_collection *pListOfItems = static_cast<type_collection *>(pModel->getCollection());
for (long l = 0; l < pListOfItems->count(); l++)
{
type_ptr ptr = pListOfItems->getByIndex(l);
if (!ptr)
{
continue;
}
type_item item = type_generic_container::createItem();
type_data &item_val = item.value_qx();
qx::model_view::detail::QxNestedModel_Helper<type_data, std::is_base_of<QObject, type_data>::value>::synchronize(item_val, (*ptr));
QVariant vKey = QVariant(static_cast<qlonglong>(l));
qx::cvt::from_variant(vKey, item.key());
type_generic_container::insertItem(t, item);
}
}
private:
template <typename U>
static inline bool insertItem(qx::IxModel *pModel, U &item, int iRow)
{
return insertItem_Helper < U, std::is_pointer<U>::value || qx::trait::is_smart_ptr<U>::value > ::insert(pModel, item, iRow);
}
template <typename U, bool bIsPointer /* = true */>
struct insertItem_Helper
{
static inline bool insert(qx::IxModel *pModel, U &item, int iRow)
{
return (item ? qx::model_view::detail::QxNestedModel_Container<T, M>::insertItem(pModel, (*item), iRow) : true);
}
};
template <typename U1, typename U2>
struct insertItem_Helper<std::pair<U1, U2>, false>
{
static inline bool insert(qx::IxModel *pModel, std::pair<U1, U2> &item, int iRow)
{
return qx::model_view::detail::QxNestedModel_Container<T, M>::insertItem(pModel, item.second, iRow);
}
};
template <typename U1, typename U2>
struct insertItem_Helper<const std::pair<U1, U2>, false>
{
static inline bool insert(qx::IxModel *pModel, const std::pair<U1, U2> &item, int iRow)
{
return qx::model_view::detail::QxNestedModel_Container<T, M>::insertItem(pModel, item.second, iRow);
}
};
#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
template <typename U1, typename U2>
struct insertItem_Helper<QPair<U1, U2>, false>
{
static inline bool insert(qx::IxModel *pModel, QPair<U1, U2> &item, int iRow)
{
return qx::model_view::detail::QxNestedModel_Container<T, M>::insertItem(pModel, item.second, iRow);
}
};
template <typename U1, typename U2>
struct insertItem_Helper<const QPair<U1, U2>, false>
{
static inline bool insert(qx::IxModel *pModel, const QPair<U1, U2> &item, int iRow)
{
return qx::model_view::detail::QxNestedModel_Container<T, M>::insertItem(pModel, item.second, iRow);
}
};
#endif // (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
template <typename U>
struct insertItem_Helper<U, false>
{
enum
{
is_same_type = std::is_same<qx::model_view::detail::QxNestedModel_Container<T, M>::type_data, U>::value
};
static bool insert(qx::IxModel *pModel, U &item, int iRow)
{
static_assert(is_same_type, "is_same_type");
return qx::model_view::detail::QxNestedModel_Container<T, M>::insert(pModel, item, iRow);
}
};
};
template <class T, class M /* = void */>
struct QxNestedModel_Ptr
{
static inline qx::IxModel *create(qx::IxModel *pParent, const QModelIndex &idxParent, T &t)
{
return (t ? create_Helper(pParent, idxParent, (*t)) : create_NullHelper(pParent, idxParent));
}
static inline void synchronize(qx::IxModel *pModel, T &t)
{
if (!t)
{
qx::trait::construct_ptr<T>::get(t);
};
if (t)
{
qx::model_view::sync_nested_model(pModel, (*t));
}
}
private:
template <class U>
static inline qx::IxModel *create_Helper(qx::IxModel *pParent, const QModelIndex &idxParent, U &u)
{
return qx::model_view::detail::QxNestedModel<U, M>::create(pParent, idxParent, u);
}
static inline qx::IxModel *create_NullHelper(qx::IxModel *pParent, const QModelIndex &idxParent)
{
M *pModelType = NULL;
Q_UNUSED(pModelType);
T t;
qx::trait::construct_ptr<T>::get(t);
if (!t)
{
qAssert(false);
return NULL;
}
qx::IxModel *pModel = qx::model_view::create_nested_model_with_type(pParent, idxParent, (*t), pModelType);
if (pModel)
{
pModel->clear();
}
qAssert(pModel != NULL);
return pModel;
}
};
template <class T, class M /* = void */>
struct QxNestedModel
{
typedef typename std::conditional<std::is_pointer<T>::value, qx::model_view::detail::QxNestedModel_Ptr<T, M>, qx::model_view::detail::QxNestedModel_Generic<T, M>>::type type_model_view_1;
typedef typename std::conditional<qx::trait::is_smart_ptr<T>::value, qx::model_view::detail::QxNestedModel_Ptr<T, M>, type_model_view_1>::type type_model_view_2;
typedef typename std::conditional<qx::trait::is_container<T>::value, qx::model_view::detail::QxNestedModel_Container<T, M>, type_model_view_2>::type type_model_view_3;
static inline qx::IxModel *create(qx::IxModel *pParent, const QModelIndex &idxParent, T &t)
{
return type_model_view_3::create(pParent, idxParent, t);
}
static inline void synchronize(qx::IxModel *pModel, T &t)
{
type_model_view_3::synchronize(pModel, t);
}
};
} // namespace detail
} // namespace model_view
} // namespace qx
namespace qx
{
namespace model_view
{
/*!
* \ingroup QxModelView
* \brief qx::model_view::create_nested_model is used by QxEntityEditor to manage complex data structure to work with relationships in QML views and Qt model/view architecture
* \param pParent Parent model, qx::model_view::create_nested_model creates a child model associated to this parent model (a NULL value means that the created model is a root model)
* \param idxParent Index parent model, qx::model_view::create_nested_model creates a child model indexed by this parent index model (an empty index means that the created model is a root model)
* \param t Item which contain all values exposed by the model to the views, t item can be a simple type, a pointer, a smart pointer, or a collection of items
*/
template <class T>
qx::IxModel *create_nested_model(qx::IxModel *pParent, const QModelIndex &idxParent, T &t)
{
return qx::model_view::detail::QxNestedModel<T, void>::create(pParent, idxParent, t);
}
template <class T, class M>
qx::IxModel *create_nested_model_with_type(qx::IxModel *pParent, const QModelIndex &idxParent, T &t, M *pModelType)
{
Q_UNUSED(pModelType);
static_assert((std::is_base_of<qx::IxModel, M>::value || std::is_same<M, void>::value), "(std::is_base_of<qx::IxModel, M>::value || std::is_same<M, void>::value)");
return qx::model_view::detail::QxNestedModel<T, M>::create(pParent, idxParent, t);
}
template <class T>
void sync_nested_model(qx::IxModel *pModel, T &t)
{
qx::model_view::detail::QxNestedModel<T, void>::synchronize(pModel, t);
}
} // namespace model_view
} // namespace qx
#endif // _QX_NESTED_MODEL_H_