/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<ViewItemRenderFlag> 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_ |