1 // This may look like C code, but it's really -*- C++ -*-
2 /*
3 * Copyright (C) 2008 Emweb bv, Herent, Belgium.
4 *
5 * See the LICENSE file for terms of use.
6 */
7 #ifndef WVIEWWIDGET_H_
8 #define WVIEWWIDGET_H_
9
10 #include <Wt/WWebWidget.h>
11
12 namespace Wt {
13
14 /*! \class WViewWidget Wt/WViewWidget.h Wt/WViewWidget.h
15 * \brief An abstract base class for an MVC view that is rendered using a
16 * widget.
17 *
18 * In principle, %Wt widgets are self-contained and manage both their
19 * content, behavior and layout. From the point of view of a
20 * Model-View-Controller (MVC) design pattern, they implement each of
21 * these, except for the view widgets that work in conjunction with
22 * WAbstractItemModel. As a developer you can chose to keep Model,
23 * View and Controller together or separate them as you wish.
24 *
25 * This widget facilitates separation of the View from the Model and
26 * Controller in a particular way. The %View is rendered as a %Wt
27 * widget. The use of this widget provides two benefits. The classic
28 * MVC benefit is a decoupling between view and model, which may allow
29 * easier maintainance of code. In addition, this widget enforces the
30 * View to be stateless, as it is only created transiently on the
31 * server. Therefore the View does not require session resources. This
32 * may increase scalability for Internet-deployments.
33 *
34 * The rendered View widget returned by renderView() should reflect
35 * the current model state. Whenever the model changes, rerendering
36 * can be triggered by calling update().
37 *
38 * Currently, the View cannot enclose \link WFormWidget
39 * WFormWidgets\endlink which would allow direct manipulation of the
40 * model (but we are working to remove this limitation in the future,
41 * and let the Model/Controller handle editing changes) and the View
42 * may only be updated by a complete rerendering of the entire view.
43 *
44 * The View widget may contain event handling code, but only in one of
45 * the following ways:
46 * <ul>
47 * <li>event handling implemented directly in JavaScript code</li>
48 * <li>event handling implemented in pre-learned stateless slot
49 * implementations</li>
50 * </ul>
51 * Thus, currently, event handling code related to the View cannot be
52 * implemented at server-side (but we are thinking about a solution for
53 * this as well...).
54 *
55 * \if cpp
56 * Implementation example:
57 * \code
58 * // Shows the contents for a specific role of a model index in a WText widget
59 * class SourceView : public Wt::WViewWidget
60 * {
61 * public:
62 * // role is the ItemDataRole
63 * SourceView(int role)
64 * : role_(role)
65 * { }
66 *
67 * // set an index
68 * void setIndex(const Wt::WModelIndex& index) {
69 * if (index != index_
70 * && (!index.isValid() || !index.data(role_).empty())) {
71 * index_ = index;
72 * update(); // trigger rerendering of the view
73 * }
74 * }
75 *
76 * private:
77 * Wt::WModelIndex index_;
78 * int role_;
79 *
80 * protected:
81 * virtual std::unique_ptr<Wt::WWidget> renderView() {
82 * auto result = std::make_unique<Wt::WText>();
83 * result->setInline(false);
84 *
85 * if (!index_.isValid())
86 * return result;
87 *
88 * cpp17::any d = index_.data(role_);
89 * const std::string& t = cpp17::any_cast<const std::string&>(d);
90 *
91 * result->setTextFormat(Wt::TextFormat::Plain);
92 * result->setText(t);
93 *
94 * return result;
95 * }
96 * };
97 *
98 * \endcode
99 * \endif
100 *
101 * <h3>CSS</h3>
102 *
103 * This widget does not provide styling,
104 * and can be styled using inline or external CSS as appropriate.
105 */
106 class WT_API WViewWidget : public WWebWidget
107 {
108 public:
109 /*! \brief Creates a new view widget.
110 */
111 WViewWidget();
112
113 ~WViewWidget();
114
115 /*! \brief Updates the view.
116 *
117 * Typically, the model will want to update the view when the model
118 * has changed.
119 *
120 * This will trigger a call to renderView() to ask for a new rendering of
121 * the view.
122 */
123 void update();
124
125 virtual void load() override;
126 virtual void render(WFlags<RenderFlag> flags) override;
127 virtual void refresh() override;
128
129 protected:
130 /*! \brief Creates a widget that renders the View.
131 *
132 * This method must be reimplemented to return a widget that renders the
133 * view. The returned widget will be deleted by %WViewWidget.
134 */
135 virtual std::unique_ptr<WWidget> renderView() = 0;
136
137 virtual void updateDom(DomElement& element, bool all) override;
138 virtual void propagateRenderOk(bool deep) override;
139 virtual DomElementType domElementType() const override;
140
141 virtual void doneRerender() override;
142
143 private:
144 std::unique_ptr<WWidget> contents_;
145 bool needContentsUpdate_;
146 };
147
148 /*! \class WStaticModelView Wt/WViewWidget.h Wt/WViewWidget.h
149 * \brief A widget that implements a view for a non-changing model.
150 *
151 * This model uses a function object which is passed in the
152 * constructor to render the View, and does not react to changes.
153 *
154 * You may want to use the utility function Wt::makeStaticModel() to create an
155 * instance of this class.
156 */
157 template <typename Renderer>
158 class WStaticModelView : public WViewWidget
159 {
160 public:
161 /*! \brief Creates a new static model view, given a function
162 * object to render the View widget.
163 */
WStaticModelView(Renderer f)164 WStaticModelView(Renderer f)
165 : f_(f) { }
166
167 protected:
renderView()168 std::unique_ptr<WWidget> renderView() {
169 return f_();
170 }
171
172 Renderer f_;
173 };
174
175 /*! \brief Wraps a widget into a view with a non-changing model.
176 *
177 * The ViewRenderer is called without arguments and must return a
178 * newly created widget (WWidget *).
179 *
180 * \relates WStaticModelView
181 */
182 template <typename R>
makeStaticModel(R f)183 std::unique_ptr<WStaticModelView<R> > makeStaticModel(R f)
184 {
185 return std::unique_ptr<WStaticModelView<R> >(new WStaticModelView<R>(f));
186 }
187
188 }
189
190 #endif // WVIEWWIDGET_H_
191