1 /*
2 * Copyright (C) 2008 Emweb bv, Herent, Belgium.
3 *
4 * See the LICENSE file for terms of use.
5 */
6
7 #include "Wt/WApplication.h"
8 #include "Wt/WBootstrap5Theme.h"
9 #include "Wt/WInPlaceEdit.h"
10 #include "Wt/WCssDecorationStyle.h"
11 #include "Wt/WContainerWidget.h"
12 #include "Wt/WPushButton.h"
13 #include "Wt/WText.h"
14 #include "Wt/WTheme.h"
15 #include "Wt/WLineEdit.h"
16
17 #include <memory>
18
19 namespace Wt {
20
WInPlaceEdit()21 WInPlaceEdit::WInPlaceEdit()
22 {
23 create();
24 }
25
WInPlaceEdit(const WString & text)26 WInPlaceEdit::WInPlaceEdit(const WString& text)
27 {
28 create();
29 setText(text);
30 }
31
WInPlaceEdit(bool buttons,const WString & text)32 WInPlaceEdit::WInPlaceEdit(bool buttons, const WString& text)
33 {
34 create();
35 setText(text);
36 setButtonsEnabled(buttons);
37 }
38
create()39 void WInPlaceEdit::create()
40 {
41 setImplementation(std::unique_ptr<WWidget>(impl_ = new WContainerWidget()));
42 setInline(true);
43
44 impl_->addWidget(std::unique_ptr<WWidget>
45 (text_ = new WText(WString::Empty, TextFormat::Plain)));
46 text_->decorationStyle().setCursor(Cursor::Arrow);
47
48 impl_->addWidget(std::unique_ptr<WWidget>(editing_ = new WContainerWidget()));
49 editing_->setInline(true);
50 editing_->hide();
51
52 editing_->addWidget(std::unique_ptr<WWidget>(edit_ = new WLineEdit()));
53 edit_->setTextSize(20);
54 save_ = nullptr;
55 cancel_ = nullptr;
56
57 /*
58 * This is stateless implementation heaven
59 */
60 text_->clicked().connect(text_, &WWidget::hide);
61 text_->clicked().connect(editing_, &WWidget::show);
62 text_->clicked().connect(edit_, &WWidget::setFocus);
63
64 edit_->enterPressed().connect(edit_, &WFormWidget::disable);
65 edit_->enterPressed().connect(this, &WInPlaceEdit::save);
66 edit_->enterPressed().preventPropagation();
67
68 edit_->escapePressed().connect(editing_, &WWidget::hide);
69 edit_->escapePressed().connect(text_, &WWidget::show);
70 edit_->escapePressed().connect(this, &WInPlaceEdit::cancel);
71 edit_->escapePressed().preventPropagation();
72
73 auto app = WApplication::instance();
74 auto bs5Theme = std::dynamic_pointer_cast<WBootstrap5Theme>(app->theme());
75
76 if (!bs5Theme) {
77 editing_->addWidget
78 (std::unique_ptr<WWidget>(buttons_ = new WContainerWidget()));
79 buttons_->setInline(true);
80
81 app->theme()->apply(this, buttons_, InPlaceEditingButtonsContainer);
82 }
83
84 setButtonsEnabled();
85 }
86
text()87 const WString& WInPlaceEdit::text() const
88 {
89 return edit_->text();
90 }
91
setText(const WString & text)92 void WInPlaceEdit::setText(const WString& text)
93 {
94 empty_ = text.empty();
95
96 if (!empty_)
97 text_->setText(text);
98 else
99 text_->setText(placeholderText());
100
101 edit_->setText(text);
102 }
103
setPlaceholderText(const WString & text)104 void WInPlaceEdit::setPlaceholderText(const WString& text)
105 {
106 placeholderText_ = text;
107
108 edit_->setPlaceholderText(text);
109 if (empty_)
110 text_->setText(text);
111 }
112
placeholderText()113 const WString& WInPlaceEdit::placeholderText() const
114 {
115 return placeholderText_;
116 }
117
save()118 void WInPlaceEdit::save()
119 {
120 editing_->hide();
121 text_->show();
122 edit_->enable();
123 if (save_)
124 save_->enable();
125 if (cancel_)
126 cancel_->enable();
127
128 bool changed
129 = empty_ ? !edit_->text().empty() : edit_->text() != text_->text();
130
131 if (changed) {
132 setText(edit_->text());
133 valueChanged().emit(edit_->text());
134 }
135 }
136
cancel()137 void WInPlaceEdit::cancel()
138 {
139 edit_->setText(empty_ ? WString::Empty : text_->text());
140 }
141
setButtonsEnabled(bool enabled)142 void WInPlaceEdit::setButtonsEnabled(bool enabled)
143 {
144 if (enabled && !save_) {
145 c2_.disconnect();
146
147 auto app = WApplication::instance();
148 auto bs5Theme = std::dynamic_pointer_cast<WBootstrap5Theme>(app->theme());
149
150 if (!bs5Theme) {
151 buttons_->addWidget
152 (std::unique_ptr<WWidget>
153 (save_ = new WPushButton(tr("Wt.WInPlaceEdit.Save"))));
154 buttons_->addWidget
155 (std::unique_ptr<WWidget>
156 (cancel_ = new WPushButton(tr("Wt.WInPlaceEdit.Cancel"))));
157 } else {
158 editing_->addWidget (std::unique_ptr<WWidget>
159 (save_ = new WPushButton(tr("Wt.WInPlaceEdit.Save"))));
160 editing_->addWidget (std::unique_ptr<WWidget>
161 (cancel_ = new WPushButton(tr("Wt.WInPlaceEdit.Cancel"))));
162 }
163
164 app->theme()->apply(this, save_, InPlaceEditingButton);
165 app->theme()->apply(this, cancel_, InPlaceEditingButton);
166
167 save_->clicked().connect(edit_, &WFormWidget::disable);
168 save_->clicked().connect(save_, &WFormWidget::disable);
169 save_->clicked().connect(cancel_, &WFormWidget::disable);
170 save_->clicked().connect(this, &WInPlaceEdit::save);
171
172 cancel_->clicked().connect(editing_, &WWidget::hide);
173 cancel_->clicked().connect(text_, &WWidget::show);
174 cancel_->clicked().connect(this, &WInPlaceEdit::cancel);
175 } else if (!enabled && save_) {
176 save_->parent()->removeWidget(save_);
177 cancel_->parent()->removeWidget(cancel_);
178 save_ = nullptr;
179 cancel_ = nullptr;
180
181 c2_ = edit_->blurred().connect(this, &WInPlaceEdit::save);
182 }
183 }
184
render(WFlags<RenderFlag> flags)185 void WInPlaceEdit::render(WFlags<RenderFlag> flags)
186 {
187 if (save_ && flags.test(RenderFlag::Full))
188 wApp->theme()->apply(this, editing_, InPlaceEditing);
189
190 WCompositeWidget::render(flags);
191 }
192 }
193