| QxOrm 1.4.5 C++ Object Relational Mapping library

- Main Page
- Modules
- Namespaces
- Classes
- Files
- Directories

- File List
- File Members

QxModel.h
Go to the documentation of this file.

    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_MODEL_H_
    00033 #define _QX_MODEL_H_
    00034
    00035 #ifdef _MSC_VER
    00036 #pragma once
    00037 #endif
    00038
    00046 #include <QxModelView/IxModel.h>
    00047 #include <QxModelView/QxModelRowCompare.h>
    00048
    00049 #include <QxCollection/QxCollection.h>
    00050
    00051 #include <QxRegister/QxClass.h>
    00052
    00053 #include <QxTraits/get_primary_key.h>
    00054 #include <QxTraits/is_qx_registered.h>
    00055 #include <QxTraits/is_valid_primary_key.h>
    00056
    00057 #include <QxSerialize/QxDump.h>
    00058 #include <QxSerialize/QxClone.h>
    00059
    00060 #ifndef _QX_NO_JSON
    00061 #include <QxSerialize/QJson/QxSerializeQJson_QxCollection.h>
    00062 #include <QxSerialize/QxSerializeQJson.h>
    00063 #endif // _QX_NO_JSON
    00064
    00065 namespace qx {
    00066 namespace model_view {
    00067 namespace detail {
    00068
    00069 template <class T, class M> struct QxNestedModel;
    00070 template <class T, class M> struct QxNestedModel_Generic;
    00071 template <class T, class M> struct QxNestedModel_Container;
    00072
    00073 } // namespace detail
    00074 } // namespace model_view
    00075 } // namespace qx
    00076
    00077 namespace qx {
    00078
    00162 template <class T, class B = qx::IxModel>
    00163 class QxModel : public B // B type must inherit from qx::IxModel and must not define new data-members (use 'm_hCustomProperties' or QObject dynamic properties if you need new properties in your derived class)
    00164 {
    00165
    00166    template <typename U, typename V> friend struct qx::model_view::detail::QxNestedModel;
    00167    template <typename U, typename V> friend struct qx::model_view::detail::QxNestedModel_Generic;
    00168    template <typename U, typename V> friend struct qx::model_view::detail::QxNestedModel_Container;
    00169
    00170 public:
    00171
    00172    typedef std::shared_ptr<T> type_ptr;
    00173    typedef typename qx::trait::get_primary_key<T>::type type_primary_key;
    00174    typedef qx::QxCollection<type_primary_key, type_ptr> type_collection;
    00175    typedef B type_base_class;
    00176
    00177    enum { qx_is_valid = (qx::trait::is_qx_registered<T>::value && std::is_base_of<qx::IxModel, B>::value) };
    00178
    00179 protected:
    00180
    00181    type_collection m_model;
    00182    std::shared_ptr<QPair<int, type_ptr> > m_pDirtyRow;
    00183
    00184 public:
    00185
    00186    QxModel(QObject * parent = 0) : B(parent) { qx::QxModel<T, B>::init(); }
    00187    QxModel(qx::IxModel * other, QObject * parent) : B(parent) { qx::QxModel<T, B>::initFrom(other); }
    00188    virtual ~QxModel() { ; }
    00189
    00190 protected:
    00191
    00192    void init()
    00193    {
    00194       static_assert(qx_is_valid, "qx_is_valid");
    00195       this->m_pClass = qx::QxClass<T>::getSingleton(); qAssert(this->m_pClass != NULL);
    00196       this->m_pDataMemberX = (this->m_pClass ? this->m_pClass->getDataMemberX() : NULL); qAssert(this->m_pDataMemberX != NULL);
    00197       this->m_pDataMemberId = (this->m_pDataMemberX ? this->m_pDataMemberX->getId_WithDaoStrategy() : NULL);
    00198       this->m_pCollection = (& m_model);
    00199       this->generateRoleNames();
    00200    }
    00201
    00202    void initFrom(qx::IxModel * pOther)
    00203    {
    00204       init();
    00205       qx::QxModel<T, B> * pOtherWrk = static_cast<qx::QxModel<T, B> *>(pOther);
    00206       m_model = pOtherWrk->m_model;
    00207       this->m_lManualInsertIndex = pOtherWrk->m_lManualInsertIndex;
    00208       this->setParentModel(pOtherWrk->m_pParent);
    00209       if (this->m_pParent) { this->m_eAutoUpdateDatabase = this->m_pParent->getAutoUpdateDatabase(); }
    00210       this->m_hCustomProperties = pOtherWrk->m_hCustomProperties;
    00211    }
    00212
    00213 public:
    00214
    00215    virtual bool insertRows(int row, int count, const QModelIndex & parent = QModelIndex())
    00216    {
    00217       if (parent.isValid()) { return false; }
    00218       if ((row < 0) || (count <= 0)) { return false; }
    00219       this->beginInsertRows(QModelIndex(), row, (row + count - 1));
    00220       for (int i = 0; i < count; ++i)
    00221       {
    00222          type_ptr pItem = type_ptr(new T());
    00223          insertItem(row, pItem);
    00224       }
    00225       this->endInsertRows();
    00226       return true;
    00227    }
    00228
    00229    virtual void sort(int column, Qt::SortOrder order = Qt::AscendingOrder)
    00230    {
    00231       IxDataMember * pDataMember = this->getDataMember(column); if (! pDataMember) { return; }
    00232       m_model.sort(qx::model_view::QxModelRowCompare<typename type_collection::type_pair_key_value>((order == Qt::AscendingOrder), pDataMember));
    00233       this->raiseEvent_layoutChanged();
    00234    }
    00235
    00236    virtual bool getShowEmptyLine() const { return m_pDirtyRow.get(); }
    00237
    00238    virtual void setShowEmptyLine(bool b)
    00239    {
    00240       if (b == getShowEmptyLine()) { return; }
    00241       if (b) { addDirtyRow(); return; }
    00242       this->beginRemoveRows(QModelIndex(), this->rowCount(), this->rowCount());
    00243       m_pDirtyRow.reset();
    00244       this->endRemoveRows();
    00245    }
    00246
    00247 public:
    00248
    00254    virtual long qxCount(const qx::QxSqlQuery & query = qx::QxSqlQuery(), QSqlDatabase * pDatabase = NULL)
    00255    {
    00256       return qx::dao::count<T>(query, this->database(pDatabase));
    00257    }
    00258
    00265    virtual QSqlError qxCount(long & lCount, const qx::QxSqlQuery & query = qx::QxSqlQuery(), QSqlDatabase * pDatabase = NULL)
    00266    {
    00267       this->m_lastError = qx::dao::count<T>(lCount, query, this->database(pDatabase));
    00268       return this->m_lastError;
    00269    }
    00270
    00278    virtual QSqlError qxFetchById(const QVariant & id, const QStringList & relation = QStringList(), QSqlDatabase * pDatabase = NULL)
    00279    {
    00280       this->clear();
    00281       type_ptr pItem = type_ptr(new T());
    00282       if (! this->m_pDataMemberId) { qDebug("[QxOrm] problem with 'qxFetchById()' method : '%s'", "data member id not registered"); qAssert(false); }
    00283       if (! this->m_pDataMemberId) { this->m_lastError = QSqlError("[QxOrm] problem with 'qxFetchById()' method : 'data member id not registered'", "", QSqlError::UnknownError); return this->m_lastError; }
    00284       this->m_pDataMemberId->fromVariant(pItem.get(), id);
    00285
    00286       type_primary_key primaryKey;
    00287       qx::cvt::from_variant(id, primaryKey);
    00288       this->beginInsertRows(QModelIndex(), 0, 0);
    00289       m_model.insert(primaryKey, pItem);
    00290
    00291       if (relation.count() == 0) { this->m_lastError = qx::dao::fetch_by_id((* pItem), this->database(pDatabase), this->m_lstColumns); }
    00292       else { this->m_lastError = qx::dao::fetch_by_id_with_relation(relation, (* pItem), this->database(pDatabase)); }
    00293       this->updateShowEmptyLine();
    00294       this->endInsertRows();
    00295       return this->m_lastError;
    00296    }
    00297
    00304    virtual QSqlError qxFetchAll(const QStringList & relation = QStringList(), QSqlDatabase * pDatabase = NULL)
    00305    {
    00306       this->clear();
    00307       type_collection tmp;
    00308       if (relation.count() == 0) { this->m_lastError = qx::dao::fetch_all(tmp, this->database(pDatabase), this->m_lstColumns); }
    00309       else { this->m_lastError = qx::dao::fetch_all_with_relation(relation, tmp, this->database(pDatabase)); }
    00310
    00311       if (tmp.count() <= 0) { return this->m_lastError; }
    00312       this->beginResetModel();
    00313       m_model = tmp;
    00314       this->updateShowEmptyLine();
    00315       this->endResetModel();
    00316       return this->m_lastError;
    00317    }
    00318
    00326    virtual QSqlError qxFetchByQuery(const qx::QxSqlQuery & query, const QStringList & relation = QStringList(), QSqlDatabase * pDatabase = NULL)
    00327    {
    00328       this->clear();
    00329       type_collection tmp;
    00330       if (relation.count() == 0) { this->m_lastError = qx::dao::fetch_by_query(query, tmp, this->database(pDatabase), this->m_lstColumns); }
    00331       else { this->m_lastError = qx::dao::fetch_by_query_with_relation(relation, query, tmp, this->database(pDatabase)); }
    00332
    00333       if (tmp.count() <= 0) { return this->m_lastError; }
    00334       this->beginResetModel();
    00335       m_model = tmp;
    00336       this->updateShowEmptyLine();
    00337       this->endResetModel();
    00338       return this->m_lastError;
    00339    }
    00340
    00348    virtual QSqlError qxFetchRow(int row, const QStringList & relation = QStringList(), QSqlDatabase * pDatabase = NULL)
    00349    {
    00350       type_ptr pItem = getRowItemAt(row); if (! pItem) { return QSqlError(); }
    00351       if (relation.count() == 0) { this->m_lastError = qx::dao::fetch_by_id((* pItem), this->database(pDatabase), this->m_lstColumns); }
    00352       else { this->m_lastError = qx::dao::fetch_by_id_with_relation(relation, (* pItem), this->database(pDatabase)); }
    00353       if (this->m_lastError.isValid()) { return this->m_lastError; }
    00354
    00355       QModelIndex idxTopLeft = this->index(row, 0);
    00356       QModelIndex idxBottomRight = this->index(row, (this->m_lstDataMember.count() - 1));
    00357       this->raiseEvent_dataChanged(idxTopLeft, idxBottomRight);
    00358       updateKey(row);
    00359       return this->m_lastError;
    00360    }
    00361
    00368    virtual QSqlError qxInsert(const QStringList & relation = QStringList(), QSqlDatabase * pDatabase = NULL)
    00369    {
    00370       if (relation.count() > 0) { this->syncAllNestedModel(relation); }
    00371       if (relation.count() == 0) { this->m_lastError = qx::dao::insert(m_model, this->database(pDatabase)); }
    00372       else { this->m_lastError = qx::dao::insert_with_relation(relation, m_model, this->database(pDatabase)); }
    00373       if (! this->m_lastError.isValid()) { this->updateAllKeys(); }
    00374       return this->m_lastError;
    00375    }
    00376
    00384    virtual QSqlError qxInsertRow(int row, const QStringList & relation = QStringList(), QSqlDatabase * pDatabase = NULL)
    00385    {
    00386       type_ptr pItem = getRowItemAt(row); if (! pItem) { return QSqlError(); }
    00387       if (relation.count() > 0) { this->syncNestedModel(row, relation); }
    00388       if (relation.count() == 0) { this->m_lastError = qx::dao::insert((* pItem), this->database(pDatabase)); }
    00389       else { this->m_lastError = qx::dao::insert_with_relation(relation, (* pItem), this->database(pDatabase)); }
    00390       if (! this->m_lastError.isValid()) { updateKey(row); }
    00391       return this->m_lastError;
    00392    }
    00393
    00401    virtual QSqlError qxUpdate(const qx::QxSqlQuery & query = qx::QxSqlQuery(), const QStringList & relation = QStringList(), QSqlDatabase * pDatabase = NULL)
    00402    {
    00403       if (relation.count() > 0) { this->syncAllNestedModel(relation); }
    00404       if (relation.count() == 0) { this->m_lastError = qx::dao::update_by_query(query, m_model, this->database(pDatabase), this->m_lstColumns); }
    00405       else { this->m_lastError = qx::dao::update_by_query_with_relation(relation, query, m_model, this->database(pDatabase)); }
    00406       if (! this->m_lastError.isValid()) { this->updateAllKeys(); }
    00407       return this->m_lastError;
    00408    }
    00409
    00418    virtual QSqlError qxUpdateRow(int row, const qx::QxSqlQuery & query = qx::QxSqlQuery(), const QStringList & relation = QStringList(), QSqlDatabase * pDatabase = NULL)
    00419    {
    00420       if ((row < 0) || (row >= m_model.count())) { return QSqlError(); }
    00421       if (relation.count() > 0) { this->syncNestedModel(row, relation); }
    00422       type_ptr pItem = m_model.getByIndex(row); if (! pItem) { return QSqlError(); }
    00423       if (relation.count() == 0) { this->m_lastError = qx::dao::update_by_query(query, (* pItem), this->database(pDatabase), this->m_lstColumns); }
    00424       else { this->m_lastError = qx::dao::update_by_query_with_relation(relation, query, (* pItem), this->database(pDatabase)); }
    00425       if (! this->m_lastError.isValid()) { updateKey(row); }
    00426       return this->m_lastError;
    00427    }
    00428
    00435    virtual QSqlError qxSave(const QStringList & relation = QStringList(), QSqlDatabase * pDatabase = NULL)
    00436    {
    00437       if (relation.count() > 0) { this->syncAllNestedModel(relation); }
    00438       if (relation.count() == 0) { this->m_lastError = qx::dao::save(m_model, this->database(pDatabase)); }
    00439       else { this->m_lastError = qx::dao::save_with_relation(relation, m_model, this->database(pDatabase)); }
    00440       if (! this->m_lastError.isValid()) { this->updateAllKeys(); }
    00441       return this->m_lastError;
    00442    }
    00443
    00451    virtual QSqlError qxSaveRow(int row, const QStringList & relation = QStringList(), QSqlDatabase * pDatabase = NULL)
    00452    {
    00453       if ((row < 0) || (row >= m_model.count())) { return QSqlError(); }
    00454       if (relation.count() > 0) { this->syncNestedModel(row, relation); }
    00455       type_ptr pItem = m_model.getByIndex(row); if (! pItem) { return QSqlError(); }
    00456       if (relation.count() == 0) { this->m_lastError = qx::dao::save((* pItem), this->database(pDatabase)); }
    00457       else { this->m_lastError = qx::dao::save_with_relation(relation, (* pItem), this->database(pDatabase)); }
    00458       if (! this->m_lastError.isValid()) { updateKey(row); }
    00459       return this->m_lastError;
    00460    }
    00461
    00469    virtual QSqlError qxSaveRowData(int row, const QStringList & column = QStringList(), QSqlDatabase * pDatabase = NULL)
    00470    {
    00471       if (! this->m_pDataMemberId) { this->m_lastError = QSqlError("[QxOrm] problem with 'qxSaveRowData()' method : 'data member id not registered'", "", QSqlError::UnknownError); return this->m_lastError; }
    00472       type_ptr pItem = getRowItemAt(row); if (! pItem) { return QSqlError(); }
    00473       QVariant id = this->m_pDataMemberId->toVariant(pItem.get());
    00474       bool bExist = qx::trait::is_valid_primary_key(id);
    00475       if (bExist) { bExist = qx::dao::exist((* pItem), this->database(pDatabase)); }
    00476       if (bExist) { this->m_lastError = qx::dao::update((* pItem), this->database(pDatabase), column); }
    00477       else { this->m_lastError = qx::dao::insert((* pItem), this->database(pDatabase)); }
    00478       return this->m_lastError;
    00479    }
    00480
    00487    virtual QSqlError qxDeleteById(const QVariant & id, QSqlDatabase * pDatabase = NULL)
    00488    {
    00489       type_ptr pItem = type_ptr(new T());
    00490       if (! this->m_pDataMemberId) { qDebug("[QxOrm] problem with 'qxDeleteById()' method : '%s'", "data member id not registered"); qAssert(false); }
    00491       if (! this->m_pDataMemberId) { this->m_lastError = QSqlError("[QxOrm] problem with 'qxDeleteById()' method : 'data member id not registered'", "", QSqlError::UnknownError); return this->m_lastError; }
    00492       this->m_pDataMemberId->fromVariant(pItem.get(), id);
    00493       this->m_lastError = qx::dao::delete_by_id((* pItem), this->database(pDatabase));
    00494       return this->m_lastError;
    00495    }
    00496
    00502    virtual QSqlError qxDeleteAll(QSqlDatabase * pDatabase = NULL)
    00503    {
    00504       this->m_lastError = qx::dao::delete_all<T>(this->database(pDatabase));
    00505       return this->m_lastError;
    00506    }
    00507
    00514    virtual QSqlError qxDeleteByQuery(const qx::QxSqlQuery & query, QSqlDatabase * pDatabase = NULL)
    00515    {
    00516       this->m_lastError = qx::dao::delete_by_query<T>(query, this->database(pDatabase));
    00517       return this->m_lastError;
    00518    }
    00519
    00526    virtual QSqlError qxDeleteRow(int row, QSqlDatabase * pDatabase = NULL)
    00527    {
    00528       if ((row < 0) || (row >= m_model.count())) { return QSqlError(); }
    00529       type_ptr pItem = m_model.getByIndex(row); if (! pItem) { return QSqlError(); }
    00530       this->m_lastError = qx::dao::delete_by_id((* pItem), this->database(pDatabase));
    00531       return this->m_lastError;
    00532    }
    00533
    00540    virtual QSqlError qxDestroyById(const QVariant & id, QSqlDatabase * pDatabase = NULL)
    00541    {
    00542       type_ptr pItem = type_ptr(new T());
    00543       if (! this->m_pDataMemberId) { qDebug("[QxOrm] problem with 'qxDeleteById()' method : '%s'", "data member id not registered"); qAssert(false); }
    00544       if (! this->m_pDataMemberId) { this->m_lastError = QSqlError("[QxOrm] problem with 'qxDeleteById()' method : 'data member id not registered'", "", QSqlError::UnknownError); return this->m_lastError; }
    00545       this->m_pDataMemberId->fromVariant(pItem.get(), id);
    00546       this->m_lastError = qx::dao::destroy_by_id((* pItem), this->database(pDatabase));
    00547       return this->m_lastError;
    00548    }
    00549
    00555    virtual QSqlError qxDestroyAll(QSqlDatabase * pDatabase = NULL)
    00556    {
    00557       this->m_lastError = qx::dao::destroy_all<T>(this->database(pDatabase));
    00558       return this->m_lastError;
    00559    }
    00560
    00567    virtual QSqlError qxDestroyByQuery(const qx::QxSqlQuery & query, QSqlDatabase * pDatabase = NULL)
    00568    {
    00569       this->m_lastError = qx::dao::destroy_by_query<T>(query, this->database(pDatabase));
    00570       return this->m_lastError;
    00571    }
    00572
    00579    virtual QSqlError qxDestroyRow(int row, QSqlDatabase * pDatabase = NULL)
    00580    {
    00581       if ((row < 0) || (row >= m_model.count())) { return QSqlError(); }
    00582       type_ptr pItem = m_model.getByIndex(row); if (! pItem) { return QSqlError(); }
    00583       this->m_lastError = qx::dao::destroy_by_id((* pItem), this->database(pDatabase));
    00584       return this->m_lastError;
    00585    }
    00586
    00587    virtual QSqlError qxExecuteQuery(qx::QxSqlQuery & query, QSqlDatabase * pDatabase = NULL)
    00588    {
    00589       this->clear();
    00590       type_collection tmp;
    00591       this->m_lastError = qx::dao::execute_query(query, tmp, this->database(pDatabase));
    00592
    00593       if (tmp.count() <= 0) { return this->m_lastError; }
    00594       this->beginResetModel();
    00595       m_model = tmp;
    00596       this->updateShowEmptyLine();
    00597       this->endResetModel();
    00598       return this->m_lastError;
    00599    }
    00600
    00601    virtual qx_bool qxExist(const QVariant & id, QSqlDatabase * pDatabase = NULL)
    00602    {
    00603       type_ptr pItem = type_ptr(new T());
    00604       if (! this->m_pDataMemberId) { qDebug("[QxOrm] problem with 'qxExist()' method : '%s'", "data member id not registered"); qAssert(false); }
    00605       if (! this->m_pDataMemberId) { return qx_bool(false); }
    00606       this->m_pDataMemberId->fromVariant(pItem.get(), id);
    00607       return qx::dao::exist((* pItem), this->database(pDatabase));
    00608    }
    00609
    00610    virtual qx::QxInvalidValueX qxValidate(const QStringList & groups = QStringList())
    00611    {
    00612       return qx::validate(m_model, groups);
    00613    }
    00614
    00615    virtual qx::QxInvalidValueX qxValidateRow(int row, const QStringList & groups = QStringList())
    00616    {
    00617       type_ptr pItem = getRowItemAt(row); if (! pItem) { return qx::QxInvalidValueX(); }
    00618       return qx::validate((* pItem), groups);
    00619    }
    00620
    00621 protected:
    00622
    00623    type_ptr getRowItemAt(int row) const
    00624    {
    00625       if ((row >= 0) && (row < m_model.count())) { return m_model.getByIndex(row); }
    00626       if (m_pDirtyRow && (m_pDirtyRow->first == row)) { return m_pDirtyRow->second; }
    00627       return type_ptr();
    00628    }
    00629
    00630    virtual void * getRowItemAsVoidPtr(int row) const { return getRowItemAt(row).get(); }
    00631
    00632    virtual void dumpModelImpl(bool bJsonFormat) const { qx::dump(m_model, bJsonFormat); }
    00633
    00634    virtual QObject * cloneModelImpl()
    00635    {
    00636       qx::QxModel<T, B> * pClone = new qx::QxModel<T, B>(this, NULL);
    00637       std::shared_ptr<type_collection> pModel = qx::clone(pClone->m_model);
    00638       if (pModel) { pClone->m_model = (* pModel); }
    00639       return static_cast<QObject *>(pClone);
    00640    }
    00641
    00642    virtual void updateShowEmptyLine() { if (m_pDirtyRow) { m_pDirtyRow->first = m_model.count(); } }
    00643
    00644    virtual bool isDirtyRow(int row) const { return (m_pDirtyRow && (m_pDirtyRow->first == row)); }
    00645
    00646    virtual void insertDirtyRowToModel()
    00647    {
    00648       if (! m_pDirtyRow) { return; }
    00649       int row = m_pDirtyRow->first;
    00650       insertItem(row, m_pDirtyRow->second);
    00651       if (this->m_pParent) { this->m_pParent->saveChildRelations(this); }
    00652       updateKey(row);
    00653       addDirtyRow();
    00654    }
    00655
    00656    void addDirtyRow()
    00657    {
    00658       this->beginInsertRows(QModelIndex(), m_model.count(), m_model.count());
    00659       m_pDirtyRow.reset(new QPair<int, type_ptr>(m_model.count(), type_ptr(new T())));
    00660       IxSqlRelation * pRelationParent = (this->m_pDataMemberRelationToParent ? this->m_pDataMemberRelationToParent->getSqlRelation() : NULL);
    00661       IxSqlRelation::relation_type eRelationParentType = (pRelationParent ? pRelationParent->getRelationType() : IxSqlRelation::no_relation);
    00662       if (this->m_pParent && ((eRelationParentType == IxSqlRelation::many_to_many) || (eRelationParentType == IxSqlRelation::many_to_one)))
    00663       { this->m_pDataMemberRelationToParent->fromVariant(m_pDirtyRow->second.get(), this->m_pParent->getIdFromChild(this)); }
    00664       this->endInsertRows();
    00665    }
    00666
    00667    void insertItem(int row, const type_ptr & pItem)
    00668    {
    00669       if (! pItem) { return; }
    00670       type_primary_key primaryKey;
    00671       this->m_lManualInsertIndex = (this->m_lManualInsertIndex - 1);
    00672       QVariant vNewId(static_cast<qlonglong>(this->m_lManualInsertIndex));
    00673       qx::cvt::from_variant(vNewId, primaryKey);
    00674       m_model.insert(row, primaryKey, pItem);
    00675       this->updateShowEmptyLine();
    00676    }
    00677
    00678    void updateKey(int row)
    00679    {
    00680       if ((row < 0) || (row >= m_model.count())) { return; }
    00681       type_ptr pItem = m_model.getByIndex(row); if (! pItem || ! this->m_pDataMemberId) { return; }
    00682       type_primary_key currPrimaryKey = m_model.getKeyByIndex(row);
    00683       QVariant vCurrPrimaryKey = qx::cvt::to_variant(currPrimaryKey);
    00684       QVariant vNextPrimaryKey = this->m_pDataMemberId->toVariant(pItem.get());
    00685       if ((vCurrPrimaryKey == vNextPrimaryKey) || (! vNextPrimaryKey.isValid())) { return; }
    00686       if (! qx::trait::is_valid_primary_key(vNextPrimaryKey)) { return; }
    00687       type_primary_key updatedPrimaryKey;
    00688       qx::cvt::from_variant(vNextPrimaryKey, updatedPrimaryKey);
    00689       if (m_model.exist(updatedPrimaryKey)) { return; }
    00690       m_model.removeByIndex(row);
    00691       m_model.insert(row, updatedPrimaryKey, pItem);
    00692    }
    00693
    00694    void updateAllKeys()
    00695    {
    00696       for (long l = 0; l < m_model.count(); l++)
    00697       { updateKey(l); }
    00698    }
    00699
    00700 protected:
    00701
    00702 #ifndef _QX_NO_JSON
    00703
    00704    virtual QString toJson_Helper(int row) const
    00705    {
    00706       if (row == -1) { return qx::serialization::json::to_string(m_model); }
    00707       type_ptr pItem = getRowItemAt(row); if (! pItem) { return QString(); }
    00708       return qx::serialization::json::to_string(* pItem);
    00709    }
    00710
    00711    virtual bool fromJson_Helper(const QString & json, int row)
    00712    {
    00713       if (row == -1)
    00714       {
    00715          this->clear();
    00716          type_collection tmp;
    00717          if (! qx::serialization::json::from_string(tmp, json)) { return false; }
    00718          this->beginResetModel();
    00719          m_model = tmp;
    00720          this->updateShowEmptyLine();
    00721          this->endResetModel();
    00722          return true;
    00723       }
    00724
    00725       type_ptr pItem = getRowItemAt(row); if (! pItem) { return false; }
    00726       if (! qx::serialization::json::from_string((* pItem), json)) { return false; }
    00727
    00728       QModelIndex idxTopLeft = this->index(row, 0);
    00729       QModelIndex idxBottomRight = this->index(row, (this->m_lstDataMember.count() - 1));
    00730       this->raiseEvent_dataChanged(idxTopLeft, idxBottomRight);
    00731       updateKey(row);
    00732       return true;
    00733    }
    00734
    00735    virtual QVariant getRelationshipValues_Helper(int row, const QString & relation, bool bLoadFromDatabase, const QString & sAppendRelations)
    00736    {
    00737       if ((row < 0) || (row >= m_model.count())) { return QVariant(); }
    00738       if (! this->m_pDataMemberId || ! this->m_pDataMemberX || ! this->m_pDataMemberX->exist(relation)) { return QVariant(); }
    00739       IxDataMember * pDataMember = this->m_pDataMemberX->get_WithDaoStrategy(relation); if (! pDataMember) { return QVariant(); }
    00740       IxSqlRelation * pRelation = (pDataMember->hasSqlRelation() ? pDataMember->getSqlRelation() : NULL); if (! pRelation) { return QVariant(); }
    00741       type_ptr pItem = m_model.getByIndex(row); if (! pItem) { return QVariant(); }
    00742       type_ptr pItemTemp = pItem;
    00743
    00744       if (bLoadFromDatabase)
    00745       {
    00746          QString sRelation = relation;
    00747          if (! sAppendRelations.isEmpty() && ! sAppendRelations.startsWith("->") && ! sAppendRelations.startsWith(">>")) { sRelation += "->" + sAppendRelations; }
    00748          else if (! sAppendRelations.isEmpty()) { sRelation += sAppendRelations; }
    00749          pItemTemp = type_ptr(new T());
    00750          QVariant id = this->m_pDataMemberId->toVariant(pItem.get());
    00751          this->m_pDataMemberId->fromVariant(pItemTemp.get(), id);
    00752          QSqlError daoError = qx::dao::fetch_by_id_with_relation(sRelation, (* pItemTemp));
    00753          if (daoError.isValid()) { return QVariant(); }
    00754       }
    00755
    00756       QJsonValue json = pDataMember->toJson(pItemTemp.get()); if (json.isNull()) { return QVariant(); }
    00757       if (json.isArray()) { return json.toArray().toVariantList(); }
    00758       return json.toObject().toVariantMap();
    00759    }
    00760
    00761    virtual bool setRelationshipValues_Helper(int row, const QString & relation, const QVariant & values)
    00762    {
    00763       if ((row < 0) || (row >= m_model.count())) { return false; }
    00764       if ((values.type() != QVariant::List) && (values.type() != QVariant::Map)) { return false; }
    00765       if (! this->m_pDataMemberId || ! this->m_pDataMemberX || ! this->m_pDataMemberX->exist(relation)) { return false; }
    00766       IxDataMember * pDataMember = this->m_pDataMemberX->get_WithDaoStrategy(relation); if (! pDataMember) { return false; }
    00767       IxSqlRelation * pRelation = (pDataMember->hasSqlRelation() ? pDataMember->getSqlRelation() : NULL); if (! pRelation) { return false; }
    00768       type_ptr pItem = m_model.getByIndex(row); if (! pItem) { return false; }
    00769
    00770       QJsonValue json;
    00771       if (values.type() == QVariant::List) { json = QJsonArray::fromVariantList(values.toList()); }
    00772       else if (values.type() == QVariant::Map) { json = QJsonObject::fromVariantMap(values.toMap()); }
    00773       if (! pDataMember->fromJson(pItem.get(), json)) { return false; }
    00774
    00775       QModelIndex idxTopLeft = this->index(row, 0);
    00776       QModelIndex idxBottomRight = this->index(row, (this->m_lstDataMember.count() - 1));
    00777       this->raiseEvent_dataChanged(idxTopLeft, idxBottomRight);
    00778       return true;
    00779    }
    00780
    00781 #endif // _QX_NO_JSON
    00782
    00783 };
    00784
    00785 } // namespace qx
    00786
    00787 #endif // _QX_MODEL_H_