QSqlRelationalDelegate subclass that works with QSqlRelationalTableModel

When you are using a QSqlRelationalTableModel in combination with QSortFilterProxyModel, you loose the automatic combobox that is displayed in a QTableView.

This is a subclass of QSqlRelationalDelegate, that works:

COMMENT: To use it with another proxy model (my own QXTreeProxyModel that converts a table to a tree that can be displayed by QTreeView), I replaced QSortFilterProxyModel by QAbstractProxyModel throughout the code in mysqlrelationaldelegate.cpp; no other changes were necessary. BTW, QXTreeProxyModel is available on https://github.com/Al-/QXTreeProxyModel

Header:

  1. #ifndef MYSQLRELATIONALDELEGATE_H
  2. #define MYSQLRELATIONALDELEGATE_H
  3.  
  4. #include <QSqlRelationalDelegate>
  5.  
  6. class mySqlRelationalDelegate : public QSqlRelationalDelegate
  7. {
  8.     Q_OBJECT
  9. public:
  10.     explicit mySqlRelationalDelegate(QObject *parent = 0);
  11.  
  12.     QWidget *createEditor(QWidget *aParent, const QStyleOptionViewItem &option, const QModelIndex &index) const;
  13.     void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const;
  14.     void setEditorData(QWidget *editor, const QModelIndex &index) const;
  15.  
  16. signals:
  17.  
  18. public slots:
  19.  
  20. };
  21.  
  22. #endif // MYSQLRELATIONALDELEGATE_H

Source:

  1. #include "mysqlrelationaldelegate.h"
  2. #include <QSqlRelationalTableModel>
  3. #include <QSortFilterProxyModel>
  4.  
  5. #include <QDebug>
  6. #include <QSqlRecord>
  7.  
  8. mySqlRelationalDelegate::mySqlRelationalDelegate(QObject *parent) :
  9.     QSqlRelationalDelegate (parent)
  10. {
  11. }
  12.  
  13.  
  14. QWidget *mySqlRelationalDelegate::createEditor(QWidget *aParent, const QStyleOptionViewItem &option, const QModelIndex &index) const {
  15.  
  16.     const QSqlRelationalTableModel *sqlModel = qobject_cast<const QSqlRelationalTableModel *>(index.model());
  17.     QSqlTableModel *childModel = sqlModel ? sqlModel->relationModel(index.column()) : 0;
  18.  
  19.     if (!childModel )
  20.     {
  21.         const QSortFilterProxyModel* proxyModel = qobject_cast<const QSortFilterProxyModel *>(index.model());
  22.         if (proxyModel)
  23.         {
  24.             sqlModel = qobject_cast<const QSqlRelationalTableModel *>(proxyModel->sourceModel());
  25.             childModel = sqlModel ? sqlModel->relationModel(index.column()) : 0;
  26.         }
  27.     }
  28.  
  29.     if (!childModel)
  30.     {
  31.         return QItemDelegate::createEditor(aParent, option, index);
  32.     }
  33.  
  34.     QComboBox *combo = new QComboBox(aParent);
  35.     combo->setModel(childModel);
  36.     combo->setModelColumn(childModel->fieldIndex(sqlModel->relation(index.column()).displayColumn()));
  37.     combo->installEventFilter(const_cast<mySqlRelationalDelegate *>(this));
  38.  
  39.     return combo;
  40.  
  41. }
  42.  
  43. void mySqlRelationalDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const
  44. {
  45.     QString strVal = "";
  46.     const QSqlRelationalTableModel *sqlModel = qobject_cast<const QSqlRelationalTableModel *>(index.model());
  47.     if (!sqlModel )
  48.     {
  49.         const QSortFilterProxyModel* proxyModel = qobject_cast<const QSortFilterProxyModel *>(index.model());
  50.         if (proxyModel) {
  51.             strVal = proxyModel->data(index).toString();
  52.         }
  53.     } else {
  54.         strVal = sqlModel->data(index).toString();
  55.     }
  56.  
  57.     QComboBox *combo = qobject_cast<QComboBox *>(editor);
  58.     if (strVal.isEmpty() || !combo) {
  59.         QItemDelegate::setEditorData(editor, index);
  60.         return;
  61.     }
  62.  
  63.     combo->setCurrentIndex(combo->findText(strVal));
  64. }
  65.  
  66. void mySqlRelationalDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const
  67. {
  68.     if (!index.isValid())
  69.         return;
  70.  
  71.     QSqlRelationalTableModel *sqlModel = qobject_cast<QSqlRelationalTableModel *>(model);
  72.     QSortFilterProxyModel* proxyModel = NULL;
  73.     if (!sqlModel )
  74.     {
  75.         proxyModel = qobject_cast<QSortFilterProxyModel *>(model);
  76.         if (proxyModel)
  77.              sqlModel = qobject_cast<QSqlRelationalTableModel *>(proxyModel->sourceModel());
  78.     }
  79.  
  80.     QSqlTableModel *childModel = sqlModel ? sqlModel->relationModel(index.column()) : 0;
  81.     QComboBox *combo = qobject_cast<QComboBox *>(editor);
  82.     if (!sqlModel || !childModel || !combo) {
  83.         QItemDelegate::setModelData(editor, model, index);
  84.         return;
  85.     }
  86.  
  87.     int currentItem = combo->currentIndex();
  88.     int childColIndex = childModel->fieldIndex(sqlModel->relation(index.column()).displayColumn());
  89.     int childEditIndex = childModel->fieldIndex(sqlModel->relation(index.column()).indexColumn());
  90.  
  91.  
  92.     if (proxyModel) {
  93.         proxyModel->setData(index, childModel->data(childModel->index(currentItem, childColIndex), Qt::DisplayRole), Qt::DisplayRole);
  94.         proxyModel->setData(index, childModel->data(childModel->index(currentItem, childEditIndex), Qt::EditRole), Qt::EditRole);
  95.     } else {
  96.         sqlModel->setData(index, childModel->data(childModel->index(currentItem, childColIndex), Qt::DisplayRole), Qt::DisplayRole);
  97.         sqlModel->setData(index, childModel->data(childModel->index(currentItem, childEditIndex), Qt::EditRole), Qt::EditRole);
  98.     }
  99. }

Categories: