Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. Subclassed QSqlRelationalDelegate not working properly with SQlite view
QtWS25 Last Chance

Subclassed QSqlRelationalDelegate not working properly with SQlite view

Scheduled Pinned Locked Moved Unsolved General and Desktop
sqlite3qtableviewdelegaterelational
4 Posts 2 Posters 1.8k Views
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • Q Offline
    Q Offline
    Qutie
    wrote on last edited by Qutie
    #1

    I have table view with a QSortFilterProxy model. The source of the proxy is a QSqlRelationalTableModel. I have subclassed QSqlRelationalDelegate for the QSortFilterProxyModel to edit and display column with foreign key support (ComboBox) and set the table view delegate to it.

    SQlite table 1:
    | ID1 | Name | foreign_key_table2 | foreign_key_table3 |
    
    
    SQlite table 2:
    | ID2 | Value 1 | Value 2 | Value 3 |
    
    SQlite view (join of table1 and table2):
    | ID1 | Name | Value 1 | Value 2 | Value 3 | foreign_key_table3 |
    

    If I set the SQlite table1 as source for the QSqlRelationalTableModel with the correspondend relations, I can edit and display all data properly. The Data gets written to the database.
    If I set the SQlite view as source for for the QSqlRelationalTableModel, I can only edit the cell I first double click on. The createEditor methode of the subclassed delegate is only called on this cell. All other cells are not editable anymore. No data is written to the database.

    I don't fully understand the delegate mechanics. Why does it makes any difference if I use a database view as source and not a table. I noticed that the column header name changes if I set the view as source.

    QTableview headers
    |view.ID1 | view.Name | view.value1 | view.value2 | view.value3 | relTblAl_7.table4ColumnName |
    

    Subclassed delegate

    class SqlProxyRelationalDelegate : public QSqlRelationalDelegate
    {
        Q_OBJECT
    public:
        static int fieldIndex(const QSqlTableModel *const model,
                              const QSqlDriver *const driver,
                              const QString &fieldName)
        {
            const QString stripped = driver->isIdentifierEscaped(fieldName, QSqlDriver::FieldName)
                    ? driver->stripDelimiters(fieldName, QSqlDriver::FieldName)
                    : fieldName;
            return model->fieldIndex(stripped);
        }
        explicit SqlProxyRelationalDelegate(QObject *parent = nullptr);
        virtual QWidget * createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const;
        virtual void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const;
        virtual void setEditorData(QWidget *editor, const QModelIndex &index) const;
    };
    

    Delegate implementation

    QWidget * SqlProxyRelationalDelegate::createEditor(QWidget *aParent, const QStyleOptionViewItem &option, const QModelIndex &index) const{
        const QSqlRelationalTableModel* sqlModel = qobject_cast<const QSqlRelationalTableModel*>(index.model());
        QSqlTableModel* childModel = sqlModel ? sqlModel->relationModel(index.column()) : nullptr;
        if (!childModel)
        {
            const QSortFilterProxyModel* proxyModel = qobject_cast<const QSortFilterProxyModel*>(index.model());
            if (proxyModel)
            {
                sqlModel = qobject_cast<const QSqlRelationalTableModel*>(proxyModel->sourceModel());
                childModel = sqlModel ? sqlModel->relationModel(index.column()) : nullptr;
            }
        }
        if (!childModel)
        {
            return QItemDelegate::createEditor(aParent, option, index);
        }
    
        const QSqlDriver *const driver = childModel->database().driver();
        QComboBox* combo = new QComboBox(aParent);
    
        combo->setModel(childModel);
        int u = fieldIndex(childModel,driver,sqlModel->relation(index.column()).displayColumn());
        combo->setModelColumn(u);
        //combo->setFocusPolicy(Qt::StrongFocus);
        combo->installEventFilter(const_cast<SqlProxyRelationalDelegate*>(this));
    
        return combo;
    }
    
    void SqlProxyRelationalDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const{
    
        QString strVal = "";
        const QSqlRelationalTableModel* sqlModel = qobject_cast<const QSqlRelationalTableModel*>(index.model());
        if (!sqlModel )
        {
            const QSortFilterProxyModel* proxyModel = qobject_cast<const QSortFilterProxyModel*>(index.model());
            if (proxyModel) {
                strVal = proxyModel->data(index).toString();
            }
        } else {
            strVal = sqlModel->data(index).toString();
        }
    
        QComboBox* combo = qobject_cast<QComboBox*>(editor);
    
        if (strVal.isEmpty() || !combo) {
            QItemDelegate::setEditorData(editor, index);
            return;
        }
    
        combo->setCurrentIndex(combo->findText(strVal));
    }
    
    void SqlProxyRelationalDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const{
        if (!index.isValid())
            return;
    
        QSqlRelationalTableModel* sqlModel = qobject_cast<QSqlRelationalTableModel*>(model);
    
        QSortFilterProxyModel* proxyModel = NULL;
        if (!sqlModel )
        {
            proxyModel = qobject_cast<QSortFilterProxyModel*>(model);
            if (proxyModel)
                sqlModel = qobject_cast<QSqlRelationalTableModel*>(proxyModel->sourceModel());
        }
    
        QSqlTableModel *childModel = sqlModel ? sqlModel->relationModel(index.column()) : nullptr;
    
        QComboBox* combo = qobject_cast<QComboBox*>(editor);
        if (!childModel || !combo) {
            QItemDelegate::setModelData(editor, model, index);
            return;
        }
    
        int currentItem = combo->currentIndex();
    
        int childColIndex = childModel->fieldIndex(sqlModel->relation(index.column()).displayColumn());
        int childEditIndex = childModel->fieldIndex(sqlModel->relation(index.column()).indexColumn());
    
        if (proxyModel) {
            proxyModel->setData(index, childModel->data(childModel->index(currentItem, childColIndex), Qt::DisplayRole), Qt::DisplayRole);
            proxyModel->setData(index, childModel->data(childModel->index(currentItem, childEditIndex), Qt::EditRole), Qt::EditRole);
        } else {
            sqlModel->setData(index, childModel->data(childModel->index(currentItem, childColIndex), Qt::DisplayRole), Qt::DisplayRole);
            sqlModel->setData(index, childModel->data(childModel->index(currentItem, childEditIndex), Qt::EditRole), Qt::EditRole);
        }
    }
    
    1 Reply Last reply
    0
    • SGaistS Offline
      SGaistS Offline
      SGaist
      Lifetime Qt Champion
      wrote on last edited by
      #2

      Hi,

      SQLite views are read-only..

      Interested in AI ? www.idiap.ch
      Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

      1 Reply Last reply
      2
      • Q Offline
        Q Offline
        Qutie
        wrote on last edited by
        #3

        That should not be a problem. I set triggers to implement the missing write feature for views.
        I did some further testing.

        1. QSqlRelationalTableModel with Sqlite view as source but no relation set.
        2. QSqlRelationalTableModel with Sqlite view as source with relations set.
        3. QSortFilterProxyModel with 2) as source

        With 1) I can edit data in the view and it gets written to the DB.
        With 2) and 3) Data edits are not commited to the db.

        It seams there is already a problem with QSqlRelationalTableModel and views.

        1 Reply Last reply
        0
        • SGaistS Offline
          SGaistS Offline
          SGaist
          Lifetime Qt Champion
          wrote on last edited by
          #4

          Did you already checked the bug report system to see if there was something related ?

          If not, please consider opening a new report providing a minimal compilable example showing the behaviour.

          Interested in AI ? www.idiap.ch
          Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

          1 Reply Last reply
          0

          • Login

          • Login or register to search.
          • First post
            Last post
          0
          • Categories
          • Recent
          • Tags
          • Popular
          • Users
          • Groups
          • Search
          • Get Qt Extensions
          • Unsolved