/**************************************************************************** ** ** https://www.qxorm.com/ ** Copyright (C) 2013 Lionel Marty (contact@qxorm.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 Lionel Marty ** ** 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 : ** contact@qxorm.com ** ****************************************************************************/ #ifndef _QX_NESTED_MODEL_H_ #define _QX_NESTED_MODEL_H_ #ifdef _MSC_VER #pragma once #endif /*! * \file QxNestedModel.h * \author Lionel Marty * \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 #include #include #include #include #include #include #include #include #include #include #include #include namespace qx { namespace model_view { template qx::IxModel * create_nested_model(qx::IxModel * pParent, const QModelIndex & idxParent, T & t); template qx::IxModel * create_nested_model_with_type(qx::IxModel * pParent, const QModelIndex & idxParent, T & t, M * pModelType); template void sync_nested_model(qx::IxModel * pModel, T & t); } // namespace model_view } // namespace qx namespace qx { namespace model_view { namespace detail { template struct QxNestedModel; template struct QxNestedModel_Helper { static std::shared_ptr clone(T & t) { std::shared_ptr p = std::make_shared(); (* p) = t; return p; } static void synchronize(T & t1, T & t2) { t1 = t2; } }; template struct QxNestedModel_Helper { static std::shared_ptr clone(T & t) { std::shared_ptr 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::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 struct QxNestedModel_Creator { static qx::IxModel * newModel(qx::IxModel * pParent) { return new M(pParent); } }; template struct QxNestedModel_Creator { static qx::IxModel * newModel(qx::IxModel * pParent) { return new qx::QxModel(pParent); } }; template struct QxNestedModel_Generic { typedef typename qx::QxModel::type_collection type_collection; typedef typename qx::QxModel::type_primary_key type_primary_key; typedef typename qx::QxModel::type_ptr type_ptr; enum { is_valid = qx::trait::is_qx_registered::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::value>::newModel(pParent); pModel->setParentModel(pParent); type_collection * pListOfItems = static_cast(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::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(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(pModel->getCollection()); if (! pListOfItems || (pListOfItems->count() <= 0)) { return; } type_ptr ptr = pListOfItems->getByIndex(0); if (! ptr) { return; } qx::model_view::detail::QxNestedModel_Helper::value>::synchronize(t, (* ptr)); } }; template struct QxNestedModel_Container { typedef qx::trait::generic_container 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_collection type_collection; typedef typename qx::QxModel::type_primary_key type_primary_key; typedef typename qx::QxModel::type_ptr type_ptr; enum { is_valid = qx::trait::is_qx_registered::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::value>::newModel(pParent); pModel->setParentModel(pParent); long lCount = static_cast(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 static inline bool insert(qx::IxModel * pModel, U & item, int iRow) { if (! pModel) { qAssert(false); return false; } type_collection * pListOfItems = static_cast(pModel->getCollection()); long & idx = pModel->m_lManualInsertIndex; type_primary_key key; type_ptr ptr = qx::model_view::detail::QxNestedModel_Helper::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(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(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::value>::synchronize(item_val, (* ptr)); QVariant vKey = QVariant(static_cast(l)); qx::cvt::from_variant(vKey, item.key()); type_generic_container::insertItem(t, item); } } private: template static inline bool insertItem(qx::IxModel * pModel, U & item, int iRow) { return insertItem_Helper::value || qx::trait::is_smart_ptr::value>::insert(pModel, item, iRow); } template struct insertItem_Helper { static inline bool insert(qx::IxModel * pModel, U & item, int iRow) { return (item ? qx::model_view::detail::QxNestedModel_Container::insertItem(pModel, (* item), iRow) : true); } }; template struct insertItem_Helper, false> { static inline bool insert(qx::IxModel * pModel, std::pair & item, int iRow) { return qx::model_view::detail::QxNestedModel_Container::insertItem(pModel, item.second, iRow); } }; template struct insertItem_Helper, false> { static inline bool insert(qx::IxModel * pModel, const std::pair & item, int iRow) { return qx::model_view::detail::QxNestedModel_Container::insertItem(pModel, item.second, iRow); } }; template struct insertItem_Helper, false> { static inline bool insert(qx::IxModel * pModel, QPair & item, int iRow) { return qx::model_view::detail::QxNestedModel_Container::insertItem(pModel, item.second, iRow); } }; template struct insertItem_Helper, false> { static inline bool insert(qx::IxModel * pModel, const QPair & item, int iRow) { return qx::model_view::detail::QxNestedModel_Container::insertItem(pModel, item.second, iRow); } }; template struct insertItem_Helper { enum { is_same_type = std::is_same::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::insert(pModel, item, iRow); } }; }; template 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::get(t); }; if (t) { qx::model_view::sync_nested_model(pModel, (* t)); } } private: template static inline qx::IxModel * create_Helper(qx::IxModel * pParent, const QModelIndex & idxParent, U & u) { return qx::model_view::detail::QxNestedModel::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::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 struct QxNestedModel { typedef typename std::conditional< std::is_pointer::value, qx::model_view::detail::QxNestedModel_Ptr, qx::model_view::detail::QxNestedModel_Generic >::type type_model_view_1; typedef typename std::conditional< qx::trait::is_smart_ptr::value, qx::model_view::detail::QxNestedModel_Ptr, type_model_view_1 >::type type_model_view_2; typedef typename std::conditional< qx::trait::is_container::value, qx::model_view::detail::QxNestedModel_Container, 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 qx::IxModel * create_nested_model(qx::IxModel * pParent, const QModelIndex & idxParent, T & t) { return qx::model_view::detail::QxNestedModel::create(pParent, idxParent, t); } template 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::value || std::is_same::value), "(std::is_base_of::value || std::is_same::value)"); return qx::model_view::detail::QxNestedModel::create(pParent, idxParent, t); } template void sync_nested_model(qx::IxModel * pModel, T & t) { qx::model_view::detail::QxNestedModel::synchronize(pModel, t); } } // namespace model_view } // namespace qx #endif // _QX_NESTED_MODEL_H_