Coverage Report

Created: 2026-07-15 07:03

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/wt/src/Wt/WItemDelegate.h
Line
Count
Source
1
// This may look like C code, but it's really -*- C++ -*-
2
/*
3
 * Copyright (C) 2009 Emweb bv, Herent, Belgium.
4
 *
5
 * See the LICENSE file for terms of use.
6
 */
7
#ifndef WITEMDELEGATE_H_
8
#define WITEMDELEGATE_H_
9
10
#include <Wt/WAbstractItemDelegate.h>
11
#include <Wt/WCheckBox.h>
12
#include <Wt/WLineEdit.h>
13
#include <Wt/WString.h>
14
15
namespace Wt {
16
  class WAnchor;
17
  class WCheckBox;
18
  class WContainerWidget;
19
  class WImage;
20
  class WLineEdit;
21
  class WText;
22
23
#ifndef WT_CNOR
24
  template <class Widget> class IndexEdit;
25
  typedef IndexEdit<WCheckBox> IndexCheckBox;
26
  typedef IndexEdit<WContainerWidget> IndexContainerWidget;
27
  typedef IndexEdit<WAnchor> IndexAnchor;
28
  typedef IndexEdit<WText> IndexText;
29
#else
30
  class IndexCheckBox;
31
  class IndexContainerWidget;
32
  class IndexAnchor;
33
  class IndexText;
34
#endif // WT_CNOR
35
36
/*! \class WItemDelegate Wt/WItemDelegate.h Wt/WItemDelegate.h
37
 *  \brief Standard delegate class for rendering a view item.
38
 *
39
 * This class provides the standard implementation for rendering an
40
 * item (as in a WAbstractItemView), and renders data provided by the
41
 * standard data roles (see ItemDataRole). It also provides default
42
 * editing support using a line edit.
43
 *
44
 * You may provide special editing support for an item by specializing
45
 * the widget and reimplement createEditor(), setModelData(),
46
 * editState(), and setEditState().
47
 *
48
 * \ingroup modelview
49
 */
50
class WT_API WItemDelegate : public WAbstractItemDelegate
51
{
52
public:
53
  /*! \brief Create an item delegate.
54
   */
55
  WItemDelegate();
56
57
  /*! \brief Creates or updates a widget that renders an item.
58
   *
59
   * The following properties of an item are rendered:
60
   *
61
   * - text using the Wt::ItemDataRole::Display data, with the format specified
62
   *   by setTextFormat()
63
   * - a check box depending on the Wt::ItemFlag::UserCheckable flag and
64
   *   Wt::ItemDataRole::Checked data
65
   * - an anchor depending on the value of Wt::ItemDataRole::Link
66
   * - an icon depending on the value of Wt::ItemDataRole::Decoration
67
   * - a tooltip depending on the value of Wt::ItemDataRole::ToolTip
68
   * - a custom style class depending on the value of Wt::ItemDataRole::StyleClass
69
   *
70
   * When the flags indicates Wt::ViewItemRenderFlag::Editing, then createEditor() is
71
   * called to create a suitable editor for editing the item.
72
   */
73
  virtual std::unique_ptr<WWidget> update
74
    (WWidget *widget, const WModelIndex& index,
75
     WFlags<ViewItemRenderFlag> flags) override;
76
77
  virtual void updateModelIndex(WWidget *widget, const WModelIndex& index)
78
    override;
79
80
  /*! \brief Sets the text format string.
81
   *
82
   * \if cpp
83
   *
84
   * The ItemDataRole::Display data is converted to a string using asString() by passing
85
   * the given format.
86
   *
87
   * \elseif java
88
   *
89
   * The ItemDataRole::Display data is converted to a string using {javadoclink
90
   * StringUtils#asString(Object)}, passing the given format. If the format is
91
   * an empty string, this corresponds to {javadoclink Object#toString()}.
92
   *
93
   * \endif
94
   *
95
   * The default value is "".
96
   */
97
  void setTextFormat(const WT_USTRING& format);
98
99
  /*! \brief Returns the text format string.
100
   *
101
   * \sa setTextFormat()
102
   */
103
0
  const WT_USTRING& textFormat() const { return textFormat_; }
104
105
  /*! \brief Saves the edited data to the model.
106
   *
107
   * The default implementation saves the current edit value to the model.
108
   * You will need to reimplement this method for a custom editor.
109
   *
110
   * As an example of how to deal with a specialized editor, consider the
111
   * default implementation:
112
   * \if cpp
113
   * \code
114
   * void WItemDelegate::setModelData(const Wt::cpp17::any& editState,
115
   *                                  Wt::WAbstractItemModel *model,
116
   *                                  const Wt::WModelIndex& index) const
117
   * {
118
   *   model->setData(index, editState, ItemDataRole::Edit);
119
   * }
120
   * \endcode
121
   * \elseif java
122
   * \code
123
   * public void setModelData(Object editState, WAbstractItemModel model, WModelIndex index) {
124
   *   model.setData(index, editState, ItemDataRole.ItemDataRole::Edit);
125
   * }
126
   * \endcode
127
   * \endif
128
   *
129
   * \sa createEditor(), editState()
130
   */
131
  virtual void setModelData(const cpp17::any& editState,
132
                            WAbstractItemModel *model,
133
                            const WModelIndex& index) const override;
134
135
  /*! \brief Returns the current edit state.
136
   *
137
   * The default implementation returns the current text in the line edit.
138
   * You will need to reimplement this method for a custom editor.
139
   *
140
   * As an example of how to deal with a specialized editor, consider the
141
   * default implementation:
142
   * \if cpp
143
   * \code
144
   * cpp17::any WItemDelegate::editState(Wt::WWidget *editor) const
145
   * {
146
   *   Wt::WContainerWidget *w = dynamic_cast<Wt::WContainerWidget *>(editor);
147
   *   Wt::WLineEdit *lineEdit = dynamic_cast<Wt::WLineEdit *>(w->widget(0));
148
   *
149
   *   return cpp17::any(lineEdit->text());
150
   * }
151
   * \endcode
152
   * \elseif java
153
   * \code
154
   * public Object getEditState(WWidget editor) {
155
   *   WContainerWidget w = (WContainerWidget) editor;
156
   *   WLineEdit lineEdit = (WLineEdit) w.getWidget(0);
157
   *   return lineEdit.getText();
158
   * }
159
   * \endcode
160
   * \endif
161
   *
162
   * \sa createEditor(), setEditState(), setModelData()
163
   */
164
  virtual cpp17::any editState(WWidget *editor, const WModelIndex& index) const
165
    override;
166
167
  /*! \brief Sets the editor data from the editor state.
168
   *
169
   * The default implementation resets the text in the line edit.
170
   * You will need to reimplement this method if for a custom editor.
171
   *
172
   * As an example of how to deal with a specialized editor, consider the
173
   * default implementation:
174
   * \if cpp
175
   * \code
176
   * void WItemDelegate::setEditState(Wt::WWidget *editor, const WModelIndex& index, const cpp17::any& value) const
177
   * {
178
   *   Wt::WContainerWidget *w = dynamic_cast<Wt::WContainerWidget *>(editor);
179
   *   Wt::WLineEdit *lineEdit = dynamic_cast<Wt::WLineEdit *>(w->widget(0));
180
   *
181
   *   lineEdit->setText(cpp17::any_cast<Wt::WString>(value));
182
   * }
183
   * \endcode
184
   * \elseif java
185
   * \code
186
   * public void setEditState(WWidget editor, WModelIndex index, Object value) {
187
   *   WContainerWidget w = (WContainerWidget) editor;
188
   *   WLineEdit lineEdit = (WLineEdit) w.getWidget(0);
189
   *   lineEdit.setText((String) value);
190
   * }
191
   * \endcode
192
   * \endif
193
   *
194
   * \sa createEditor()
195
   */
196
  virtual void setEditState(WWidget *editor, const WModelIndex& index,
197
                            const cpp17::any& value) const
198
    override;
199
200
protected:
201
  /*! \brief Creates an editor for a data item.
202
   *
203
   * The default implementation returns a WLineEdit which edits the
204
   * item's Wt::ItemDataRole::Edit value.
205
   *
206
   * You may reimplement this method to provide a suitable editor, or
207
   * to attach a custom validator. In that case, you will probably
208
   * also want to reimplement editState(), setEditState(), and
209
   * setModelData().
210
   *
211
   * The editor should not keep a reference to the model index (it
212
   * does not need to since setModelData() will provide the proper
213
   * model index to save the data to the model). Otherwise, because
214
   * model indexes may shift because of row or column insertions, you
215
   * should reimplement updateModelIndex().
216
   *
217
   * As an example of how to provide a specialized editor, consider the
218
   * default implementation, which returns a WLineEdit:
219
   * \if cpp
220
   * \code
221
   * std::unique_ptr<Wt::WWidget> WItemDelegate::createEditor(const Wt::WModelIndex& index, WFlags<ViewItemRenderFlag> flags) const
222
   * {
223
   *   auto result = std::make_unique<Wt::WContainerWidget>();
224
   *   result->setSelectable(true);
225
   *
226
   *   auto lineEdit = std::make_unique<Wt::WLineEdit>();
227
   *   lineEdit->setText(asString(index.data(ItemDataRole::Edit), textFormat_));
228
   *   lineEdit->enterPressed().connect(std::bind(&WItemDelegate::doCloseEditor, this, result, true));
229
   *   lineEdit->escapePressed().connect(std::bind(&WItemDelegate::doCloseEditor, this, result, false));
230
   *
231
   *   if (flags.test(ViewItemRenderFlag::Focused))
232
   *     lineEdit->setFocus();
233
   *
234
   *   // We use a layout so that the line edit fills the entire cell.
235
   *   result->setLayout(std::make_unique<WHBoxLayout>());
236
   *   result->layout()->setContentsMargins(1, 1, 1, 1);
237
   *   result->layout()->addWidget(std::move(lineEdit));
238
   *
239
   *   return result;
240
   * }
241
   *
242
   * void WItemDelegate::doCloseEditor(Wt::WWidget *editor, bool save) const
243
   * {
244
   *   closeEditor().emit(editor, save);
245
   * }
246
   * \endcode
247
   * \elseif java
248
   * \code
249
   * protected WWidget createEditor(WModelIndex index, EnumSet&lt;ViewItemRenderFlag&gt; flags) {
250
   *  final WContainerWidget result = new WContainerWidget();
251
   *  result.setSelectable(true);
252
   *  WLineEdit lineEdit = new WLineEdit();
253
   *  lineEdit.setText(StringUtils.asString(index.getData(ItemDataRole.ItemDataRole::Edit), this.textFormat_).toString());
254
   *  lineEdit.enterPressed().addListener(this, new Signal.Listener() {
255
   *    public void trigger() {
256
   *      WItemDelegate.this.closeEditor().trigger(result, true);
257
   *    }
258
   *  });
259
   *  lineEdit.escapePressed().addListener(this, new Signal.Listener() {
260
   *    public void trigger() {
261
   *      WItemDelegate.this.closeEditor().trigger(result, false);
262
   *    }
263
   *  });
264
   *
265
   *  if (flags.contains(ViewItemRenderFlag.ViewItemRenderFlag::Focused))
266
   *    lineEdit.setFocus();
267
   *
268
   *  result.setLayout(new WHBoxLayout());
269
   *  result.getLayout().setContentsMargins(1, 1, 1, 1);
270
   *  result.getLayout().addWidget(lineEdit);
271
   *  return result;
272
   * }
273
   * \endcode
274
   * \endif
275
   */
276
  virtual std::unique_ptr<WWidget>
277
    createEditor(const WModelIndex& index,
278
                 WFlags<ViewItemRenderFlag> flags) const;
279
280
private:
281
  WT_USTRING textFormat_;
282
283
  struct WidgetRef {
284
    std::unique_ptr<WWidget> created;
285
    WWidget *w;
286
0
    WidgetRef(WWidget *widget) : w(widget) { }
287
  };
288
289
  IndexCheckBox *checkBox(WidgetRef& w, const WModelIndex& index,
290
                         bool autoCreate, bool update = false, bool triState = false);
291
292
  IndexText *textWidget(WidgetRef& w, const WModelIndex& index);
293
  WImage *iconWidget(WidgetRef& w, const WModelIndex& index, bool autoCreate = false);
294
  IndexAnchor *anchorWidget(WidgetRef& w, const WModelIndex& index, bool autoCreate = false);
295
296
  void onCheckedChange(IndexCheckBox *checkBox) const;
297
  void doCloseEditor(WWidget *editor, bool save) const;
298
};
299
300
}
301
302
#endif // WITEMDELEGATE_H_