1// Copyright (C) 2024 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#include "qquicktableviewdelegate_p.h"
5#include "qquicktableviewdelegate_p_p.h"
6
7#include <QtQuickTemplates2/private/qquickitemdelegate_p_p.h>
8#include <QtQuick/private/qquicktaphandler_p.h>
9#include <QtQuick/private/qquicktableview_p.h>
10
11#include <QtCore/qpointer.h>
12
13QT_BEGIN_NAMESPACE
14
15/*!
16 \qmltype TableViewDelegate
17 \inherits ItemDelegate
18 \inqmlmodule QtQuick.Controls
19 \since 6.9
20 \ingroup qtquickcontrols-delegates
21 \brief A delegate that can be assigned to a TableView.
22
23 \image qtquickcontrols-tableviewdelegate.png
24
25 A TableViewDelegate is a delegate that can be assigned to the
26 \l {TableView::delegate} {delegate property} of a \l TableView.
27 It renders each cell of the table in the view using the application style.
28
29 \code
30 TableView {
31 anchors.fill: parent
32 delegate: TableViewDelegate {}
33 // model: yourModel
34 }
35 \endcode
36
37 TableViewDelegate inherits \l ItemDelegate, which means that it's composed of
38 two items: a \l[QML]{Control::}{background} and a \l [QML]{Control::}{contentItem}.
39
40 The position of the contentItem is controlled with \l [QML]{Control::}{padding}.
41
42 \section2 Interacting with pointers
43 TableViewDelegate inherits \l ItemDelegate. This means that it will emit signals such as
44 \l {AbstractButton::clicked()}{clicked} when the user clicks on the delegate.
45 You can connect to this signal to implement application-specific functionality.
46
47 However, the ItemDelegate API does not give you information about the position of the
48 click, or which modifiers are being held. If this is needed, a better approach would
49 be to use pointer handlers, for example:
50
51 \code
52 TableView {
53 id: tableView
54 delegate: TableViewDelegate {
55 TapHandler {
56 acceptedButtons: Qt.RightButton
57 onTapped: someContextMenu.open()
58 }
59
60 TapHandler {
61 acceptedModifiers: Qt.ControlModifier
62 onTapped: tableView.doSomethingToCell(row, column)
63 }
64 }
65 }
66 \endcode
67
68 \note If you want to disable the default behavior that occurs when the
69 user clicks on the delegate (like changing the current index), you can set
70 \l {TableView::pointerNavigationEnabled}{pointerNavigationEnabled} to \c false.
71
72 \section2 Editing cells in the table
73 TableViewDelegate has a default \l {TableView::editDelegate}{edit delegate} assigned.
74 If \l TableView has \l {TableView::editTriggers}{edit triggers} set, and
75 the \l {TableView::model}{model} has support for \l {Editing cells} {editing model items},
76 then the user can activate any of the edit triggers to edit the text of
77 the \l {TableViewDelegate::current}{current} table cell.
78
79 The default edit delegate will use the \c {Qt.EditRole} to read and write data to the
80 \l {TableView::model}{model}. If you need to use another role, or otherwise have needs
81 outside what the default edit delegate offers, you can always assign your own delegate
82 to \l {TableView::editDelegate}{TableView.editDelegate}.
83
84 \sa {Customizing TableViewDelegate}, {TableView}
85*/
86
87/*!
88 \qmlproperty TableView QtQuick.Controls::TableViewDelegate::tableView
89
90 This property points to the \l TableView that contains the delegate item.
91*/
92
93/*!
94 \qmlproperty bool QtQuick.Controls::TableViewDelegate::current
95
96 This property holds whether or not the delegate represents the
97 \l {QItemSelectionModel::currentIndex()}{current index}
98 in the \l {TableView::selectionModel}{selection model}.
99*/
100
101/*!
102 \qmlproperty bool QtQuick.Controls::TableViewDelegate::selected
103
104 This property holds whether or not the delegate represents a
105 \l {QItemSelectionModel::selection()}{selected index}
106 in the \l {TableView::selectionModel}{selection model}.
107*/
108
109/*!
110 \qmlproperty bool QtQuick.Controls::TableViewDelegate::editing
111
112 This property holds whether or not the delegate is being \l {Editing cells}{edited}.
113*/
114
115using namespace Qt::Literals::StringLiterals;
116
117QQuickTableViewDelegate::QQuickTableViewDelegate(QQuickItem *parent)
118 : QQuickItemDelegate(*(new QQuickTableViewDelegatePrivate), parent)
119{
120 Q_D(QQuickTableViewDelegate);
121
122 auto tapHandler = new QQuickTapHandler(this);
123 tapHandler->setAcceptedModifiers(Qt::NoModifier);
124
125 // Since we override mousePressEvent to avoid QQuickAbstractButton from blocking
126 // pointer handlers, we inform the button about its pressed state from the tap
127 // handler instead. This will ensure that we emit button signals like
128 // pressed, clicked, and doubleClicked.
129 connect(sender: tapHandler, signal: &QQuickTapHandler::pressedChanged, context: this, slot: [this, d, tapHandler] {
130 auto view = tableView();
131 if (!view || !view->pointerNavigationEnabled())
132 return;
133
134 const QQuickHandlerPoint p = tapHandler->point();
135 if (tapHandler->isPressed())
136 d->handlePress(point: p.position(), timestamp: 0);
137 else if (tapHandler->tapCount() > 0)
138 d->handleRelease(point: p.position(), timestamp: 0);
139 else
140 d->handleUngrab();
141
142 if (tapHandler->tapCount() > 1 && !tapHandler->isPressed())
143 emit doubleClicked();
144 }, type: Qt::DirectConnection);
145}
146
147QQuickTableViewDelegate::QQuickTableViewDelegate(QQuickTableViewDelegatePrivate &dd, QQuickItem *parent)
148 : QQuickItemDelegate(dd, parent)
149{
150}
151
152void QQuickTableViewDelegate::mousePressEvent(QMouseEvent *event)
153{
154 Q_D(QQuickTableViewDelegate);
155
156 const auto view = d->m_tableView;
157 if (view && view->pointerNavigationEnabled()) {
158 // Ignore mouse events so that we don't block our own pointer handlers, or
159 // pointer handlers in e.g TreeView, TableView, or SelectionRectangle. Instead
160 // we call out to the needed mouse handling functions in QQuickAbstractButton directly
161 // from our pointer handlers, to ensure that we continue to work as a button.
162 event->ignore();
163 return;
164 }
165
166 QQuickItemDelegate::mousePressEvent(event);
167}
168
169QPalette QQuickTableViewDelegatePrivate::defaultPalette() const
170{
171 return QQuickTheme::palette(scope: QQuickTheme::ItemView);
172}
173
174QFont QQuickTableViewDelegate::defaultFont() const
175{
176 return QQuickTheme::font(scope: QQuickTheme::ItemView);
177}
178
179bool QQuickTableViewDelegate::current() const
180{
181 return d_func()->current;
182}
183
184void QQuickTableViewDelegate::setCurrent(bool current)
185{
186 Q_D(QQuickTableViewDelegate);
187 if (d->current == current)
188 return;
189
190 d->current = current;
191 emit currentChanged();
192}
193
194bool QQuickTableViewDelegate::selected() const
195{
196 return d_func()->selected;
197}
198
199void QQuickTableViewDelegate::setSelected(bool selected)
200{
201 Q_D(QQuickTableViewDelegate);
202 if (d->selected == selected)
203 return;
204
205 d->selected = selected;
206 emit selectedChanged();
207}
208
209bool QQuickTableViewDelegate::editing() const
210{
211 return d_func()->editing;
212}
213
214void QQuickTableViewDelegate::setEditing(bool editing)
215{
216 Q_D(QQuickTableViewDelegate);
217 if (d->editing == editing)
218 return;
219
220 d->editing = editing;
221 emit editingChanged();
222}
223
224QQuickTableView *QQuickTableViewDelegate::tableView() const
225{
226 return d_func()->m_tableView;
227}
228
229void QQuickTableViewDelegate::setTableView(QQuickTableView *tableView)
230{
231 Q_D(QQuickTableViewDelegate);
232 if (d->m_tableView == tableView)
233 return;
234
235 d->m_tableView = tableView;
236 emit tableViewChanged();
237}
238
239QT_END_NAMESPACE
240
241#include "moc_qquicktableviewdelegate_p.cpp"
242

source code of qtdeclarative/src/quicktemplates/qquicktableviewdelegate.cpp