1 /**
2  * \file ButtonController.cpp
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author Allan Rae
7  *
8  * Full author contact details are available in file CREDITS.
9  */
10 
11 #include <config.h>
12 
13 #include "ButtonController.h"
14 
15 #include "qt_helpers.h"
16 
17 #include "support/debug.h"
18 
19 #include <QCheckBox>
20 #include <QPushButton>
21 #include <QLineEdit>
22 #include <QLabel>
23 #include <QList>
24 #include <QValidator>
25 
26 
27 namespace lyx {
28 namespace frontend {
29 
setWidgetEnabled(QWidget * obj,bool enabled)30 static void setWidgetEnabled(QWidget * obj, bool enabled)
31 {
32 	if (QLineEdit * le = qobject_cast<QLineEdit*>(obj))
33 		le->setReadOnly(!enabled);
34 	else
35 		obj->setEnabled(enabled);
36 
37 	obj->setFocusPolicy(enabled ? Qt::StrongFocus : Qt::NoFocus);
38 }
39 
40 
41 /////////////////////////////////////////////////////////////////////////
42 //
43 // CheckedLineEdit
44 //
45 /////////////////////////////////////////////////////////////////////////
46 
47 class CheckedLineEdit
48 {
49 public:
50 	CheckedLineEdit(QLineEdit * input, QWidget * label = 0);
51 	bool check() const;
52 
53 private:
54 	// non-owned
55 	QLineEdit * input_;
56 	QWidget * label_;
57 };
58 
59 
CheckedLineEdit(QLineEdit * input,QWidget * label)60 CheckedLineEdit::CheckedLineEdit(QLineEdit * input, QWidget * label)
61 	: input_(input), label_(label)
62 {}
63 
64 
check() const65 bool CheckedLineEdit::check() const
66 {
67 	QValidator const * validator = input_->validator();
68 	if (!validator)
69 		return true;
70 
71 	QString t = input_->text();
72 	int p = 0;
73 	bool const valid = validator->validate(t, p) == QValidator::Acceptable;
74 
75 	// Visual feedback.
76 	setValid(input_, valid);
77 	if (label_)
78 		setValid(label_, valid);
79 
80 	return valid;
81 }
82 
83 
84 /////////////////////////////////////////////////////////////////////////
85 //
86 // ButtonController::Private
87 //
88 /////////////////////////////////////////////////////////////////////////
89 
90 class ButtonController::Private
91 {
92 public:
93 	typedef QList<CheckedLineEdit> CheckedWidgetList;
94 
Private()95 	Private()
96 		: okay_(0), apply_(0), cancel_(0), restore_(0), auto_apply_(0),
97 			policy_(ButtonPolicy::IgnorantPolicy)
98 	{}
99 
100 	/// \return true if all CheckedWidgets are in a valid state.
checkWidgets() const101 	bool checkWidgets() const
102 	{
103 		bool valid = true;
104 		for (const CheckedLineEdit & w : checked_widgets_)
105 			valid &= w.check();
106 		return valid;
107 	}
108 
109 public:
110 	CheckedWidgetList checked_widgets_;
111 
112 	QPushButton * okay_;
113 	QPushButton * apply_;
114 	QPushButton * cancel_;
115 	QPushButton * restore_;
116 	QCheckBox * auto_apply_;
117 
118 	typedef QList<QWidget *> Widgets;
119 	Widgets read_only_;
120 
121 	ButtonPolicy policy_;
122 };
123 
124 
125 /////////////////////////////////////////////////////////////////////////
126 //
127 // ButtonController
128 //
129 /////////////////////////////////////////////////////////////////////////
130 
ButtonController()131 ButtonController::ButtonController()
132 	: d(new Private)
133 {}
134 
135 
~ButtonController()136 ButtonController::~ButtonController()
137 {
138 	delete d;
139 }
140 
141 
setPolicy(ButtonPolicy::Policy policy)142 void ButtonController::setPolicy(ButtonPolicy::Policy policy)
143 {
144 	d->policy_.setPolicy(policy);
145 }
146 
147 
ok()148 void ButtonController::ok()
149 {
150 	input(ButtonPolicy::SMI_OKAY);
151 }
152 
153 
input(ButtonPolicy::SMInput in)154 void ButtonController::input(ButtonPolicy::SMInput in)
155 {
156 	if (ButtonPolicy::SMI_NOOP == in)
157 		return;
158 	d->policy_.input(in);
159 	refresh();
160 }
161 
162 
apply()163 void ButtonController::apply()
164 {
165 	input(ButtonPolicy::SMI_APPLY);
166 }
167 
168 
autoApply()169 void ButtonController::autoApply()
170 {
171 	input(ButtonPolicy::SMI_AUTOAPPLY);
172 }
173 
174 
cancel()175 void ButtonController::cancel()
176 {
177 	input(ButtonPolicy::SMI_CANCEL);
178 }
179 
180 
restore()181 void ButtonController::restore()
182 {
183 	input(ButtonPolicy::SMI_RESTORE);
184 }
185 
186 
hide()187 void ButtonController::hide()
188 {
189 	input(ButtonPolicy::SMI_HIDE);
190 }
191 
192 
setValid(bool v)193 void ButtonController::setValid(bool v)
194 {
195 	input(v ? ButtonPolicy::SMI_VALID : ButtonPolicy::SMI_INVALID);
196 }
197 
198 
setReadOnly(bool ro)199 bool ButtonController::setReadOnly(bool ro)
200 {
201 	LYXERR(Debug::GUI, "Setting controller ro: " << ro);
202 
203 	d->policy_.input(ro ?
204 		ButtonPolicy::SMI_READ_ONLY : ButtonPolicy::SMI_READ_WRITE);
205 	// refreshReadOnly(); This will enable all widgets in dialogs, no matter if
206 	//                    they allowed to be enabled, so when you plan to
207 	//                    reenable this call, read this before:
208     // http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg128222.html
209 	refresh();
210 	return ro;
211 }
212 
213 
refresh() const214 void ButtonController::refresh() const
215 {
216 	LYXERR(Debug::GUI, "Calling BC refresh()");
217 
218 	bool const all_valid = d->checkWidgets();
219 
220 	if (d->okay_) {
221 		bool const enabled =
222 			all_valid && policy().buttonStatus(ButtonPolicy::OKAY);
223 		d->okay_->setEnabled(enabled);
224 	}
225 	if (d->apply_) {
226 		bool const enabled =
227 			all_valid && policy().buttonStatus(ButtonPolicy::APPLY);
228 		d->apply_->setEnabled(enabled);
229 	}
230 	if (d->restore_) {
231 		bool const enabled =
232 			all_valid && policy().buttonStatus(ButtonPolicy::RESTORE);
233 		d->restore_->setEnabled(enabled);
234 	}
235 	if (d->cancel_) {
236 		bool const enabled = policy().buttonStatus(ButtonPolicy::CANCEL);
237 		if (enabled)
238 			d->cancel_->setText(qt_("Cancel"));
239 		else
240 			d->cancel_->setText(qt_("Close"));
241 	}
242 	if (d->auto_apply_) {
243 		bool const enabled = policy().buttonStatus(ButtonPolicy::AUTOAPPLY);
244 		d->auto_apply_->setEnabled(enabled);
245 	}
246 
247 }
248 
249 
refreshReadOnly() const250 void ButtonController::refreshReadOnly() const
251 {
252 	if (d->read_only_.empty())
253 		return;
254 	bool const enable = !policy().isReadOnly();
255 	for(QWidget * w : d->read_only_)
256 		setWidgetEnabled(w, enable);
257 }
258 
259 
addCheckedLineEdit(QLineEdit * input,QWidget * label)260 void ButtonController::addCheckedLineEdit(QLineEdit * input, QWidget * label)
261 {
262 	d->checked_widgets_.append(CheckedLineEdit(input, label));
263 }
264 
265 
setOK(QPushButton * obj)266 void ButtonController::setOK(QPushButton * obj)
267 {
268 	d->okay_ = obj;
269 }
270 
271 
setApply(QPushButton * obj)272 void ButtonController::setApply(QPushButton * obj)
273 {
274 	d->apply_ = obj;
275 }
276 
277 
setAutoApply(QCheckBox * obj)278 void ButtonController::setAutoApply(QCheckBox * obj)
279 {
280 	d->auto_apply_ = obj;
281 }
282 
283 
setCancel(QPushButton * obj)284 void ButtonController::setCancel(QPushButton * obj)
285 {
286 	d->cancel_ = obj;
287 }
288 
289 
setRestore(QPushButton * obj)290 void ButtonController::setRestore(QPushButton * obj)
291 {
292 	d->restore_ = obj;
293 }
294 
295 
addReadOnly(QWidget * obj)296 void ButtonController::addReadOnly(QWidget * obj)
297 {
298 	d->read_only_.push_back(obj);
299 }
300 
policy() const301 ButtonPolicy const & ButtonController::policy() const
302 {
303 	return d->policy_;
304 }
305 
306 
policy()307 ButtonPolicy & ButtonController::policy()
308 {
309 	return d->policy_;
310 }
311 
312 } // namespace frontend
313 } // namespace lyx
314