QxOrm
1.5.0
C++ Object Relational Mapping library
|
00001 /**************************************************************************** 00002 ** 00003 ** https://www.qxorm.com/ 00004 ** Copyright (C) 2013 Lionel Marty (contact@qxorm.com) 00005 ** 00006 ** This file is part of the QxOrm library 00007 ** 00008 ** This software is provided 'as-is', without any express or implied 00009 ** warranty. In no event will the authors be held liable for any 00010 ** damages arising from the use of this software 00011 ** 00012 ** Commercial Usage 00013 ** Licensees holding valid commercial QxOrm licenses may use this file in 00014 ** accordance with the commercial license agreement provided with the 00015 ** Software or, alternatively, in accordance with the terms contained in 00016 ** a written agreement between you and Lionel Marty 00017 ** 00018 ** GNU General Public License Usage 00019 ** Alternatively, this file may be used under the terms of the GNU 00020 ** General Public License version 3.0 as published by the Free Software 00021 ** Foundation and appearing in the file 'license.gpl3.txt' included in the 00022 ** packaging of this file. Please review the following information to 00023 ** ensure the GNU General Public License version 3.0 requirements will be 00024 ** met : http://www.gnu.org/copyleft/gpl.html 00025 ** 00026 ** If you are unsure which license is appropriate for your use, or 00027 ** if you have questions regarding the use of this file, please contact : 00028 ** contact@qxorm.com 00029 ** 00030 ****************************************************************************/ 00031 00032 #ifndef _QX_NESTED_MODEL_H_ 00033 #define _QX_NESTED_MODEL_H_ 00034 00035 #ifdef _MSC_VER 00036 #pragma once 00037 #endif 00038 00046 #include <QxConvert/QxConvert.h> 00047 00048 #include <QxCollection/QxCollection.h> 00049 00050 #include <QxTraits/is_qx_registered.h> 00051 #include <QxTraits/is_container.h> 00052 #include <QxTraits/is_smart_ptr.h> 00053 #include <QxTraits/get_base_class.h> 00054 #include <QxTraits/get_class_name_primitive.h> 00055 #include <QxTraits/construct_ptr.h> 00056 #include <QxTraits/generic_container.h> 00057 #include <QxTraits/is_valid_primary_key.h> 00058 00059 #include <QxSerialize/QxClone.h> 00060 00061 #include <QxModelView/IxModel.h> 00062 #include <QxModelView/QxModel.h> 00063 00064 namespace qx { 00065 namespace model_view { 00066 00067 template <class T> 00068 qx::IxModel * create_nested_model(qx::IxModel * pParent, const QModelIndex & idxParent, T & t); 00069 00070 template <class T, class M> 00071 qx::IxModel * create_nested_model_with_type(qx::IxModel * pParent, const QModelIndex & idxParent, T & t, M * pModelType); 00072 00073 template <class T> 00074 void sync_nested_model(qx::IxModel * pModel, T & t); 00075 00076 } // namespace model_view 00077 } // namespace qx 00078 00079 namespace qx { 00080 namespace model_view { 00081 namespace detail { 00082 00083 template <class T, class M /* = void */> 00084 struct QxNestedModel; 00085 00086 template <class T, bool bIsQObject /* = false */> 00087 struct QxNestedModel_Helper 00088 { 00089 00090 static std::shared_ptr<T> clone(T & t) 00091 { std::shared_ptr<T> p = std::make_shared<T>(); (* p) = t; return p; } 00092 00093 static void synchronize(T & t1, T & t2) 00094 { t1 = t2; } 00095 00096 }; 00097 00098 template <class T> 00099 struct QxNestedModel_Helper<T, true> 00100 { 00101 00102 static std::shared_ptr<T> clone(T & t) 00103 { std::shared_ptr<T> p; p.reset(qx::clone_to_nude_ptr(t)); qAssert(p); return p; } 00104 00105 static void synchronize(T & t1, T & t2) 00106 { 00107 qx::IxClass * pClass = qx::QxClass<T>::getSingleton(); 00108 qx::IxDataMemberX * pDataMemberX = (pClass ? pClass->getDataMemberX() : NULL); 00109 for (long l = 0; (pDataMemberX && (l < pDataMemberX->count_WithDaoStrategy())); l++) 00110 { 00111 qx::IxDataMember * pDataMember = pDataMemberX->get_WithDaoStrategy(l); if (! pDataMember) { continue; } 00112 QVariant value = pDataMember->toVariant(& t2); 00113 pDataMember->fromVariant((& t1), value); 00114 } 00115 } 00116 00117 }; 00118 00119 template <class T, class M, bool bIsTypeVoid /* = false */> 00120 struct QxNestedModel_Creator 00121 { static qx::IxModel * newModel(qx::IxModel * pParent) { return new M(pParent); } }; 00122 00123 template <class T, class M> 00124 struct QxNestedModel_Creator<T, M, true> 00125 { static qx::IxModel * newModel(qx::IxModel * pParent) { return new qx::QxModel<T>(pParent); } }; 00126 00127 template <class T, class M /* = void */> 00128 struct QxNestedModel_Generic 00129 { 00130 00131 typedef typename qx::QxModel<T>::type_collection type_collection; 00132 typedef typename qx::QxModel<T>::type_primary_key type_primary_key; 00133 typedef typename qx::QxModel<T>::type_ptr type_ptr; 00134 00135 enum { is_valid = qx::trait::is_qx_registered<T>::value }; 00136 00137 static inline qx::IxModel * create(qx::IxModel * pParent, const QModelIndex & idxParent, T & t) 00138 { 00139 static_assert(is_valid, "is_valid"); 00140 qx::IxModel * pModel = qx::model_view::detail::QxNestedModel_Creator<T, M, std::is_same<M, void>::value>::newModel(pParent); 00141 pModel->setParentModel(pParent); 00142 type_collection * pListOfItems = static_cast<type_collection *>(pModel->getCollection()); 00143 long & idx = pModel->m_lManualInsertIndex; 00144 type_primary_key key; 00145 00146 pModel->beginInsertRows(idxParent, 0, 0); 00147 type_ptr ptr = qx::model_view::detail::QxNestedModel_Helper<T, std::is_base_of<QObject, T>::value>::clone(t); 00148 qx::IxDataMember * pDataMemberId = pModel->m_pDataMemberId; 00149 if (! pDataMemberId) { qAssert(false); pModel->endInsertRows(); return pModel; } 00150 QVariant value = pDataMemberId->toVariant(& t); 00151 if (! qx::trait::is_valid_primary_key(value)) 00152 { idx--; value = QVariant(static_cast<qlonglong>(idx)); } 00153 qx::cvt::from_variant(value, key); 00154 pListOfItems->insert(0, key, ptr); 00155 pModel->endInsertRows(); 00156 return pModel; 00157 } 00158 00159 static inline void synchronize(qx::IxModel * pModel, T & t) 00160 { 00161 if (! pModel) { qAssert(false); return; } 00162 type_collection * pListOfItems = static_cast<type_collection *>(pModel->getCollection()); 00163 if (! pListOfItems || (pListOfItems->count() <= 0)) { return; } 00164 type_ptr ptr = pListOfItems->getByIndex(0); if (! ptr) { return; } 00165 qx::model_view::detail::QxNestedModel_Helper<T, std::is_base_of<QObject, T>::value>::synchronize(t, (* ptr)); 00166 } 00167 00168 }; 00169 00170 template <class T, class M /* = void */> 00171 struct QxNestedModel_Container 00172 { 00173 00174 typedef qx::trait::generic_container<T> type_generic_container; 00175 typedef typename type_generic_container::type_value_qx type_data; 00176 typedef typename type_generic_container::type_item type_item; 00177 typedef typename qx::QxModel<type_data>::type_collection type_collection; 00178 typedef typename qx::QxModel<type_data>::type_primary_key type_primary_key; 00179 typedef typename qx::QxModel<type_data>::type_ptr type_ptr; 00180 00181 enum { is_valid = qx::trait::is_qx_registered<type_data>::value }; 00182 00183 static inline qx::IxModel * create(qx::IxModel * pParent, const QModelIndex & idxParent, T & t) 00184 { 00185 int iCurrRow = 0; 00186 static_assert(is_valid, "is_valid"); 00187 qx::IxModel * pModel = qx::model_view::detail::QxNestedModel_Creator<type_data, M, std::is_same<M, void>::value>::newModel(pParent); 00188 pModel->setParentModel(pParent); 00189 long lCount = static_cast<long>(type_generic_container::size(t)); 00190 if (lCount <= 0) { return pModel; } 00191 00192 pModel->beginInsertRows(idxParent, 0, (lCount - 1)); 00193 for (typename T::iterator it = t.begin(); it != t.end(); ++it) 00194 { insertItem(pModel, (* it), iCurrRow); iCurrRow++; } 00195 pModel->endInsertRows(); 00196 return pModel; 00197 } 00198 00199 template <typename U> 00200 static inline bool insert(qx::IxModel * pModel, U & item, int iRow) 00201 { 00202 if (! pModel) { qAssert(false); return false; } 00203 type_collection * pListOfItems = static_cast<type_collection *>(pModel->getCollection()); 00204 long & idx = pModel->m_lManualInsertIndex; 00205 type_primary_key key; 00206 00207 type_ptr ptr = qx::model_view::detail::QxNestedModel_Helper<U, std::is_base_of<QObject, U>::value>::clone(item); 00208 qx::IxDataMember * pDataMemberId = pModel->m_pDataMemberId; 00209 if (! pDataMemberId) { qAssert(false); return false; } 00210 QVariant value = pDataMemberId->toVariant(& item); 00211 if (! qx::trait::is_valid_primary_key(value)) 00212 { idx--; value = QVariant(static_cast<qlonglong>(idx)); } 00213 qx::cvt::from_variant(value, key); 00214 pListOfItems->insert(iRow, key, ptr); 00215 return true; 00216 } 00217 00218 static inline void synchronize(qx::IxModel * pModel, T & t) 00219 { 00220 if (! pModel) { qAssert(false); return; } 00221 type_generic_container::clear(t); 00222 type_collection * pListOfItems = static_cast<type_collection *>(pModel->getCollection()); 00223 00224 for (long l = 0; l < pListOfItems->count(); l++) 00225 { 00226 type_ptr ptr = pListOfItems->getByIndex(l); if (! ptr) { continue; } 00227 type_item item = type_generic_container::createItem(); 00228 type_data & item_val = item.value_qx(); 00229 qx::model_view::detail::QxNestedModel_Helper<type_data, std::is_base_of<QObject, type_data>::value>::synchronize(item_val, (* ptr)); 00230 QVariant vKey = QVariant(static_cast<qlonglong>(l)); 00231 qx::cvt::from_variant(vKey, item.key()); 00232 type_generic_container::insertItem(t, item); 00233 } 00234 } 00235 00236 private: 00237 00238 template <typename U> 00239 static inline bool insertItem(qx::IxModel * pModel, U & item, int iRow) 00240 { return insertItem_Helper<U, std::is_pointer<U>::value || qx::trait::is_smart_ptr<U>::value>::insert(pModel, item, iRow); } 00241 00242 template <typename U, bool bIsPointer /* = true */> 00243 struct insertItem_Helper 00244 { 00245 static inline bool insert(qx::IxModel * pModel, U & item, int iRow) 00246 { return (item ? qx::model_view::detail::QxNestedModel_Container<T, M>::insertItem(pModel, (* item), iRow) : true); } 00247 }; 00248 00249 template <typename U1, typename U2> 00250 struct insertItem_Helper<std::pair<U1, U2>, false> 00251 { 00252 static inline bool insert(qx::IxModel * pModel, std::pair<U1, U2> & item, int iRow) 00253 { return qx::model_view::detail::QxNestedModel_Container<T, M>::insertItem(pModel, item.second, iRow); } 00254 }; 00255 00256 template <typename U1, typename U2> 00257 struct insertItem_Helper<const std::pair<U1, U2>, false> 00258 { 00259 static inline bool insert(qx::IxModel * pModel, const std::pair<U1, U2> & item, int iRow) 00260 { return qx::model_view::detail::QxNestedModel_Container<T, M>::insertItem(pModel, item.second, iRow); } 00261 }; 00262 00263 #if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) 00264 template <typename U1, typename U2> 00265 struct insertItem_Helper<QPair<U1, U2>, false> 00266 { 00267 static inline bool insert(qx::IxModel * pModel, QPair<U1, U2> & item, int iRow) 00268 { return qx::model_view::detail::QxNestedModel_Container<T, M>::insertItem(pModel, item.second, iRow); } 00269 }; 00270 00271 template <typename U1, typename U2> 00272 struct insertItem_Helper<const QPair<U1, U2>, false> 00273 { 00274 static inline bool insert(qx::IxModel * pModel, const QPair<U1, U2> & item, int iRow) 00275 { return qx::model_view::detail::QxNestedModel_Container<T, M>::insertItem(pModel, item.second, iRow); } 00276 }; 00277 #endif // (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) 00278 00279 template <typename U> 00280 struct insertItem_Helper<U, false> 00281 { 00282 enum { is_same_type = std::is_same<qx::model_view::detail::QxNestedModel_Container<T, M>::type_data, U>::value }; 00283 static bool insert(qx::IxModel * pModel, U & item, int iRow) 00284 { static_assert(is_same_type, "is_same_type"); return qx::model_view::detail::QxNestedModel_Container<T, M>::insert(pModel, item, iRow); } 00285 }; 00286 00287 }; 00288 00289 template <class T, class M /* = void */> 00290 struct QxNestedModel_Ptr 00291 { 00292 00293 static inline qx::IxModel * create(qx::IxModel * pParent, const QModelIndex & idxParent, T & t) 00294 { return (t ? create_Helper(pParent, idxParent, (* t)) : create_NullHelper(pParent, idxParent)); } 00295 00296 static inline void synchronize(qx::IxModel * pModel, T & t) 00297 { if (! t) { qx::trait::construct_ptr<T>::get(t); }; if (t) { qx::model_view::sync_nested_model(pModel, (* t)); } } 00298 00299 private: 00300 00301 template <class U> 00302 static inline qx::IxModel * create_Helper(qx::IxModel * pParent, const QModelIndex & idxParent, U & u) 00303 { return qx::model_view::detail::QxNestedModel<U, M>::create(pParent, idxParent, u); } 00304 00305 static inline qx::IxModel * create_NullHelper(qx::IxModel * pParent, const QModelIndex & idxParent) 00306 { 00307 M * pModelType = NULL; Q_UNUSED(pModelType); 00308 T t; qx::trait::construct_ptr<T>::get(t); if (! t) { qAssert(false); return NULL; } 00309 qx::IxModel * pModel = qx::model_view::create_nested_model_with_type(pParent, idxParent, (* t), pModelType); 00310 if (pModel) { pModel->clear(); } qAssert(pModel != NULL); 00311 return pModel; 00312 } 00313 00314 }; 00315 00316 template <class T, class M /* = void */> 00317 struct QxNestedModel 00318 { 00319 00320 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; 00321 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; 00322 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; 00323 00324 static inline qx::IxModel * create(qx::IxModel * pParent, const QModelIndex & idxParent, T & t) 00325 { return type_model_view_3::create(pParent, idxParent, t); } 00326 00327 static inline void synchronize(qx::IxModel * pModel, T & t) 00328 { type_model_view_3::synchronize(pModel, t); } 00329 00330 }; 00331 00332 } // namespace detail 00333 } // namespace model_view 00334 } // namespace qx 00335 00336 namespace qx { 00337 namespace model_view { 00338 00346 template <class T> 00347 qx::IxModel * create_nested_model(qx::IxModel * pParent, const QModelIndex & idxParent, T & t) 00348 { return qx::model_view::detail::QxNestedModel<T, void>::create(pParent, idxParent, t); } 00349 00350 template <class T, class M> 00351 qx::IxModel * create_nested_model_with_type(qx::IxModel * pParent, const QModelIndex & idxParent, T & t, M * pModelType) 00352 { 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); } 00353 00354 template <class T> 00355 void sync_nested_model(qx::IxModel * pModel, T & t) 00356 { qx::model_view::detail::QxNestedModel<T, void>::synchronize(pModel, t); } 00357 00358 } // namespace model_view 00359 } // namespace qx 00360 00361 #endif // _QX_NESTED_MODEL_H_