QxOrm  1.2.9
C++ Object Relational Mapping library
QxNestedModel.h
Go to the documentation of this file.
00001 /****************************************************************************
00002 **
00003 ** http://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 <boost/static_assert.hpp>
00047 #include <boost/mpl/if.hpp>
00048 #include <boost/mpl/logical.hpp>
00049 #include <boost/type_traits/is_pointer.hpp>
00050 #include <boost/type_traits/is_same.hpp>
00051 #include <boost/type_traits/is_base_of.hpp>
00052 
00053 #include <QxCommon/QxStringCvt.h>
00054 
00055 #include <QxCollection/QxCollection.h>
00056 
00057 #include <QxTraits/is_qx_registered.h>
00058 #include <QxTraits/is_container.h>
00059 #include <QxTraits/is_smart_ptr.h>
00060 #include <QxTraits/get_base_class.h>
00061 #include <QxTraits/get_class_name_primitive.h>
00062 #include <QxTraits/construct_ptr.h>
00063 #include <QxTraits/generic_container.h>
00064 #include <QxTraits/is_valid_primary_key.h>
00065 
00066 #include <QxModelView/IxModel.h>
00067 #include <QxModelView/QxModel.h>
00068 
00069 namespace qx {
00070 namespace model_view {
00071 
00072 template <class T>
00073 qx::IxModel * create_nested_model(qx::IxModel * pParent, const QModelIndex & idxParent, T & t);
00074 
00075 } // namespace model_view
00076 } // namespace qx
00077 
00078 namespace qx {
00079 namespace model_view {
00080 namespace detail {
00081 
00082 template <class T>
00083 struct QxNestedModel;
00084 
00085 template <class T>
00086 struct QxNestedModel_Generic
00087 {
00088 
00089    enum { is_valid = qx::trait::is_qx_registered<T>::value };
00090 
00091    static inline qx::IxModel * create(qx::IxModel * pParent, const QModelIndex & idxParent, T & t)
00092    {
00093       typedef typename qx::QxModel<T>::type_collection type_collection;
00094       typedef typename qx::QxModel<T>::type_primary_key type_primary_key;
00095       typedef typename qx::QxModel<T>::type_ptr type_ptr;
00096 
00097       BOOST_STATIC_ASSERT(is_valid);
00098       qx::QxModel<T> * pModel = new qx::QxModel<T>(pParent);
00099       pModel->setParentModel(pParent);
00100       type_collection & model = pModel->m_model;
00101       long & idx = pModel->m_lManualInsertIndex;
00102       type_primary_key key;
00103       type_ptr ptr;
00104 
00105       pModel->beginInsertRows(idxParent, 0, 0);
00106       ptr = type_ptr(new T());
00107       (* ptr) = t;
00108       qx::IxDataMember * pDataMemberId = pModel->m_pDataMemberId;
00109       if (! pDataMemberId) { qAssert(false); pModel->endInsertRows(); return pModel; }
00110       QVariant value = pDataMemberId->toVariant(& t);
00111       if (! qx::trait::is_valid_primary_key(value))
00112       { idx--; value = QVariant(static_cast<qlonglong>(idx)); }
00113       qx::cvt::from_variant(value, key);
00114       model.insert(0, key, ptr);
00115       pModel->endInsertRows();
00116       return pModel;
00117    }
00118 
00119 };
00120 
00121 template <class T>
00122 struct QxNestedModel_Container
00123 {
00124 
00125    typedef qx::trait::generic_container<T> type_generic_container;
00126    typedef typename type_generic_container::type_value_qx type_data;
00127 
00128    enum { is_valid = qx::trait::is_qx_registered<type_data>::value };
00129 
00130    static inline qx::IxModel * create(qx::IxModel * pParent, const QModelIndex & idxParent, T & t)
00131    {
00132       int iCurrRow = 0;
00133       BOOST_STATIC_ASSERT(is_valid);
00134       qx::QxModel<type_data> * pModel = new qx::QxModel<type_data>(pParent);
00135       pModel->setParentModel(pParent);
00136       long lCount = static_cast<long>(qx::trait::generic_container<T>::size(t));
00137       if (lCount <= 0) { return pModel; }
00138 
00139       pModel->beginInsertRows(idxParent, 0, (lCount - 1));
00140       for (typename T::iterator it = t.begin(); it != t.end(); ++it)
00141       { insertItem(pModel, (* it), iCurrRow); iCurrRow++; }
00142       pModel->endInsertRows();
00143       return pModel;
00144    }
00145 
00146    template <typename U>
00147    static inline bool insert(qx::IxModel * pModel, U & item, int iRow)
00148    {
00149       typedef typename qx::QxModel<U>::type_collection type_collection;
00150       typedef typename qx::QxModel<U>::type_primary_key type_primary_key;
00151       typedef typename qx::QxModel<U>::type_ptr type_ptr;
00152 
00153       if (! pModel) { qAssert(false); return false; }
00154       qx::QxModel<U> * pModelWrk = static_cast<qx::QxModel<U> *>(pModel);
00155       type_collection & model = pModelWrk->m_model;
00156       long & idx = pModelWrk->m_lManualInsertIndex;
00157       type_primary_key key;
00158       type_ptr ptr;
00159 
00160       ptr = type_ptr(new U());
00161       (* ptr) = item;
00162       qx::IxDataMember * pDataMemberId = pModelWrk->m_pDataMemberId;
00163       if (! pDataMemberId) { qAssert(false); return false; }
00164       QVariant value = pDataMemberId->toVariant(& item);
00165       if (! qx::trait::is_valid_primary_key(value))
00166       { idx--; value = QVariant(static_cast<qlonglong>(idx)); }
00167       qx::cvt::from_variant(value, key);
00168       model.insert(iRow, key, ptr);
00169       return true;
00170    }
00171 
00172 private:
00173 
00174    template <typename U>
00175    static inline bool insertItem(qx::IxModel * pModel, U & item, int iRow)
00176    { return insertItem_Helper<U, boost::is_pointer<U>::value || qx::trait::is_smart_ptr<U>::value>::insert(pModel, item, iRow); }
00177 
00178    template <typename U, bool bIsPointer /* = true */>
00179    struct insertItem_Helper
00180    {
00181       static inline bool insert(qx::IxModel * pModel, U & item, int iRow)
00182       { return (item ? qx::model_view::detail::QxNestedModel_Container<T>::insertItem(pModel, (* item), iRow) : true); }
00183    };
00184 
00185    template <typename U1, typename U2>
00186    struct insertItem_Helper<std::pair<U1, U2>, false>
00187    {
00188       static inline bool insert(qx::IxModel * pModel, std::pair<U1, U2> & item, int iRow)
00189       { return qx::model_view::detail::QxNestedModel_Container<T>::insertItem(pModel, item.second, iRow); }
00190    };
00191 
00192    template <typename U1, typename U2>
00193    struct insertItem_Helper<const std::pair<U1, U2>, false>
00194    {
00195       static inline bool insert(qx::IxModel * pModel, const std::pair<U1, U2> & item, int iRow)
00196       { return qx::model_view::detail::QxNestedModel_Container<T>::insertItem(pModel, item.second, iRow); }
00197    };
00198 
00199    template <typename U1, typename U2>
00200    struct insertItem_Helper<QPair<U1, U2>, false>
00201    {
00202       static inline bool insert(qx::IxModel * pModel, QPair<U1, U2> & item, int iRow)
00203       { return qx::model_view::detail::QxNestedModel_Container<T>::insertItem(pModel, item.second, iRow); }
00204    };
00205 
00206    template <typename U1, typename U2>
00207    struct insertItem_Helper<const QPair<U1, U2>, false>
00208    {
00209       static inline bool insert(qx::IxModel * pModel, const QPair<U1, U2> & item, int iRow)
00210       { return qx::model_view::detail::QxNestedModel_Container<T>::insertItem(pModel, item.second, iRow); }
00211    };
00212 
00213    template <typename U>
00214    struct insertItem_Helper<U, false>
00215    {
00216       enum { is_same_type = boost::is_same<qx::model_view::detail::QxNestedModel_Container<T>::type_data, U>::value };
00217       static bool insert(qx::IxModel * pModel, U & item, int iRow)
00218       { BOOST_STATIC_ASSERT(is_same_type); return qx::model_view::detail::QxNestedModel_Container<T>::insert(pModel, item, iRow); }
00219    };
00220 
00221 };
00222 
00223 template <class T>
00224 struct QxNestedModel_Ptr
00225 {
00226 
00227    static inline qx::IxModel * create(qx::IxModel * pParent, const QModelIndex & idxParent, T & t)
00228    { return (t ? create_Helper(pParent, idxParent, (* t)) : create_NullHelper(pParent, idxParent)); }
00229 
00230 private:
00231 
00232    template <class U>
00233    static inline qx::IxModel * create_Helper(qx::IxModel * pParent, const QModelIndex & idxParent, U & u)
00234    { return qx::model_view::detail::QxNestedModel<U>::create(pParent, idxParent, u); }
00235 
00236    static inline qx::IxModel * create_NullHelper(qx::IxModel * pParent, const QModelIndex & idxParent)
00237    {
00238       T t; qx::trait::construct_ptr<T>::get(t);
00239       if (! t) { qAssert(false); return NULL; }
00240       qx::IxModel * pModel = qx::model_view::create_nested_model(pParent, idxParent, (* t));
00241       if (pModel) { pModel->clear(); } qAssert(pModel != NULL);
00242       return pModel;
00243    }
00244 
00245 };
00246 
00247 template <class T>
00248 struct QxNestedModel
00249 {
00250 
00251    static inline qx::IxModel * create(qx::IxModel * pParent, const QModelIndex & idxParent, T & t)
00252    {
00253       typedef typename boost::mpl::if_c< boost::is_pointer<T>::value, qx::model_view::detail::QxNestedModel_Ptr<T>, qx::model_view::detail::QxNestedModel_Generic<T> >::type type_model_view_1;
00254       typedef typename boost::mpl::if_c< qx::trait::is_smart_ptr<T>::value, qx::model_view::detail::QxNestedModel_Ptr<T>, type_model_view_1 >::type type_model_view_2;
00255       typedef typename boost::mpl::if_c< qx::trait::is_container<T>::value, qx::model_view::detail::QxNestedModel_Container<T>, type_model_view_2 >::type type_model_view_3;
00256 
00257       return type_model_view_3::create(pParent, idxParent, t);
00258    }
00259 
00260 };
00261 
00262 } // namespace detail
00263 } // namespace model_view
00264 } // namespace qx
00265 
00266 namespace qx {
00267 namespace model_view {
00268 
00276 template <class T>
00277 qx::IxModel * create_nested_model(qx::IxModel * pParent, const QModelIndex & idxParent, T & t)
00278 { return qx::model_view::detail::QxNestedModel<T>::create(pParent, idxParent, t); }
00279 
00280 template <class T, class U>
00281 qx::IxModel * create_nested_model_with_type(qx::IxModel * pParent, const QModelIndex & idxParent, T & t, U * dummy)
00282 {
00283    Q_UNUSED(dummy);
00284    BOOST_STATIC_ASSERT((boost::is_base_of<qx::IxModel, U>::value));
00285    qx::IxModel * pModel = qx::model_view::create_nested_model(pParent, idxParent, t);
00286    if (! pModel) { return NULL; }
00287    U * pOther = new U(pModel, pParent);
00288    delete pModel;
00289    return pOther;
00290 }
00291 
00292 } // namespace model_view
00293 } // namespace qx
00294 
00295 #endif // _QX_NESTED_MODEL_H_