QxOrm  1.5.0
C++ Object Relational Mapping library
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 
00369    virtual QSqlError qxInsert(const QStringList & relation = QStringList(), QSqlDatabase * pDatabase = NULL, bool bUseExecBatch = false)
00370    {
00371       if (relation.count() > 0) { this->syncAllNestedModel(relation); }
00372       if (relation.count() == 0) { this->m_lastError = qx::dao::insert(m_model, this->database(pDatabase), bUseExecBatch); }
00373       else { this->m_lastError = qx::dao::insert_with_relation(relation, m_model, this->database(pDatabase)); }
00374       if (! this->m_lastError.isValid()) { this->updateAllKeys(); }
00375       return this->m_lastError;
00376    }
00377 
00385    virtual QSqlError qxInsertRow(int row, const QStringList & relation = QStringList(), QSqlDatabase * pDatabase = NULL)
00386    {
00387       type_ptr pItem = getRowItemAt(row); if (! pItem) { return QSqlError(); }
00388       if (relation.count() > 0) { this->syncNestedModel(row, relation); }
00389       if (relation.count() == 0) { this->m_lastError = qx::dao::insert((* pItem), this->database(pDatabase)); }
00390       else { this->m_lastError = qx::dao::insert_with_relation(relation, (* pItem), this->database(pDatabase)); }
00391       if (! this->m_lastError.isValid()) { updateKey(row); }
00392       return this->m_lastError;
00393    }
00394 
00403    virtual QSqlError qxUpdate(const qx::QxSqlQuery & query = qx::QxSqlQuery(), const QStringList & relation = QStringList(), QSqlDatabase * pDatabase = NULL, bool bUseExecBatch = false)
00404    {
00405       if (relation.count() > 0) { this->syncAllNestedModel(relation); }
00406       if (relation.count() == 0) { this->m_lastError = qx::dao::update_by_query(query, m_model, this->database(pDatabase), this->m_lstColumns, bUseExecBatch); }
00407       else { this->m_lastError = qx::dao::update_by_query_with_relation(relation, query, m_model, this->database(pDatabase)); }
00408       if (! this->m_lastError.isValid()) { this->updateAllKeys(); }
00409       return this->m_lastError;
00410    }
00411 
00420    virtual QSqlError qxUpdateRow(int row, const qx::QxSqlQuery & query = qx::QxSqlQuery(), const QStringList & relation = QStringList(), QSqlDatabase * pDatabase = NULL)
00421    {
00422       if ((row < 0) || (row >= m_model.count())) { return QSqlError(); }
00423       if (relation.count() > 0) { this->syncNestedModel(row, relation); }
00424       type_ptr pItem = m_model.getByIndex(row); if (! pItem) { return QSqlError(); }
00425       if (relation.count() == 0) { this->m_lastError = qx::dao::update_by_query(query, (* pItem), this->database(pDatabase), this->m_lstColumns); }
00426       else { this->m_lastError = qx::dao::update_by_query_with_relation(relation, query, (* pItem), this->database(pDatabase)); }
00427       if (! this->m_lastError.isValid()) { updateKey(row); }
00428       return this->m_lastError;
00429    }
00430 
00437    virtual QSqlError qxSave(const QStringList & relation = QStringList(), QSqlDatabase * pDatabase = NULL)
00438    {
00439       if (relation.count() > 0) { this->syncAllNestedModel(relation); }
00440       if (relation.count() == 0) { this->m_lastError = qx::dao::save(m_model, this->database(pDatabase)); }
00441       else { this->m_lastError = qx::dao::save_with_relation(relation, m_model, this->database(pDatabase)); }
00442       if (! this->m_lastError.isValid()) { this->updateAllKeys(); }
00443       return this->m_lastError;
00444    }
00445 
00453    virtual QSqlError qxSaveRow(int row, const QStringList & relation = QStringList(), QSqlDatabase * pDatabase = NULL)
00454    {
00455       if ((row < 0) || (row >= m_model.count())) { return QSqlError(); }
00456       if (relation.count() > 0) { this->syncNestedModel(row, relation); }
00457       type_ptr pItem = m_model.getByIndex(row); if (! pItem) { return QSqlError(); }
00458       if (relation.count() == 0) { this->m_lastError = qx::dao::save((* pItem), this->database(pDatabase)); }
00459       else { this->m_lastError = qx::dao::save_with_relation(relation, (* pItem), this->database(pDatabase)); }
00460       if (! this->m_lastError.isValid()) { updateKey(row); }
00461       return this->m_lastError;
00462    }
00463 
00471    virtual QSqlError qxSaveRowData(int row, const QStringList & column = QStringList(), QSqlDatabase * pDatabase = NULL)
00472    {
00473       if (! this->m_pDataMemberId) { this->m_lastError = QSqlError("[QxOrm] problem with 'qxSaveRowData()' method : 'data member id not registered'", "", QSqlError::UnknownError); return this->m_lastError; }
00474       type_ptr pItem = getRowItemAt(row); if (! pItem) { return QSqlError(); }
00475       QVariant id = this->m_pDataMemberId->toVariant(pItem.get());
00476       bool bExist = qx::trait::is_valid_primary_key(id);
00477       if (bExist) { bExist = qx::dao::exist((* pItem), this->database(pDatabase)); }
00478       if (bExist) { this->m_lastError = qx::dao::update((* pItem), this->database(pDatabase), column); }
00479       else { this->m_lastError = qx::dao::insert((* pItem), this->database(pDatabase)); }
00480       return this->m_lastError;
00481    }
00482 
00489    virtual QSqlError qxDeleteById(const QVariant & id, QSqlDatabase * pDatabase = NULL)
00490    {
00491       type_ptr pItem = type_ptr(new T());
00492       if (! this->m_pDataMemberId) { qDebug("[QxOrm] problem with 'qxDeleteById()' method : '%s'", "data member id not registered"); qAssert(false); }
00493       if (! this->m_pDataMemberId) { this->m_lastError = QSqlError("[QxOrm] problem with 'qxDeleteById()' method : 'data member id not registered'", "", QSqlError::UnknownError); return this->m_lastError; }
00494       this->m_pDataMemberId->fromVariant(pItem.get(), id);
00495       this->m_lastError = qx::dao::delete_by_id((* pItem), this->database(pDatabase));
00496       return this->m_lastError;
00497    }
00498 
00504    virtual QSqlError qxDeleteAll(QSqlDatabase * pDatabase = NULL)
00505    {
00506       this->m_lastError = qx::dao::delete_all<T>(this->database(pDatabase));
00507       return this->m_lastError;
00508    }
00509 
00516    virtual QSqlError qxDeleteByQuery(const qx::QxSqlQuery & query, QSqlDatabase * pDatabase = NULL)
00517    {
00518       this->m_lastError = qx::dao::delete_by_query<T>(query, this->database(pDatabase));
00519       return this->m_lastError;
00520    }
00521 
00528    virtual QSqlError qxDeleteRow(int row, QSqlDatabase * pDatabase = NULL)
00529    {
00530       if ((row < 0) || (row >= m_model.count())) { return QSqlError(); }
00531       type_ptr pItem = m_model.getByIndex(row); if (! pItem) { return QSqlError(); }
00532       this->m_lastError = qx::dao::delete_by_id((* pItem), this->database(pDatabase));
00533       return this->m_lastError;
00534    }
00535 
00542    virtual QSqlError qxDestroyById(const QVariant & id, QSqlDatabase * pDatabase = NULL)
00543    {
00544       type_ptr pItem = type_ptr(new T());
00545       if (! this->m_pDataMemberId) { qDebug("[QxOrm] problem with 'qxDeleteById()' method : '%s'", "data member id not registered"); qAssert(false); }
00546       if (! this->m_pDataMemberId) { this->m_lastError = QSqlError("[QxOrm] problem with 'qxDeleteById()' method : 'data member id not registered'", "", QSqlError::UnknownError); return this->m_lastError; }
00547       this->m_pDataMemberId->fromVariant(pItem.get(), id);
00548       this->m_lastError = qx::dao::destroy_by_id((* pItem), this->database(pDatabase));
00549       return this->m_lastError;
00550    }
00551 
00557    virtual QSqlError qxDestroyAll(QSqlDatabase * pDatabase = NULL)
00558    {
00559       this->m_lastError = qx::dao::destroy_all<T>(this->database(pDatabase));
00560       return this->m_lastError;
00561    }
00562 
00569    virtual QSqlError qxDestroyByQuery(const qx::QxSqlQuery & query, QSqlDatabase * pDatabase = NULL)
00570    {
00571       this->m_lastError = qx::dao::destroy_by_query<T>(query, this->database(pDatabase));
00572       return this->m_lastError;
00573    }
00574 
00581    virtual QSqlError qxDestroyRow(int row, QSqlDatabase * pDatabase = NULL)
00582    {
00583       if ((row < 0) || (row >= m_model.count())) { return QSqlError(); }
00584       type_ptr pItem = m_model.getByIndex(row); if (! pItem) { return QSqlError(); }
00585       this->m_lastError = qx::dao::destroy_by_id((* pItem), this->database(pDatabase));
00586       return this->m_lastError;
00587    }
00588 
00589    virtual QSqlError qxExecuteQuery(qx::QxSqlQuery & query, QSqlDatabase * pDatabase = NULL)
00590    {
00591       this->clear();
00592       type_collection tmp;
00593       this->m_lastError = qx::dao::execute_query(query, tmp, this->database(pDatabase));
00594 
00595       if (tmp.count() <= 0) { return this->m_lastError; }
00596       this->beginResetModel();
00597       m_model = tmp;
00598       this->updateShowEmptyLine();
00599       this->endResetModel();
00600       return this->m_lastError;
00601    }
00602 
00603    virtual qx_bool qxExist(const QVariant & id, QSqlDatabase * pDatabase = NULL)
00604    {
00605       type_ptr pItem = type_ptr(new T());
00606       if (! this->m_pDataMemberId) { qDebug("[QxOrm] problem with 'qxExist()' method : '%s'", "data member id not registered"); qAssert(false); }
00607       if (! this->m_pDataMemberId) { return qx_bool(false); }
00608       this->m_pDataMemberId->fromVariant(pItem.get(), id);
00609       return qx::dao::exist((* pItem), this->database(pDatabase));
00610    }
00611 
00612    virtual qx::QxInvalidValueX qxValidate(const QStringList & groups = QStringList())
00613    {
00614       return qx::validate(m_model, groups);
00615    }
00616 
00617    virtual qx::QxInvalidValueX qxValidateRow(int row, const QStringList & groups = QStringList())
00618    {
00619       type_ptr pItem = getRowItemAt(row); if (! pItem) { return qx::QxInvalidValueX(); }
00620       return qx::validate((* pItem), groups);
00621    }
00622 
00623 protected:
00624 
00625    type_ptr getRowItemAt(int row) const
00626    {
00627       if ((row >= 0) && (row < m_model.count())) { return m_model.getByIndex(row); }
00628       if (m_pDirtyRow && (m_pDirtyRow->first == row)) { return m_pDirtyRow->second; }
00629       return type_ptr();
00630    }
00631 
00632    virtual void * getRowItemAsVoidPtr(int row) const { return getRowItemAt(row).get(); }
00633 
00634    virtual void dumpModelImpl(bool bJsonFormat) const { qx::dump(m_model, bJsonFormat); }
00635 
00636    virtual QObject * cloneModelImpl()
00637    {
00638       qx::QxModel<T, B> * pClone = new qx::QxModel<T, B>(this, NULL);
00639       std::shared_ptr<type_collection> pModel = qx::clone(pClone->m_model);
00640       if (pModel) { pClone->m_model = (* pModel); }
00641       return static_cast<QObject *>(pClone);
00642    }
00643 
00644    virtual void updateShowEmptyLine() { if (m_pDirtyRow) { m_pDirtyRow->first = m_model.count(); } }
00645 
00646    virtual bool isDirtyRow(int row) const { return (m_pDirtyRow && (m_pDirtyRow->first == row)); }
00647 
00648    virtual void insertDirtyRowToModel()
00649    {
00650       if (! m_pDirtyRow) { return; }
00651       int row = m_pDirtyRow->first;
00652       insertItem(row, m_pDirtyRow->second);
00653       if (this->m_pParent) { this->m_pParent->saveChildRelations(this); }
00654       updateKey(row);
00655       addDirtyRow();
00656    }
00657 
00658    void addDirtyRow()
00659    {
00660       this->beginInsertRows(QModelIndex(), m_model.count(), m_model.count());
00661       m_pDirtyRow.reset(new QPair<int, type_ptr>(m_model.count(), type_ptr(new T())));
00662       IxSqlRelation * pRelationParent = (this->m_pDataMemberRelationToParent ? this->m_pDataMemberRelationToParent->getSqlRelation() : NULL);
00663       IxSqlRelation::relation_type eRelationParentType = (pRelationParent ? pRelationParent->getRelationType() : IxSqlRelation::no_relation);
00664       if (this->m_pParent && ((eRelationParentType == IxSqlRelation::many_to_many) || (eRelationParentType == IxSqlRelation::many_to_one)))
00665       { this->m_pDataMemberRelationToParent->fromVariant(m_pDirtyRow->second.get(), this->m_pParent->getIdFromChild(this)); }
00666       this->endInsertRows();
00667    }
00668 
00669    void insertItem(int row, const type_ptr & pItem)
00670    {
00671       if (! pItem) { return; }
00672       type_primary_key primaryKey;
00673       this->m_lManualInsertIndex = (this->m_lManualInsertIndex - 1);
00674       QVariant vNewId(static_cast<qlonglong>(this->m_lManualInsertIndex));
00675       qx::cvt::from_variant(vNewId, primaryKey);
00676       m_model.insert(row, primaryKey, pItem);
00677       this->updateShowEmptyLine();
00678    }
00679 
00680    void updateKey(int row)
00681    {
00682       if ((row < 0) || (row >= m_model.count())) { return; }
00683       type_ptr pItem = m_model.getByIndex(row); if (! pItem || ! this->m_pDataMemberId) { return; }
00684       type_primary_key currPrimaryKey = m_model.getKeyByIndex(row);
00685       QVariant vCurrPrimaryKey = qx::cvt::to_variant(currPrimaryKey);
00686       QVariant vNextPrimaryKey = this->m_pDataMemberId->toVariant(pItem.get());
00687       if ((vCurrPrimaryKey == vNextPrimaryKey) || (! vNextPrimaryKey.isValid())) { return; }
00688       if (! qx::trait::is_valid_primary_key(vNextPrimaryKey)) { return; }
00689       type_primary_key updatedPrimaryKey;
00690       qx::cvt::from_variant(vNextPrimaryKey, updatedPrimaryKey);
00691       if (m_model.exist(updatedPrimaryKey)) { return; }
00692       m_model.removeByIndex(row);
00693       m_model.insert(row, updatedPrimaryKey, pItem);
00694    }
00695 
00696    void updateAllKeys()
00697    {
00698       for (long l = 0; l < m_model.count(); l++)
00699       { updateKey(l); }
00700    }
00701 
00702 protected:
00703 
00704 #ifndef _QX_NO_JSON
00705 
00706    virtual QString toJson_Helper(int row) const
00707    {
00708       if (row == -1) { return qx::serialization::json::to_string(m_model); }
00709       type_ptr pItem = getRowItemAt(row); if (! pItem) { return QString(); }
00710       return qx::serialization::json::to_string(* pItem);
00711    }
00712 
00713    virtual bool fromJson_Helper(const QString & json, int row)
00714    {
00715       if (row == -1)
00716       {
00717          this->clear();
00718          type_collection tmp;
00719          if (! qx::serialization::json::from_string(tmp, json)) { return false; }
00720          this->beginResetModel();
00721          m_model = tmp;
00722          this->updateShowEmptyLine();
00723          this->endResetModel();
00724          return true;
00725       }
00726 
00727       type_ptr pItem = getRowItemAt(row); if (! pItem) { return false; }
00728       if (! qx::serialization::json::from_string((* pItem), json)) { return false; }
00729 
00730       QModelIndex idxTopLeft = this->index(row, 0);
00731       QModelIndex idxBottomRight = this->index(row, (this->m_lstDataMember.count() - 1));
00732       this->raiseEvent_dataChanged(idxTopLeft, idxBottomRight);
00733       updateKey(row);
00734       return true;
00735    }
00736 
00737    virtual QVariant getRelationshipValues_Helper(int row, const QString & relation, bool bLoadFromDatabase, const QString & sAppendRelations)
00738    {
00739       if ((row < 0) || (row >= m_model.count())) { return QVariant(); }
00740       if (! this->m_pDataMemberId || ! this->m_pDataMemberX || ! this->m_pDataMemberX->exist(relation)) { return QVariant(); }
00741       IxDataMember * pDataMember = this->m_pDataMemberX->get_WithDaoStrategy(relation); if (! pDataMember) { return QVariant(); }
00742       IxSqlRelation * pRelation = (pDataMember->hasSqlRelation() ? pDataMember->getSqlRelation() : NULL); if (! pRelation) { return QVariant(); }
00743       type_ptr pItem = m_model.getByIndex(row); if (! pItem) { return QVariant(); }
00744       type_ptr pItemTemp = pItem;
00745 
00746       if (bLoadFromDatabase)
00747       {
00748          QString sRelation = relation;
00749          if (! sAppendRelations.isEmpty() && ! sAppendRelations.startsWith("->") && ! sAppendRelations.startsWith(">>")) { sRelation += "->" + sAppendRelations; }
00750          else if (! sAppendRelations.isEmpty()) { sRelation += sAppendRelations; }
00751          pItemTemp = type_ptr(new T());
00752          QVariant id = this->m_pDataMemberId->toVariant(pItem.get());
00753          this->m_pDataMemberId->fromVariant(pItemTemp.get(), id);
00754          QSqlError daoError = qx::dao::fetch_by_id_with_relation(sRelation, (* pItemTemp));
00755          if (daoError.isValid()) { return QVariant(); }
00756       }
00757 
00758       QJsonValue json = pDataMember->toJson(pItemTemp.get()); if (json.isNull()) { return QVariant(); }
00759       if (json.isArray()) { return json.toArray().toVariantList(); }
00760       return json.toObject().toVariantMap();
00761    }
00762 
00763    virtual bool setRelationshipValues_Helper(int row, const QString & relation, const QVariant & values)
00764    {
00765       if ((row < 0) || (row >= m_model.count())) { return false; }
00766       if ((values.type() != QVariant::List) && (values.type() != QVariant::Map)) { return false; }
00767       if (! this->m_pDataMemberId || ! this->m_pDataMemberX || ! this->m_pDataMemberX->exist(relation)) { return false; }
00768       IxDataMember * pDataMember = this->m_pDataMemberX->get_WithDaoStrategy(relation); if (! pDataMember) { return false; }
00769       IxSqlRelation * pRelation = (pDataMember->hasSqlRelation() ? pDataMember->getSqlRelation() : NULL); if (! pRelation) { return false; }
00770       type_ptr pItem = m_model.getByIndex(row); if (! pItem) { return false; }
00771 
00772       QJsonValue json;
00773       if (values.type() == QVariant::List) { json = QJsonArray::fromVariantList(values.toList()); }
00774       else if (values.type() == QVariant::Map) { json = QJsonObject::fromVariantMap(values.toMap()); }
00775       if (! pDataMember->fromJson(pItem.get(), json)) { return false; }
00776 
00777       QModelIndex idxTopLeft = this->index(row, 0);
00778       QModelIndex idxBottomRight = this->index(row, (this->m_lstDataMember.count() - 1));
00779       this->raiseEvent_dataChanged(idxTopLeft, idxBottomRight);
00780       return true;
00781    }
00782 
00783 #endif // _QX_NO_JSON
00784 
00785 };
00786 
00787 } // namespace qx
00788 
00789 #endif // _QX_MODEL_H_