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/WContainerWidget.h"
9 #include "Wt/WIcon.h"
10 #include "Wt/WImage.h"
11 #include "Wt/WMessageBox.h"
12 #include "Wt/WPushButton.h"
13 #include "Wt/WText.h"
14 
15 namespace Wt {
16 
17 StandardButton WMessageBox::order_[] = {
18   StandardButton::Ok,
19   StandardButton::Yes,
20   StandardButton::YesAll,
21   StandardButton::Retry,
22   StandardButton::No,
23   StandardButton::NoAll,
24   StandardButton::Abort,
25   StandardButton::Ignore,
26   StandardButton::Cancel
27 };
28 
29 const char *WMessageBox::buttonText_[]
30   = { "Wt.WMessageBox.Ok", "Wt.WMessageBox.Yes", "Wt.WMessageBox.YesToAll",
31       "Wt.WMessageBox.Retry", "Wt.WMessageBox.No", "Wt.WMessageBox.NoToAll",
32       "Wt.WMessageBox.Abort", "Wt.WMessageBox.Ignore", "Wt.WMessageBox.Cancel"
33     };
34 
WMessageBox()35 WMessageBox::WMessageBox()
36   : icon_(Icon::None),
37     result_(StandardButton::None),
38     defaultButton_(nullptr),
39     escapeButton_(nullptr)
40 {
41   create();
42 }
43 
WMessageBox(const WString & caption,const WString & text,Icon icon,WFlags<StandardButton> buttons)44 WMessageBox::WMessageBox(const WString& caption, const WString& text,
45 			 Icon icon, WFlags<StandardButton> buttons)
46   : WDialog(caption),
47     icon_(Icon::None),
48     defaultButton_(nullptr),
49     escapeButton_(nullptr)
50 {
51   create();
52 
53   setText(text);
54   setIcon(icon);
55   setStandardButtons(buttons);
56 }
57 
create()58 void WMessageBox::create()
59 {
60   std::unique_ptr<WIcon> icon(iconW_ = new WIcon());
61   contents()->addWidget(std::move(icon));
62 
63   std::unique_ptr<WText> text(text_ = new WText());
64   contents()->addWidget(std::move(text));
65 
66   contents()->addStyleClass("Wt-msgbox-body");
67 
68   rejectWhenEscapePressed();
69 
70   finished().connect(this, &WMessageBox::onFinished);
71 }
72 
addButton(StandardButton result)73 WPushButton *WMessageBox::addButton(StandardButton result)
74 {
75   return addButton(standardButtonText(result), result);
76 }
77 
addButton(const WString & text,StandardButton result)78 WPushButton *WMessageBox::addButton(const WString& text, StandardButton result)
79 {
80   WPushButton *b = new WPushButton(text);
81   addButton(std::unique_ptr<WPushButton>(b), result);
82   return b;
83 }
84 
addButton(std::unique_ptr<WPushButton> button,const StandardButton result)85 void WMessageBox::addButton(std::unique_ptr<WPushButton> button,
86 			    const StandardButton result)
87 {
88   buttons_.push_back(Button());
89   buttons_.back().button = button.get();
90   buttons_.back().result = result;
91 
92   button->clicked().connect
93     (this, std::bind(&WMessageBox::onButtonClick, this, result));
94 
95   if (button->isDefault())
96     setDefaultButton(button.get());
97 
98   footer()->addWidget(std::move(button));
99 }
100 
setDefaultButton(WPushButton * button)101 void WMessageBox::setDefaultButton(WPushButton *button)
102 {
103   if (defaultButton_)
104     defaultButton_->setDefault(false);
105   defaultButton_ = button;
106   if (defaultButton_)
107     defaultButton_->setDefault(true);
108 }
109 
setDefaultButton(StandardButton button)110 void WMessageBox::setDefaultButton(StandardButton button)
111 {
112   WPushButton *b = this->button(button);
113   if (b)
114     setDefaultButton(b);
115 }
116 
setEscapeButton(WPushButton * button)117 void WMessageBox::setEscapeButton(WPushButton *button)
118 {
119   escapeButton_ = button;
120 }
121 
setEscapeButton(StandardButton button)122 void WMessageBox::setEscapeButton(StandardButton button)
123 {
124   WPushButton *b = this->button(button);
125   if (b)
126     setEscapeButton(b);
127 }
128 
setText(const WString & text)129 void WMessageBox::setText(const WString& text)
130 {
131   text_->setText(text);
132 }
133 
text()134 const WString& WMessageBox::text() const
135 {
136   return text_->text();
137 }
138 
setIcon(Icon icon)139 void WMessageBox::setIcon(Icon icon)
140 {
141   icon_ = icon;
142 
143   iconW_->toggleStyleClass("Wt-msgbox-icon", icon_ != Icon::None);
144   text_->toggleStyleClass("Wt-msgbox-text", icon_ != Icon::None);
145   iconW_->setSize(icon_ != Icon::None ? 2.5 : 1);
146 
147   switch (icon_) {
148   case Icon::None:
149     iconW_->setName(std::string());
150     break;
151   case Icon::Information:
152     iconW_->setName("info");
153     break;
154   case Icon::Warning:
155     iconW_->setName("warning");
156     break;
157   case Icon::Critical:
158     iconW_->setName("exclamation");
159     break;
160   case Icon::Question:
161     iconW_->setName("question");
162   }
163 }
164 
setStandardButtons(WFlags<StandardButton> buttons)165 void WMessageBox::setStandardButtons(WFlags<StandardButton> buttons)
166 {
167   buttons_.clear();
168   footer()->clear();
169 
170   defaultButton_ = escapeButton_ = nullptr;
171 
172   for (int i = 0; i < 9; ++i)
173     if (buttons.test(order_[i]))
174       addButton(order_[i]);
175 }
176 
standardButtons()177 WFlags<StandardButton> WMessageBox::standardButtons() const
178 {
179   WFlags<StandardButton> result;
180 
181   for (unsigned i = 0; i < buttons_.size(); ++i)
182     result |= buttons_[i].result;
183 
184   return result;
185 }
186 
buttons()187 std::vector<WPushButton *> WMessageBox::buttons() const
188 {
189   std::vector<WPushButton *> result;
190 
191   for (unsigned i = 0; i < buttons_.size(); ++i)
192     result.push_back(buttons_[i].button);
193 
194   return result;
195 }
196 
button(StandardButton b)197 WPushButton *WMessageBox::button(StandardButton b)
198 {
199   for (unsigned i = 0; i < buttons_.size(); ++i)
200     if (buttons_[i].result == b)
201       return buttons_[i].button;
202 
203   return nullptr;
204 }
205 
onButtonClick(StandardButton b)206 void WMessageBox::onButtonClick(StandardButton b)
207 {
208   result_ = b;
209   buttonClicked_.emit(b);
210 }
211 
onFinished()212 void WMessageBox::onFinished()
213 {
214   if (result() == DialogCode::Rejected) {
215     if (escapeButton_) {
216       for (unsigned i = 0; i < buttons_.size(); ++i) {
217 	if (buttons_[i].button == escapeButton_) {
218 	  onButtonClick(buttons_[i].result);
219 	  return;
220 	}
221       }
222     } else {
223       if (buttons_.size() == 1) {
224 	onButtonClick(buttons_[0].result);
225 	return;
226       } else {
227 	WPushButton *b = button(StandardButton::Cancel);
228 	if (b) {
229 	  onButtonClick(StandardButton::Cancel);
230 	  return;
231 	}
232 	b = button(StandardButton::No);
233 	if (b) {
234 	  onButtonClick(StandardButton::No);
235 	  return;
236 	}
237 
238 	onButtonClick(StandardButton::None);
239       }
240     }
241   }
242 }
243 
setHidden(bool hidden,const WAnimation & animation)244 void WMessageBox::setHidden(bool hidden, const WAnimation& animation)
245 {
246   if (!hidden) {
247     if (!defaultButton_) {
248       for (unsigned i = 0; i < buttons_.size(); ++i) {
249 	if (buttons_[i].result == StandardButton::Ok ||
250 	    buttons_[i].result == StandardButton::Yes) {
251 	  buttons_[i].button->setDefault(true);
252 	  break;
253 	}
254       }
255     }
256   }
257 
258   WDialog::setHidden(hidden, animation);
259 }
260 
show(const WString & caption,const WString & text,WFlags<StandardButton> buttons,const WAnimation & animation)261 StandardButton WMessageBox::show(const WString& caption,
262 				 const WString& text,
263 				 WFlags<StandardButton> buttons,
264 				 const WAnimation& animation)
265 {
266   WMessageBox box(caption, text, Icon::Information, buttons);
267   box.buttonClicked().connect(&box, &WMessageBox::accept);
268   box.exec(animation);
269   return box.buttonResult();
270 }
271 
standardButtonText(StandardButton button)272 WString WMessageBox::standardButtonText(StandardButton button)
273 {
274   for (unsigned i = 0; i < 9; ++i)
275     if (order_[i] == button)
276       return tr(buttonText_[i]);
277 
278   return WString::Empty;
279 }
280 
281 }
282