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