/****************************************************************************
**
** https://www.qxorm.com/
** Copyright (C) 2013 XDL Team (ic-east.com)
**
** This file is part of the QxOrm library
**
** This software is provided 'as-is', without any express or implied
** warranty. In no event will the authors be held liable for any
** damages arising from the use of this software
**
** Commercial Usage
** Licensees holding valid commercial QxOrm licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and XDL Team
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3.0 as published by the Free Software
** Foundation and appearing in the file 'license.gpl3.txt' included in the
** packaging of this file. Please review the following information to
** ensure the GNU General Public License version 3.0 requirements will be
** met : http://www.gnu.org/copyleft/gpl.html
**
** If you are unsure which license is appropriate for your use, or
** if you have questions regarding the use of this file, please contact :
** ic-east.com
**
****************************************************************************/

#include <QxPrecompiled.h>

#include <QxModelView/IxModel.h>

#include <QxMemLeak/mem_leak.h>

#define QX_CONSTRUCT_IX_MODEL()                                                                           \
   m_pClass(NULL), m_pModelClass(NULL), m_pDataMemberX(NULL), m_pDataMemberId(NULL), m_pCollection(NULL), \
       m_pParent(NULL), m_eAutoUpdateDatabase(IxModel::e_no_auto_update), m_pDataMemberRelationToParent(NULL), m_lManualInsertIndex(0)

namespace qx
{

   IxModel::IxModel(QObject *parent /* = 0 */) : QAbstractItemModel(parent), QX_CONSTRUCT_IX_MODEL() { ; }

   IxModel::~IxModel() { ; }

   IxClass *IxModel::getClass() const { return m_pClass; }

   IxClass *IxModel::getModelClass() const { return m_pModelClass; }

   IxCollection *IxModel::getCollection() const { return m_pCollection; }

   QSqlDatabase IxModel::getDatabase() const { return m_database; }

   QSqlError IxModel::getLastError() const { return m_lastError; }

   QString IxModel::getLastErrorAsString() const { return (m_lastError.isValid() ? m_lastError.text() : QString()); }

   QStringList IxModel::getListOfColumns() const { return m_lstColumns; }

   int IxModel::getRowCount() const { return rowCount(); }

   QHash<QString, QString> IxModel::getListOfHeaders() const
   {
      QHash<QString, QString> lst;
      QHashIterator<QString, QVariant> itr(m_lstHeadersData);
      QString sStart = (QString::number(Qt::DisplayRole) + "|");
      while (itr.hasNext())
      {
         itr.next();
         if (itr.key().startsWith(sStart))
         {
            QString sKey = itr.key();
            sKey.replace(sStart, "");
            lst.insert(sKey, itr.value().toString());
         }
      }
      return lst;
   }

   IxDataMember *IxModel::getDataMember(int column) const { return (((column < 0) || (column >= m_lstDataMember.count())) ? NULL : m_lstDataMember.at(column)); }

   QString IxModel::getDataMemberKey(int column) const
   {
      IxDataMember *p = getDataMember(column);
      return (p ? p->getKey() : QString());
   }

   QVariant IxModel::getModelValue(int row, const QString &column) const
   {
      if (!m_lstDataMemberByKey.contains(column))
      {
         return QVariant();
      }
      int iColumnIndex = m_lstDataMemberByKey.value(column);
      QModelIndex idx = index(row, iColumnIndex, QModelIndex());
      return data(idx, Qt::DisplayRole);
   }

   int IxModel::getColumnIndex(const QString &sColumnName) const
   {
      if (!m_lstDataMemberByKey.contains(sColumnName))
      {
         qAssert(false);
         return -1;
      }
      return m_lstDataMemberByKey.value(sColumnName);
   }

   int IxModel::getAutoUpdateDatabase_() const { return static_cast<int>(m_eAutoUpdateDatabase); }

   IxModel::e_auto_update_database IxModel::getAutoUpdateDatabase() const { return m_eAutoUpdateDatabase; }

   QVariant IxModel::getCustomProperty(const QString &key) const { return (m_hCustomProperties.contains(key) ? m_hCustomProperties.value(key) : QVariant()); }

   QObject *IxModel::getParentModel() const { return static_cast<QObject *>(m_pParent); }

   void IxModel::dumpModel(bool bJsonFormat /* = true */) const { dumpModelImpl(bJsonFormat); }

   QObject *IxModel::cloneModel() { return cloneModelImpl(); }

   void IxModel::setDatabase(const QSqlDatabase &db) { m_database = db; }

   void IxModel::setListOfColumns(const QStringList &lst)
   {
      m_lstColumns = lst;
      clear(true);
   }

   void IxModel::setListOfHeaders(const QHash<QString, QString> &lst)
   {
      QHashIterator<QString, QString> itr(lst);
      while (itr.hasNext())
      {
         itr.next();
         QString sHeaderDataKey = (QString::number(Qt::DisplayRole) + "|" + itr.key());
         QVariant vHeaderDataValue = QVariant(itr.value());
         m_lstHeadersData.insert(sHeaderDataKey, vHeaderDataValue);
      }
      Q_EMIT headerDataChanged(Qt::Horizontal, 0, (m_lstDataMember.count() - 1));
   }

   bool IxModel::setModelValue(int row, const QString &column, const QVariant &value)
   {
      if (!m_lstDataMemberByKey.contains(column))
      {
         return false;
      }
      int iColumnIndex = m_lstDataMemberByKey.value(column);
      QModelIndex idx = index(row, iColumnIndex, QModelIndex());
      return setData(idx, value, Qt::EditRole);
   }

   void IxModel::setParentModel(IxModel *pParent)
   {
      m_pParent = pParent;
      m_pDataMemberRelationToParent = NULL;
      if (!pParent || !m_pDataMemberX)
      {
         return;
      }
      long lCount = m_pDataMemberX->count_WithDaoStrategy();
      for (long l = 0; l < lCount; l++)
      {
         IxDataMember *p = m_pDataMemberX->get_WithDaoStrategy(l);
         if (!p)
         {
            continue;
         }
         IxSqlRelation *pRelation = p->getSqlRelation();
         if (!pRelation)
         {
            continue;
         }
         pRelation->init();
         if (pRelation->getDataId() == pParent->m_pDataMemberId)
         {
            m_pDataMemberRelationToParent = p;
            break;
         }
      }
   }

   void IxModel::setAutoUpdateDatabase_(int i) { m_eAutoUpdateDatabase = static_cast<IxModel::e_auto_update_database>(i); }

   void IxModel::setAutoUpdateDatabase(IxModel::e_auto_update_database e) { m_eAutoUpdateDatabase = e; }

   void IxModel::setCustomProperty(const QString &key, const QVariant &val) { m_hCustomProperties.insert(key, val); }

   int IxModel::qxCount_(const QString &sQuery)
   {
      qx_query query(sQuery);
      return static_cast<int>(qxCount(query, database(NULL)));
   }

   bool IxModel::qxFetchById_(const QVariant &id, const QStringList &relation /* = QStringList() */) { return (!qxFetchById(id, relation, database(NULL)).isValid()); }

   bool IxModel::qxFetchAll_(const QStringList &relation /* = QStringList() */) { return (!qxFetchAll(relation, database(NULL)).isValid()); }

   bool IxModel::qxFetchByQuery_(const QString &sQuery, const QStringList &relation /* = QStringList() */)
   {
      qx_query query(sQuery);
      return (!qxFetchByQuery(query, relation, database(NULL)).isValid());
   }

   bool IxModel::qxFetchRow_(int row, const QStringList &relation /* = QStringList() */) { return (!qxFetchRow(row, relation, database(NULL)).isValid()); }

   bool IxModel::qxInsert_(const QStringList &relation /* = QStringList() */, bool bUseExecBatch /* = false */) { return (!qxInsert(relation, database(NULL), bUseExecBatch).isValid()); }

   bool IxModel::qxInsertRow_(int row, const QStringList &relation /* = QStringList() */) { return (!qxInsertRow(row, relation, database(NULL)).isValid()); }

   bool IxModel::qxUpdate_(const QString &sQuery, const QStringList &relation /* = QStringList() */, bool bUseExecBatch /* = false */)
   {
      qx_query query(sQuery);
      return (!qxUpdate(query, relation, database(NULL), bUseExecBatch).isValid());
   }

   bool IxModel::qxUpdateRow_(int row, const QString &sQuery, const QStringList &relation /* = QStringList() */)
   {
      qx_query query(sQuery);
      return (!qxUpdateRow(row, query, relation, database(NULL)).isValid());
   }

   bool IxModel::qxSave_(const QStringList &relation /* = QStringList() */) { return (!qxSave(relation, database(NULL)).isValid()); }

   bool IxModel::qxSaveRow_(int row, const QStringList &relation /* = QStringList() */) { return (!qxSaveRow(row, relation, database(NULL)).isValid()); }

   bool IxModel::qxDeleteById_(const QVariant &id) { return (!qxDeleteById(id, database(NULL)).isValid()); }

   bool IxModel::qxDeleteAll_() { return (!qxDeleteAll(database(NULL)).isValid()); }

   bool IxModel::qxDeleteByQuery_(const QString &sQuery)
   {
      qx_query query(sQuery);
      return (!qxDeleteByQuery(query, database(NULL)).isValid());
   }

   bool IxModel::qxDeleteRow_(int row) { return (!qxDeleteRow(row, database(NULL)).isValid()); }

   bool IxModel::qxDestroyById_(const QVariant &id) { return (!qxDestroyById(id, database(NULL)).isValid()); }

   bool IxModel::qxDestroyAll_() { return (!qxDestroyAll(database(NULL)).isValid()); }

   bool IxModel::qxDestroyByQuery_(const QString &sQuery)
   {
      qx_query query(sQuery);
      return (!qxDestroyByQuery(query, database(NULL)).isValid());
   }

   bool IxModel::qxDestroyRow_(int row) { return (!qxDestroyRow(row, database(NULL)).isValid()); }

   bool IxModel::qxExecuteQuery_(const QString &sQuery)
   {
      qx_query query(sQuery);
      return (!qxExecuteQuery(query, database(NULL)).isValid());
   }

   bool IxModel::qxExist_(const QVariant &id) { return qxExist(id, database(NULL)).getValue(); }

   QString IxModel::qxValidate_(const QStringList &groups /* = QStringList() */)
   {
      qx::QxInvalidValueX invalidValueX = qxValidate(groups);
      return (invalidValueX ? QString() : invalidValueX.text());
   }

   QString IxModel::qxValidateRow_(int row, const QStringList &groups /* = QStringList() */)
   {
      qx::QxInvalidValueX invalidValueX = qxValidateRow(row, groups);
      return (invalidValueX ? QString() : invalidValueX.text());
   }

   void IxModel::raiseEvent_headerDataChanged(Qt::Orientation orientation, int first, int last) { Q_EMIT headerDataChanged(orientation, first, last); }

#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))

   void IxModel::raiseEvent_dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector<int> &roles /* = QVector<int>() */) { Q_EMIT dataChanged(topLeft, bottomRight, roles); }

   void IxModel::raiseEvent_layoutAboutToBeChanged(const QList<QPersistentModelIndex> &parents /* = QList<QPersistentModelIndex>() */, QAbstractItemModel::LayoutChangeHint hint /* = QAbstractItemModel::NoLayoutChangeHint */) { Q_EMIT layoutAboutToBeChanged(parents, hint); }

   void IxModel::raiseEvent_layoutChanged(const QList<QPersistentModelIndex> &parents /* = QList<QPersistentModelIndex>() */, QAbstractItemModel::LayoutChangeHint hint /* = QAbstractItemModel::NoLayoutChangeHint */) { Q_EMIT layoutChanged(parents, hint); }

#else // (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))

   void IxModel::raiseEvent_dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight) { Q_EMIT dataChanged(topLeft, bottomRight); }

   void IxModel::raiseEvent_layoutAboutToBeChanged() { Q_EMIT layoutAboutToBeChanged(); }

   void IxModel::raiseEvent_layoutChanged() { Q_EMIT layoutChanged(); }

#endif // (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))

   void IxModel::clear(bool bUpdateColumns /* = false */)
   {
      if (!m_pCollection)
      {
         qAssert(false);
         return;
      }
      if (!bUpdateColumns && (m_pCollection->_count() <= 0))
      {
         return;
      }
      beginResetModel();
      m_pCollection->_clear();
      for (long l = (m_lstChild.count() - 1); l >= 0; l--)
      {
         removeListOfChild(l);
      }
      m_lstChild.clear();
      m_hChild.clear();
      if (bUpdateColumns)
      {
         generateRoleNames();
      }
      endResetModel();

      if (getShowEmptyLine())
      {
         setShowEmptyLine(false);
         setShowEmptyLine(true);
      }
   }

   IxModel *IxModel::getChild(long row, const QString &relation)
   {
      if ((row < 0) || (row >= m_lstChild.count()))
      {
         return NULL;
      }
      IxModel::type_relation_by_name child = m_lstChild.at(row);
      if (!child.contains(relation))
      {
         return NULL;
      }
      return child.value(relation);
   }

   void IxModel::insertChild(long row, const QString &relation, IxModel *pChild)
   {
      if ((row < 0) || (!pChild))
      {
         return;
      }
      if (relation.isEmpty())
      {
         return;
      }
      while (row > (m_lstChild.count() - 1))
      {
         IxModel::type_relation_by_name tmp;
         m_lstChild.append(tmp);
      }
      m_lstChild[row].insert(relation, pChild);
      QPair<int, QString> pairRowRelation(static_cast<int>(row), relation);
      m_hChild.insert(pChild, pairRowRelation);
   }

   void IxModel::removeListOfChild(long row)
   {
      if ((row < 0) || (row >= m_lstChild.count()))
      {
         return;
      }
      IxModel::type_relation_by_name lst = m_lstChild.at(row);
      Q_FOREACH (IxModel *p, lst)
      {
         if (p)
         {
            m_hChild.remove(p);
            delete p;
         }
      }
      m_lstChild.removeAt(row);
   }

   QSqlError IxModel::saveChildRelations(IxModel *pChild)
   {
      if (!m_hChild.contains(pChild))
      {
         return QSqlError();
      }
      QPair<int, QString> pairRowRelation = m_hChild.value(pChild);
      return qxSaveRow(pairRowRelation.first, (QStringList() << pairRowRelation.second));
   }

   QVariant IxModel::getIdFromChild(IxModel *pChild) const
   {
      if (!m_hChild.contains(pChild))
      {
         return QVariant();
      }
      if (!m_pCollection || !m_pDataMemberId)
      {
         qAssert(false);
         return QVariant();
      }
      int row = m_hChild.value(pChild).first;
      if ((row < 0) || (row >= m_pCollection->_count()))
      {
         return QVariant();
      }
      void *pItem = getRowItemAsVoidPtr(row);
      return (pItem ? m_pDataMemberId->toVariant(pItem) : QVariant());
   }

   QPair<int, QString> IxModel::getChildPosition(IxModel *pChild) const
   {
      if (!m_hChild.contains(pChild))
      {
         return QPair<int, QString>(-1, "");
      }
      return m_hChild.value(pChild);
   }

   QVariant IxModel::data(const QModelIndex &index, int role /* = Qt::DisplayRole */) const
   {
      if (!index.isValid())
      {
         return QVariant();
      }
      if ((role == Qt::DisplayRole) || (role == Qt::EditRole))
      {
         if ((index.column() < 0) || (index.column() >= m_lstDataMember.count()))
         {
            return QVariant();
         }
         else if ((index.row() < 0) || (index.row() >= rowCount()))
         {
            return QVariant();
         }
         IxDataMember *pDataMember = m_lstDataMember.at(index.column());
         void *pItem = getRowItemAsVoidPtr(index.row());
         if (!pDataMember || !pItem)
         {
            return QVariant();
         }
         return pDataMember->toVariant(pItem);
      }
      else if (role >= (Qt::UserRole + 1))
      {
         QModelIndex idx = this->index(index.row(), (role - Qt::UserRole - 1), QModelIndex());
         return data(idx, Qt::DisplayRole);
      }
      return QVariant();
   }

   bool IxModel::setData(const QModelIndex &index, const QVariant &value, int role /* = Qt::EditRole */)
   {
      if (!index.isValid())
      {
         return false;
      }
      if (role == Qt::EditRole)
      {
         if ((index.column() < 0) || (index.column() >= m_lstDataMember.count()))
         {
            return false;
         }
         else if ((index.row() < 0) || (index.row() >= rowCount()))
         {
            return false;
         }
         IxDataMember *pDataMember = m_lstDataMember.at(index.column());
         bool bDirtyRow = isDirtyRow(index.row());
         void *pItem = getRowItemAsVoidPtr(index.row());
         if (!pDataMember || !pItem)
         {
            return false;
         }
         QVariant vCurrentValue = pDataMember->toVariant(pItem);
         if (vCurrentValue == value)
         {
            return true;
         }
         qx_bool bSetData = pDataMember->fromVariant(pItem, value);
         if (bSetData && (m_eAutoUpdateDatabase == qx::IxModel::e_auto_update_on_field_change))
         {
            qxSaveRowData(index.row(), (QStringList() << pDataMember->getKey()));
            if (!m_lastError.isValid() && bDirtyRow)
            {
               insertDirtyRowToModel();
            }
            if (m_lastError.isValid())
            {
               if (!bDirtyRow)
               {
                  qDebug("[QxOrm] qx::IxModel::setData() : %s", "an error occurred saving value in database (more details with 'getLastError()' method), so previous value has been restored");
                  pDataMember->fromVariant(pItem, vCurrentValue);
                  return false;
               }
            }
            else if (pDataMember->hasSqlRelation())
            {
               qxFetchRow(index.row(), (QStringList() << pDataMember->getSqlRelation()->getKey()));
            }
         }
         if (bSetData)
         {
            raiseEvent_dataChanged(index, index);
         }
         return bSetData;
      }
      else if (role >= (Qt::UserRole + 1))
      {
         QModelIndex idx = this->index(index.row(), (role - Qt::UserRole - 1), QModelIndex());
         return setData(idx, value, Qt::EditRole);
      }
      return false;
   }

   int IxModel::rowCount(const QModelIndex &parent /* = QModelIndex() */) const
   {
      if (parent.isValid() || !m_pCollection)
      {
         return 0;
      }
      return (static_cast<int>(m_pCollection->_count()) + (getShowEmptyLine() ? 1 : 0));
   }

   int IxModel::columnCount(const QModelIndex &parent /* = QModelIndex() */) const
   {
      if (parent.isValid())
      {
         return 0;
      }
      qAssert(m_lstRoleNames.count() == m_lstDataMember.count());
      return static_cast<int>(m_lstRoleNames.count());
   }

   QModelIndex IxModel::index(int row, int column, const QModelIndex &parent /* = QModelIndex() */) const
   {
      if (!hasIndex(row, column, parent))
      {
         return QModelIndex();
      }
      if ((column < 0) || (column >= m_lstDataMember.count()))
      {
         return QModelIndex();
      }
      IxDataMember *pDataMember = m_lstDataMember.at(column);
      if (pDataMember)
      {
         return createIndex(row, column, static_cast<void *>(pDataMember));
      }
      else
      {
         return QModelIndex();
      }
   }

   QModelIndex IxModel::parent(const QModelIndex &index) const
   {
      Q_UNUSED(index);
      return QModelIndex();
   }

   bool IxModel::hasChildren(const QModelIndex &parent /* = QModelIndex() */) const
   {
      Q_UNUSED(parent);
      return false;
   }

   QVariant IxModel::headerData(int section, Qt::Orientation orientation, int role /* = Qt::DisplayRole */) const
   {
      if (role == Qt::TextAlignmentRole)
      {
         return Qt::AlignCenter;
      }
      if ((orientation == Qt::Vertical) && (role == Qt::DisplayRole) && (isDirtyRow(section)))
      {
         return QVariant(QString("*"));
      }
      if (orientation != Qt::Horizontal)
      {
         return QAbstractItemModel::headerData(section, orientation, role);
      }
      if ((section < 0) || (section >= m_lstDataMember.count()))
      {
         return QAbstractItemModel::headerData(section, orientation, role);
      }
      IxDataMember *pDataMember = m_lstDataMember.at(section);
      if (!pDataMember)
      {
         return QAbstractItemModel::headerData(section, orientation, role);
      }
      QString sHeaderDataKey = (QString::number(role) + "|" + pDataMember->getKey());
      if (m_lstHeadersData.contains(sHeaderDataKey))
      {
         return m_lstHeadersData.value(sHeaderDataKey);
      }
      if ((role == Qt::DisplayRole) || (role == Qt::EditRole))
      {
         if (!pDataMember->getDescription().isEmpty())
         {
            return pDataMember->getDescription();
         }
         return pDataMember->getKey();
      }
      return QVariant();
   }

   Qt::ItemFlags IxModel::flags(const QModelIndex &index) const
   {
      if (!index.isValid())
      {
         return Qt::ItemIsEnabled;
      }
      return (Qt::ItemIsEditable | QAbstractItemModel::flags(index));
   }

#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))
   QHash<int, QByteArray> IxModel::roleNames() const
   {
      return m_lstRoleNames;
   }
#endif // (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))

#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))
   Qt::DropActions IxModel::supportedDragActions() const
   {
      return QAbstractItemModel::supportedDragActions();
   }
#endif // (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))

   Qt::DropActions IxModel::supportedDropActions() const
   {
      return QAbstractItemModel::supportedDropActions();
   }

   bool IxModel::removeRows(int row, int count, const QModelIndex &parent /* = QModelIndex() */)
   {
      if (parent.isValid())
      {
         return false;
      }
      if (m_eAutoUpdateDatabase == IxModel::e_auto_update_on_field_change)
      {
         return removeRowsAutoUpdateOnFieldChange(row, count);
      }
      return removeRowsGeneric(row, count);
   }

   bool IxModel::removeRowsGeneric(int row, int count)
   {
      if (!m_pCollection)
      {
         qAssert(false);
         return false;
      }
      beginRemoveRows(QModelIndex(), row, (row + count - 1));
      for (int i = 0; i < count; ++i)
      {
         m_pCollection->_remove(row);
         removeListOfChild(row);
      }
      updateShowEmptyLine();
      endRemoveRows();
      return true;
   }

   bool IxModel::removeRowsAutoUpdateOnFieldChange(int row, int count)
   {
      if (!m_pCollection)
      {
         qAssert(false);
         return false;
      }
      for (int i = 0; i < count; ++i)
      {
         if ((row >= 0) && (row < m_pCollection->_count()))
         {
            if (qxDeleteRow_(row))
            {
               removeRowsGeneric(row, 1);
            }
            else
            {
               qDebug("[QxOrm] qx::IxModel::removeRowsAutoUpdateOnFieldChange() : %s", "an error occurred deleting row from database (more details with 'getLastError()' method), so row is not removed from model");
               return false;
            }
         }
         else if (isDirtyRow(row))
         {
            setShowEmptyLine(false);
            setShowEmptyLine(true);
         }
         else
         {
            return true;
         }
      }
      return true;
   }

   bool IxModel::setHeaderData(int section, Qt::Orientation orientation, const QVariant &value, int role /* = Qt::EditRole */)
   {
      if (orientation != Qt::Horizontal)
      {
         return QAbstractItemModel::setHeaderData(section, orientation, value, role);
      }
      if ((section < 0) || (section >= m_lstDataMember.count()))
      {
         return false;
      }
      IxDataMember *pDataMember = m_lstDataMember.at(section);
      if (!pDataMember)
      {
         return false;
      }

      if ((role == Qt::EditRole) || (role == Qt::DisplayRole))
      {
         QString sHeaderDataKey = (QString::number(Qt::EditRole) + "|" + pDataMember->getKey());
         m_lstHeadersData.insert(sHeaderDataKey, value);
         sHeaderDataKey = (QString::number(Qt::DisplayRole) + "|" + pDataMember->getKey());
         m_lstHeadersData.insert(sHeaderDataKey, value);
      }
      else
      {
         QString sHeaderDataKey = (QString::number(role) + "|" + pDataMember->getKey());
         m_lstHeadersData.insert(sHeaderDataKey, value);
      }

      Q_EMIT headerDataChanged(orientation, section, section);
      return true;
   }

   bool IxModel::setHeaderData(const QString &sColumnName, const QVariant &value, int role /* = Qt::EditRole */)
   {
      int section = getColumnIndex(sColumnName);
      return ((section == -1) ? false : setHeaderData(section, Qt::Horizontal, value, role));
   }

   void IxModel::syncNestedModel(int row, const QStringList &relation)
   {
      Q_UNUSED(row);
      Q_UNUSED(relation);
   }

   void IxModel::syncAllNestedModel(const QStringList &relation) { Q_UNUSED(relation); }

   void IxModel::syncNestedModelRecursive(IxModel *pNestedModel, const QStringList &relation)
   {
      if (pNestedModel)
      {
         pNestedModel->syncAllNestedModel(relation);
      }
   }

   void IxModel::generateRoleNames()
   {
      int iRoleCount = 0;
      m_lstRoleNames.clear();
      m_lstDataMember.clear();
      m_lstDataMemberByKey.clear();

      for (long l = 0; l < (m_pDataMemberX ? m_pDataMemberX->count_WithDaoStrategy() : 0); ++l)
      {
         IxDataMember *pDataMember = m_pDataMemberX->get_WithDaoStrategy(l);
         if (!pDataMember)
         {
            continue;
         }
         IxSqlRelation *pRelation = (pDataMember->hasSqlRelation() ? pDataMember->getSqlRelation() : NULL);
         IxSqlRelation::relation_type eRelationType = (pRelation ? pRelation->getRelationType() : IxSqlRelation::no_relation);
         if (pRelation && ((eRelationType == IxSqlRelation::one_to_many) || (eRelationType == IxSqlRelation::many_to_many)))
         {
            continue;
         }
         if ((m_lstColumns.count() > 0) && (!m_lstColumns.contains(pDataMember->getKey())))
         {
            continue;
         }
         m_lstRoleNames.insert(static_cast<int>(Qt::UserRole + 1 + iRoleCount), pDataMember->getKey().toLatin1());
         m_lstDataMemberByKey.insert(pDataMember->getKey(), static_cast<int>(m_lstDataMember.count()));
         m_lstDataMember.append(pDataMember);
         iRoleCount++;
      }

#if (QT_VERSION < QT_VERSION_CHECK(5, 0, 0))
      setRoleNames(m_lstRoleNames);
#endif // (QT_VERSION < QT_VERSION_CHECK(5, 0, 0))
   }

   QSqlDatabase *IxModel::database(QSqlDatabase *other)
   {
      return (other ? other : (m_database.isValid() ? (&m_database) : NULL));
   }

#ifndef _QX_NO_JSON

   QString IxModel::toJson(int row /* = -1 */) const { return toJson_Helper(row); }

   bool IxModel::fromJson(const QString &json, int row /* = -1 */) { return fromJson_Helper(json, row); }

   QVariant IxModel::getRelationshipValues(int row, const QString &relation, bool bLoadFromDatabase /* = false */, const QString &sAppendRelations /* = QString() */) { return getRelationshipValues_Helper(row, relation, bLoadFromDatabase, sAppendRelations); }

   bool IxModel::setRelationshipValues(int row, const QString &relation, const QVariant &values) { return setRelationshipValues_Helper(row, relation, values); }

#else // _QX_NO_JSON

   QString IxModel::toJson(int row /* = -1 */) const
   {
      qDebug("[QxOrm] qx::IxModel::toJson() : %s", "not implemented when _QX_NO_JSON compilation option is defined");
      Q_UNUSED(row);
      return QString();
   }

   bool IxModel::fromJson(const QString &json, int row /* = -1 */)
   {
      qDebug("[QxOrm] qx::IxModel::fromJson() : %s", "not implemented when _QX_NO_JSON compilation option is defined");
      Q_UNUSED(json);
      Q_UNUSED(row);
      return false;
   }

   QVariant IxModel::getRelationshipValues(int row, const QString &relation, bool bLoadFromDatabase /* = false */, const QString &sAppendRelations /* = QString() */)
   {
      qDebug("[QxOrm] qx::IxModel::getRelationshipValues() : %s", "not implemented when _QX_NO_JSON compilation option is defined");
      Q_UNUSED(row);
      Q_UNUSED(relation);
      Q_UNUSED(bLoadFromDatabase);
      Q_UNUSED(sAppendRelations);
      return QVariant();
   }

   bool IxModel::setRelationshipValues(int row, const QString &relation, const QVariant &values)
   {
      qDebug("[QxOrm] qx::IxModel::setRelationshipValues() : %s", "not implemented when _QX_NO_JSON compilation option is defined");
      Q_UNUSED(row);
      Q_UNUSED(relation);
      Q_UNUSED(values);
      return false;
   }

#endif // _QX_NO_JSON

} // namespace qx
