Newer
Older
#include "MantidQtCustomInterfaces/UserInputValidator.h"
#include <QValidator>
#include <QLineEdit>
#include <QLabel>
#include <QString>
#include <cmath>
using namespace MantidQt::MantidWidgets;
namespace // anonymous
{
template <typename T> void sortPair(std::pair<T, T> &pair) {
if (pair.first > pair.second) {
T temp = pair.first;
pair.first = pair.second;
pair.second = temp;
} // anonymous namespace
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
namespace MantidQt {
namespace CustomInterfaces {
UserInputValidator::UserInputValidator() : m_errorMessages() {}
/**
* Check that a given QLineEdit field (with given name) is not empty. If it is
* empty then the given QLabel will be set to "*" and an error will be added to
* m_errorMessages.
* Else set the label to "".
*
* @param name :: name of the field, so as to be recognised by the user
* @param field :: the field object to be checked
* @param errorLabel :: the "*" or "" label.
* @returns True if the input was valid
*/
bool UserInputValidator::checkFieldIsNotEmpty(const QString &name,
QLineEdit *field,
QLabel *errorLabel) {
if (field->text() == "") {
setErrorLabel(errorLabel, false);
m_errorMessages.append(name + " has been left blank.");
return false;
} else {
setErrorLabel(errorLabel, true);
return true;
}
}
/**
* Check that the given QLineEdit field is valid as per any validators it might
* have.
*
* @param field :: the field to be checked
* @param errorLabel :: the "" or "*" label
* @param errorMessage :: the message to log if invalid
* @returns True if the input was valid
*/
bool UserInputValidator::checkFieldIsValid(const QString &errorMessage,
QLineEdit *field,
QLabel *errorLabel) {
int dummyPos = 0;
QString text = field->text();
QValidator::State fieldState = field->validator()->validate(text, dummyPos);
if (fieldState == QValidator::Acceptable) {
setErrorLabel(errorLabel, true);
return true;
} else {
setErrorLabel(errorLabel, false);
m_errorMessages.append(errorMessage);
return false;
}
}
/**
* Check that the given WorkspaceSelector is not empty. Appends a message to
* m_errorMessages if so.
*
* @param name :: the "name" of the workspace selector, so as to be recognised
* by the user
* @param workspaceSelector :: the workspace selector to check
* @returns True if the input was valid
*/
bool UserInputValidator::checkWorkspaceSelectorIsNotEmpty(
const QString &name, WorkspaceSelector *workspaceSelector) {
if (workspaceSelector->currentText() == "") {
m_errorMessages.append("No " + name + " workspace has been selected.");
return false;
}
return true;
}
/**
* Check that the given MWRunFiles widget has valid files.
*
* @param name :: the "name" of the widget so as to be recognised by the user.
* @param widget :: the widget to check
* @returns True if the input was valid
*/
bool UserInputValidator::checkMWRunFilesIsValid(const QString &name,
MWRunFiles *widget) {
if (!widget->isValid()) {
m_errorMessages.append(name + " file error: " + widget->getFileProblem());
return false;
}
return true;
}
/**
* Check that the given DataSelector widget has valid files.
*
* @param name :: the "name" of the widget so as to be recognised by the user.
* @param widget :: the widget to check
* @returns True if the input was valid
*/
bool UserInputValidator::checkDataSelectorIsValid(const QString &name,
DataSelector *widget) {
if (!widget->isValid()) {
m_errorMessages.append(name + " error: " + widget->getProblem());
return false;
}
return true;
}
/**
* Check that the given start and end range is valid.
*
* @param name :: the name of the range
* @param range :: the range
* @returns True if the input was valid
*/
bool UserInputValidator::checkValidRange(const QString &name,
std::pair<double, double> range) {
if (range.second == range.first) {
m_errorMessages.append(name + " must have a non-zero width.");
return false;
}
if (range.second < range.first) {
m_errorMessages.append("The start of " + name +
" must be less than the end.");
return false;
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
return true;
}
/**
* Check that the given ranges dont overlap.
*
* @param rangeA :: the start of the range
* @param rangeB :: the end of the range
* @returns True if the input was valid
*/
bool
UserInputValidator::checkRangesDontOverlap(std::pair<double, double> rangeA,
std::pair<double, double> rangeB) {
sortPair(rangeA);
sortPair(rangeB);
if (!(rangeA.second < rangeB.first || rangeB.second < rangeA.first)) {
QString message = QString("The ranges must not overlap: [%1,%2], [%3,%4].")
.arg(rangeA.first)
.arg(rangeA.second)
.arg(rangeB.first)
.arg(rangeB.second);
m_errorMessages.append(message);
return false;
}
return true;
}
/**
* Check that the given "outer" range completely encloses the given "inner"
*range.
*
* @param outerName :: the end of the range
* @param outer :: pair of range bounds
* @param innerName :: the start of the range
* @param inner :: pair of range bounds
* @returns True if the input was valid
*/
bool UserInputValidator::checkRangeIsEnclosed(const QString &outerName,
std::pair<double, double> outer,
const QString &innerName,
std::pair<double, double> inner) {
sortPair(inner);
sortPair(outer);
if (inner.first < outer.first || inner.second > outer.second) {
m_errorMessages.append(outerName + " must completely enclose " + innerName +
".");
return false;
}
return true;
}
/**
* Given a range defined by lower and upper bounds, checks to see if it can be
*divided evenly into bins
* of a given width. Due to the nature of doubles, we use a tolerance value.
*
* @param lower :: the lower bound of the range
* @param binWidth :: the wdith of the bin
* @param upper :: the upper bound of the range
* @param tolerance :: the tolerance with which to judge range / bin
*suitablility
* @returns True if the input was valid
*/
bool UserInputValidator::checkBins(double lower, double binWidth, double upper,
double tolerance) {
double range = upper - lower;
if (range < 0) {
m_errorMessages.append(
"The start of a binning range must be less than the end.");
return false;
}
if (range == 0) {
m_errorMessages.append("Binning ranges must be non-zero.");
return false;
}
if (binWidth == 0) {
m_errorMessages.append("Bin width must be non-zero.");
return false;
}
if (binWidth < 0) {
m_errorMessages.append("Bin width must be a positive value.");
return false;
}
while (range > tolerance)
range -= binWidth;
if (std::abs(range) > tolerance) {
m_errorMessages.append(
"Bin width must allow for even splitting of the range.");
return false;
}
return true;
}
/**
* Checks two values are not equal.
*
* @param name Name of value
* @param x First value
* @param y Second value (defaults to zero)
* @param tolerance Tolerance to which to compare
* @return True if input was valid
*/
bool UserInputValidator::checkNotEqual(const QString &name, double x, double y,
double tolerance) {
double delta = x - y;
if (std::abs(delta) <= tolerance) {
std::stringstream msg;
msg << name.toStdString() << " (" << x << ")"
<< " should not be equal to " << y << ".";
QString msgStr = QString::fromStdString(msg.str());
m_errorMessages.append(msgStr);
return false;
}
return true;
}
/**
* Add a custom error message to the list.
*
* @param message :: the message to add to the list
*/
void UserInputValidator::addErrorMessage(const QString &message) {
m_errorMessages.append(message);
}
/**
* Generates and returns an error message which contains all the error messages
* raised by
* the check functions.
*/
QString UserInputValidator::generateErrorMessage() {
if (m_errorMessages.isEmpty())
return "";
return "Please correct the following:\n" + m_errorMessages.join("\n");
}
/**
* Checks if the user input checked is valid.
*
* @return True if all input is valid, false otherwise
*/
bool UserInputValidator::isAllInputValid() { return m_errorMessages.isEmpty(); }
/**
* Sets a validation label that is displyed next to the widget on the UI.
*
* @param errorLabel Label to change
* @param valid If the input was valid
*/
void UserInputValidator::setErrorLabel(QLabel *errorLabel, bool valid) {
// Do nothing if no error label was provided
if (errorLabel == NULL)
return;
if (!valid) {
// Set the label to be red
QPalette palette = errorLabel->palette();
palette.setColor(errorLabel->foregroundRole(), Qt::red);
errorLabel->setPalette(palette);
errorLabel->setText("*");
} else {
errorLabel->setText("");
}
// Only show the label if input is invalid
errorLabel->setVisible(!valid);
}
}