Skip to content

Commit 7c9c077

Browse files
YoikaGRockinRoel
authored andcommitted
Custom view to represent database objects
This class inherits from WTemplateFormView and uses the custom Dbo actions and model to initialize the view. When the custom model is set, we will use the custom Dbo ViewAction to automatically generate the default form delegates for the database columns added in the model. The user is able to override the default form delegates by using setFormDelegate. Note: they will only be able to call this method before setting the model. The user is also able to customize the widgets and validators of the default form delegates, without having to specify an entire form delegate. This can for example be useful for an integer column. The default validator is a WIntValidator. Using the customizeValidator function will allow them to set a range.
1 parent 0592088 commit 7c9c077

File tree

1 file changed

+230
-0
lines changed

1 file changed

+230
-0
lines changed

src/Wt/Form/Dbo/FormView.h

Lines changed: 230 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,230 @@
1+
// This may look like C code, but it's really -*- C++ -*-
2+
/*
3+
* Copyright (C) 2021 Emweb bv, Herent, Belgium.
4+
*
5+
* See the LICENSE file for terms of use.
6+
*/
7+
#ifndef WT_FORM_DBO_FORMVIEW_H_
8+
#define WT_FORM_DBO_FORMVIEW_H_
9+
10+
#include <Wt/WTemplateFormView.h>
11+
#include <Wt/Form/WAbstractFormDelegate.h>
12+
#include <Wt/Form/Dbo/Actions.h>
13+
#include <Wt/Form/Dbo/FormModel.h>
14+
15+
namespace Wt {
16+
namespace Form {
17+
namespace Dbo {
18+
/*! \brief A view class to represent database objects
19+
*/
20+
template<class C>
21+
class FormView : public Wt::WTemplateFormView
22+
{
23+
public:
24+
explicit FormView(const Wt::WString& text)
25+
: Wt::WTemplateFormView(text)
26+
{
27+
}
28+
29+
/*! \brief Sets the form model
30+
*
31+
* This method will automatically generate the form delegates
32+
* and set the form widgets and model validators.
33+
*/
34+
void setFormModel(std::shared_ptr<FormModel<C>> model)
35+
{
36+
model_ = model;
37+
38+
C dummy;
39+
40+
// Automatically generate the form delegates
41+
ViewAction action(model->session(), model.get(), formDelegates_);
42+
dummy.persist(action);
43+
44+
for (const Wt::WFormModel::Field& f : model->fields()) {
45+
setFormWidget(f, formWidget(f));
46+
model->setValidator(f, validator(f));
47+
}
48+
49+
updateView(model.get());
50+
}
51+
52+
/*! \brief Sets a custom form delegate
53+
*
54+
* Overrides the default delegate for a given field
55+
*
56+
* This method will throw an exception if it's called after setFormModel.
57+
*/
58+
void setFormDelegate(Wt::WFormModel::Field field, std::shared_ptr<Wt::Form::WAbstractFormDelegate> delegate)
59+
{
60+
if (model_) {
61+
throw Wt::WException("Form Delegates cannot be set after the model has been initialized!");
62+
}
63+
64+
if (!delegate) {
65+
// Erase from map
66+
auto it = formDelegates_.find(field);
67+
if (it != formDelegates_.end()) {
68+
formDelegates_.erase(it);
69+
}
70+
} else {
71+
formDelegates_[field] = std::move(delegate);
72+
}
73+
}
74+
75+
/*! \brief Updates a value in the Model
76+
*/
77+
void updateModelValue(Wt::WFormModel *model, Wt::WFormModel::Field field, Wt::WFormWidget *edit) override
78+
{
79+
if (updateModelValue(model, field, static_cast<Wt::WWidget*>(edit))) {
80+
return;
81+
}
82+
83+
std::shared_ptr<Wt::Form::WAbstractFormDelegate> d = delegate(field);
84+
if (d) {
85+
d->updateModelValue(model, field, edit);
86+
} else {
87+
Wt::WTemplateFormView::updateModelValue(model, field, edit);
88+
}
89+
}
90+
91+
/*! \brief Updates a value in the Model
92+
*/
93+
bool updateModelValue(Wt::WFormModel *model, Wt::WFormModel::Field field, Wt::WWidget *edit) override
94+
{
95+
std::shared_ptr<Wt::Form::WAbstractFormDelegate> d = delegate(field);
96+
if (d) {
97+
return d->updateModelValue(model, field, edit);
98+
} else {
99+
return Wt::WTemplateFormView::updateModelValue(model, field, edit);
100+
}
101+
}
102+
103+
/*! \brief Updates a value in the View
104+
*/
105+
void updateViewValue(Wt::WFormModel *model, Wt::WFormModel::Field field, Wt::WFormWidget *edit) override
106+
{
107+
if (updateViewValue(model, field, static_cast<Wt::WWidget*>(edit))) {
108+
return;
109+
}
110+
111+
std::shared_ptr<Wt::Form::WAbstractFormDelegate> d = delegate(field);
112+
if (d) {
113+
d->updateViewValue(model, field, edit);
114+
} else {
115+
Wt::WTemplateFormView::updateViewValue(model, field, edit);
116+
}
117+
}
118+
119+
/*! \brief Updates a value in the View
120+
*/
121+
bool updateViewValue(Wt::WFormModel *model, Wt::WFormModel::Field field, Wt::WWidget *edit) override
122+
{
123+
std::shared_ptr<Wt::Form::WAbstractFormDelegate> d = delegate(field);
124+
if (d) {
125+
return d->updateViewValue(model, field, edit);
126+
} else {
127+
return Wt::WTemplateFormView::updateViewValue(model, field, edit);
128+
}
129+
}
130+
131+
void save()
132+
{
133+
updateModel(model_.get());
134+
if (model_->validate()) {
135+
model_->saveDboValues();
136+
updateView(model_.get());
137+
saved().emit();
138+
} else {
139+
// update the view to show the validation text
140+
updateView(model_.get());
141+
validationFailed().emit();
142+
}
143+
}
144+
145+
protected:
146+
/*! \brief Customize the auto generate form widget
147+
*
148+
* Allows derived classes to customize the automatically generated widget
149+
* without having to customize an entire WFormDelegate.
150+
*
151+
* Base class implementation doesn't modify the widget
152+
*/
153+
virtual void customizeFormWidget(Wt::WFormModel::Field field, Wt::WWidget *widget)
154+
{
155+
}
156+
157+
/*! \brief Customize the auto generated validator
158+
*
159+
* Allows derived classes to customize the automatically generated validator
160+
* without having to customize an entire WFormDelegate.
161+
*
162+
* For example: the default validator for integers is a WIntValidator. This
163+
* method allows a derived class to specify the range for the validator.
164+
*
165+
* Base class implementation doesn't modify the validator
166+
*/
167+
virtual void customizeValidator(Wt::WFormModel::Field field, Wt::WValidator *validator)
168+
{
169+
}
170+
171+
/*! \brief Signal emitted when form is saved
172+
*/
173+
Wt::Signal<>& saved() { return saved_; }
174+
175+
/*! \brief Signal emitted when validation failed
176+
*
177+
* This can be emitted when saving the form. The save action
178+
* will have failed because some fields are invalid.
179+
*/
180+
Wt::Signal<>& validationFailed() { return validationFailed_; }
181+
182+
private:
183+
std::shared_ptr<FormModel<C>> model_;
184+
std::map<std::string, std::shared_ptr<Wt::Form::WAbstractFormDelegate>> formDelegates_;
185+
186+
Wt::Signal<> saved_;
187+
Wt::Signal<> validationFailed_;
188+
189+
/*! \brief Gets the widget generated by the form delegate
190+
*/
191+
std::unique_ptr<Wt::WWidget> formWidget(Wt::WFormModel::Field field)
192+
{
193+
std::shared_ptr<Wt::Form::WAbstractFormDelegate> d = delegate(field);
194+
if (d) {
195+
std::unique_ptr<Wt::WWidget> widget = d->createFormWidget();
196+
customizeFormWidget(field, widget.get());
197+
return widget;
198+
}
199+
return nullptr;
200+
}
201+
202+
/*! \brief Gets the validator generated by the form delegate
203+
*/
204+
std::shared_ptr<Wt::WValidator> validator(Wt::WFormModel::Field field)
205+
{
206+
std::shared_ptr<Wt::Form::WAbstractFormDelegate> d = delegate(field);
207+
if (d) {
208+
std::shared_ptr<Wt::WValidator> validator = d->createValidator();
209+
customizeValidator(field, validator.get());
210+
return validator;
211+
}
212+
return nullptr;
213+
}
214+
215+
/*! \brief Gets the form deleate
216+
*/
217+
std::shared_ptr<Wt::Form::WAbstractFormDelegate> delegate(Wt::WFormModel::Field field)
218+
{
219+
auto it = formDelegates_.find(field);
220+
if (it != formDelegates_.end()) {
221+
return it->second;
222+
}
223+
return nullptr;
224+
}
225+
};
226+
}
227+
}
228+
}
229+
230+
#endif // WT_FORM_DBO_FORMVIEW

0 commit comments

Comments
 (0)