1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of the QtSql module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see https://www.qt.io/terms-conditions. For further
15 ** information use the contact form at https://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 3 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL3 included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 3 requirements
23 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24 **
25 ** GNU General Public License Usage
26 ** Alternatively, this file may be used under the terms of the GNU
27 ** General Public License version 2.0 or (at your option) the GNU General
28 ** Public license version 3 or any later version approved by the KDE Free
29 ** Qt Foundation. The licenses are as published by the Free Software
30 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31 ** included in the packaging of this file. Please review the following
32 ** information to ensure the GNU General Public License requirements will
33 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34 ** https://www.gnu.org/licenses/gpl-3.0.html.
35 **
36 ** $QT_END_LICENSE$
37 **
38 ****************************************************************************/
39 
40 #ifndef QSQLRELATIONALDELEGATE_H
41 #define QSQLRELATIONALDELEGATE_H
42 
43 #include <QtSql/qtsqlglobal.h>
44 
45 QT_REQUIRE_CONFIG(sqlmodel);
46 
47 #ifdef QT_WIDGETS_LIB
48 
49 #include <QtWidgets/qitemdelegate.h>
50 #if QT_CONFIG(listview)
51 #include <QtWidgets/qlistview.h>
52 #endif
53 #if QT_CONFIG(combobox)
54 #include <QtWidgets/qcombobox.h>
55 #endif
56 #include <QtSql/qsqldriver.h>
57 #include <QtSql/qsqlrelationaltablemodel.h>
58 #include <QtCore/qmetaobject.h>
59 QT_BEGIN_NAMESPACE
60 
61 // ### Qt6: QStyledItemDelegate
62 class QSqlRelationalDelegate: public QItemDelegate
63 {
fieldIndex(const QSqlTableModel * const model,const QSqlDriver * const driver,const QString & fieldName)64     static int fieldIndex(const QSqlTableModel *const model,
65                           const QSqlDriver *const driver,
66                           const QString &fieldName)
67     {
68         const QString stripped = driver->isIdentifierEscaped(fieldName, QSqlDriver::FieldName)
69                 ? driver->stripDelimiters(fieldName, QSqlDriver::FieldName)
70                 : fieldName;
71         return model->fieldIndex(stripped);
72     }
73 
74 public:
75 
76 explicit QSqlRelationalDelegate(QObject *aParent = nullptr)
QItemDelegate(aParent)77     : QItemDelegate(aParent)
78 {}
79 
~QSqlRelationalDelegate()80 ~QSqlRelationalDelegate()
81 {}
82 
createEditor(QWidget * aParent,const QStyleOptionViewItem & option,const QModelIndex & index)83 QWidget *createEditor(QWidget *aParent,
84                       const QStyleOptionViewItem &option,
85                       const QModelIndex &index) const override
86 {
87     const QSqlRelationalTableModel *sqlModel = qobject_cast<const QSqlRelationalTableModel *>(index.model());
88     QSqlTableModel *childModel = sqlModel ? sqlModel->relationModel(index.column()) : nullptr;
89     if (!childModel)
90         return QItemDelegate::createEditor(aParent, option, index);
91     const QSqlDriver *const driver = childModel->database().driver();
92 
93     QComboBox *combo = new QComboBox(aParent);
94     combo->setModel(childModel);
95     combo->setModelColumn(fieldIndex(childModel, driver,
96                                      sqlModel->relation(index.column()).displayColumn()));
97     combo->installEventFilter(const_cast<QSqlRelationalDelegate *>(this));
98 
99     return combo;
100 }
101 
setEditorData(QWidget * editor,const QModelIndex & index)102     void setEditorData(QWidget *editor, const QModelIndex &index) const override
103     {
104         if (!index.isValid())
105             return;
106 
107         if (qobject_cast<QComboBox *>(editor)) {
108             // Taken from QItemDelegate::setEditorData() as we need
109             // to present the DisplayRole and not the EditRole which
110             // is the id reference to the related model
111             QVariant v = index.data(Qt::DisplayRole);
112             const QByteArray n = editor->metaObject()->userProperty().name();
113             if (!n.isEmpty()) {
114                 if (!v.isValid())
115                     v = QVariant(editor->property(n.data()).userType(), nullptr);
116                 editor->setProperty(n.data(), v);
117                 return;
118             }
119         }
120         QItemDelegate::setEditorData(editor, index);
121     }
122 
setModelData(QWidget * editor,QAbstractItemModel * model,const QModelIndex & index)123 void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const override
124 {
125     if (!index.isValid())
126         return;
127 
128     QSqlRelationalTableModel *sqlModel = qobject_cast<QSqlRelationalTableModel *>(model);
129     QSqlTableModel *childModel = sqlModel ? sqlModel->relationModel(index.column()) : nullptr;
130     QComboBox *combo = qobject_cast<QComboBox *>(editor);
131     if (!sqlModel || !childModel || !combo) {
132         QItemDelegate::setModelData(editor, model, index);
133         return;
134     }
135     const QSqlDriver *const driver = childModel->database().driver();
136 
137     int currentItem = combo->currentIndex();
138     int childColIndex = fieldIndex(childModel, driver,
139                                    sqlModel->relation(index.column()).displayColumn());
140     int childEditIndex = fieldIndex(childModel, driver,
141                                     sqlModel->relation(index.column()).indexColumn());
142     sqlModel->setData(index,
143             childModel->data(childModel->index(currentItem, childColIndex), Qt::DisplayRole),
144             Qt::DisplayRole);
145     sqlModel->setData(index,
146             childModel->data(childModel->index(currentItem, childEditIndex), Qt::EditRole),
147             Qt::EditRole);
148 }
149 
150 };
151 
152 QT_END_NAMESPACE
153 
154 #endif // QT_WIDGETS_LIB
155 
156 #endif // QSQLRELATIONALDELEGATE_H
157