1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#ifndef QSQLRELATIONALDELEGATE_H
5#define QSQLRELATIONALDELEGATE_H
6
7#include <QtSql/qtsqlglobal.h>
8
9QT_REQUIRE_CONFIG(sqlmodel);
10
11#ifdef QT_WIDGETS_LIB
12
13#include <QtWidgets/qstyleditemdelegate.h>
14#if QT_CONFIG(listview)
15#include <QtWidgets/qlistview.h>
16#endif
17#if QT_CONFIG(combobox)
18#include <QtWidgets/qcombobox.h>
19#endif
20#include <QtSql/qsqldriver.h>
21#include <QtSql/qsqlrelationaltablemodel.h>
22#include <QtCore/qmetaobject.h>
23QT_BEGIN_NAMESPACE
24
25class QSqlRelationalDelegate : public QStyledItemDelegate
26{
27 static int fieldIndex(const QSqlTableModel *const model,
28 const QSqlDriver *const driver,
29 const QString &fieldName)
30 {
31 const QString stripped = driver->isIdentifierEscaped(fieldName, QSqlDriver::FieldName)
32 ? driver->stripDelimiters(fieldName, QSqlDriver::FieldName)
33 : fieldName;
34 return model->fieldIndex(stripped);
35 }
36
37public:
38
39 explicit QSqlRelationalDelegate(QObject *aParent = nullptr)
40 : QStyledItemDelegate(aParent)
41 {}
42
43 ~QSqlRelationalDelegate()
44 {}
45
46 QWidget *createEditor(QWidget *aParent,
47 const QStyleOptionViewItem &option,
48 const QModelIndex &index) const override
49 {
50 const QSqlRelationalTableModel *sqlModel = qobject_cast<const QSqlRelationalTableModel *>(index.model());
51 QSqlTableModel *childModel = sqlModel ? sqlModel->relationModel(index.column()) : nullptr;
52 if (!childModel)
53 return QStyledItemDelegate::createEditor(aParent, option, index);
54 const QSqlDriver *const driver = childModel->database().driver();
55
56 QComboBox *combo = new QComboBox(aParent);
57 combo->setModel(childModel);
58 combo->setModelColumn(fieldIndex(childModel, driver,
59 sqlModel->relation(index.column()).displayColumn()));
60 combo->installEventFilter(const_cast<QSqlRelationalDelegate *>(this));
61
62 return combo;
63 }
64
65 void setEditorData(QWidget *editor, const QModelIndex &index) const override
66 {
67 if (!index.isValid())
68 return;
69
70 if (qobject_cast<QComboBox *>(editor)) {
71 // Taken from QItemDelegate::setEditorData() as we need
72 // to present the DisplayRole and not the EditRole which
73 // is the id reference to the related model
74 QVariant v = index.data(Qt::DisplayRole);
75 const QByteArray n = editor->metaObject()->userProperty().name();
76 if (!n.isEmpty()) {
77 if (!v.isValid())
78 v = QVariant(editor->property(n.data()).metaType());
79 editor->setProperty(n.data(), v);
80 return;
81 }
82 }
83 QStyledItemDelegate::setEditorData(editor, index);
84 }
85
86void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const override
87{
88 if (!index.isValid())
89 return;
90
91 QSqlRelationalTableModel *sqlModel = qobject_cast<QSqlRelationalTableModel *>(model);
92 QSqlTableModel *childModel = sqlModel ? sqlModel->relationModel(index.column()) : nullptr;
93 QComboBox *combo = qobject_cast<QComboBox *>(editor);
94 if (!sqlModel || !childModel || !combo) {
95 QStyledItemDelegate::setModelData(editor, model, index);
96 return;
97 }
98 const QSqlDriver *const driver = childModel->database().driver();
99
100 int currentItem = combo->currentIndex();
101 int childColIndex = fieldIndex(childModel, driver,
102 sqlModel->relation(index.column()).displayColumn());
103 int childEditIndex = fieldIndex(childModel, driver,
104 sqlModel->relation(index.column()).indexColumn());
105 sqlModel->setData(index,
106 childModel->data(childModel->index(currentItem, childColIndex), Qt::DisplayRole),
107 Qt::DisplayRole);
108 sqlModel->setData(index,
109 childModel->data(childModel->index(currentItem, childEditIndex), Qt::EditRole),
110 Qt::EditRole);
111}
112
113};
114
115QT_END_NAMESPACE
116
117#endif // QT_WIDGETS_LIB
118
119#endif // QSQLRELATIONALDELEGATE_H
120

source code of qtbase/src/sql/models/qsqlrelationaldelegate.h