QxOrm  1.4.5
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 
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_