Mantid
Loading...
Searching...
No Matches
UserInputValidator.cpp
Go to the documentation of this file.
1// Mantid Repository : https://github.com/mantidproject/mantid
2//
3// Copyright © 2018 ISIS Rutherford Appleton Laboratory UKRI,
4// NScD Oak Ridge National Laboratory, European Spallation Source,
5// Institut Laue - Langevin & CSNS, Institute of High Energy Physics, CAS
6// SPDX - License - Identifier: GPL - 3.0 +
12
13#include <QLabel>
14#include <QLineEdit>
15#include <QString>
16#include <QValidator>
17
18#include <algorithm>
19#include <cmath>
20
21using namespace Mantid::API;
22using namespace MantidQt::MantidWidgets;
23
24namespace // anonymous
25{
26template <typename T> void sortPair(std::pair<T, T> &pair) {
27 if (pair.first > pair.second) {
28 T temp = pair.first;
29 pair.first = pair.second;
30 pair.second = temp;
31 }
32}
33
34bool doesExistInADS(std::string const &workspaceName) {
35 return AnalysisDataService::Instance().doesExist(workspaceName);
36}
37
38std::optional<std::string> containsInvalidWorkspace(const WorkspaceGroup_const_sptr &group) {
39 if (group->isEmpty())
40 return "The group workspace " + group->getName() + " is empty.";
41
42 const auto it =
43 std::find_if(std::cbegin(*group), std::cend(*group), [](const auto &workspace) { return !workspace; });
44 if (it != std::cend(*group))
45 return "The group workspace " + group->getName() + " contains an invalid workspace.";
46 return std::nullopt;
47}
48
49} // anonymous namespace
50
52UserInputValidator::UserInputValidator() : m_errorMessages(), m_error(false) {}
53
55
67bool UserInputValidator::checkFieldIsNotEmpty(const QString &name, QLineEdit *field, QLabel *errorLabel) {
68 if (field->text().trimmed().isEmpty()) {
69 setErrorLabel(errorLabel, false);
70 addErrorMessage(name.toStdString() + " has been left blank.");
71 return false;
72 } else {
73 setErrorLabel(errorLabel, true);
74 return true;
75 }
76}
77
87bool UserInputValidator::checkFieldIsValid(const QString &errorMessage, QLineEdit *field, QLabel *errorLabel) {
88 int dummyPos = 0;
89 QString text = field->text();
90 QValidator::State fieldState = field->validator()->validate(text, dummyPos);
91
92 if (fieldState == QValidator::Acceptable) {
93 setErrorLabel(errorLabel, true);
94 return true;
95 } else {
96 setErrorLabel(errorLabel, false);
97 addErrorMessage(errorMessage.toStdString());
98 return false;
99 }
100}
101
112 if (workspaceSelector->currentText() == "") {
113 addErrorMessage("No " + name.toStdString() + " workspace has been selected.");
114 return false;
115 }
116
117 return true;
118}
119
128 if (!widget->isValid()) {
129 addErrorMessage(name.toStdString() + " file error: " + widget->getFileProblem().toStdString());
130 return false;
131 }
132
133 return true;
134}
135
145bool UserInputValidator::checkDataSelectorIsValid(const QString &name, DataSelector *widget, bool const silent,
146 bool const autoLoad) {
147 if (!widget->isValid(autoLoad)) {
148 addErrorMessage(name.toStdString() + " error: " + widget->getProblem().toStdString(), silent);
149 return false;
150 }
151
152 return true;
153}
154
162bool UserInputValidator::checkValidRange(const QString &name, std::pair<double, double> range) {
163 if (range.second == range.first) {
164 addErrorMessage(name.toStdString() + " must have a non-zero width.");
165 return false;
166 }
167
168 if (range.second < range.first) {
169 addErrorMessage("The start of " + name.toStdString() + " must be less than the end.");
170 return false;
171 }
172
173 return true;
174}
175
183bool UserInputValidator::checkRangesDontOverlap(std::pair<double, double> rangeA, std::pair<double, double> rangeB) {
184 sortPair(rangeA);
185 sortPair(rangeB);
186
187 if (!(rangeA.second < rangeB.first || rangeB.second < rangeA.first)) {
188 QString message = QString("The ranges must not overlap: [%1,%2], [%3,%4].")
189 .arg(rangeA.first)
190 .arg(rangeA.second)
191 .arg(rangeB.first)
192 .arg(rangeB.second);
193 addErrorMessage(message.toStdString());
194 return false;
195 }
196
197 return true;
198}
199
210bool UserInputValidator::checkRangeIsEnclosed(const QString &outerName, std::pair<double, double> outer,
211 const QString &innerName, std::pair<double, double> inner) {
212 sortPair(inner);
213 sortPair(outer);
214
215 if (inner.first < outer.first || inner.second > outer.second) {
216 addErrorMessage(outerName.toStdString() + " must completely enclose " + innerName.toStdString() + ".");
217 return false;
218 }
219
220 return true;
221}
222
235bool UserInputValidator::checkBins(double lower, double binWidth, double upper, double tolerance) {
236 double range = upper - lower;
237 if (range < 0) {
238 addErrorMessage("The start of a binning range must be less than the end.");
239 return false;
240 }
241 if (range == 0) {
242 addErrorMessage("Binning ranges must be non-zero.");
243 return false;
244 }
245 if (binWidth == 0) {
246 addErrorMessage("Bin width must be non-zero.");
247 return false;
248 }
249 if (binWidth < 0) {
250 addErrorMessage("Bin width must be a positive value.");
251 return false;
252 }
253
254 while (range > tolerance)
255 range -= binWidth;
256
257 if (std::abs(range) > tolerance) {
258 addErrorMessage("Bin width must allow for even splitting of the range.");
259 return false;
260 }
261
262 return true;
263}
264
274bool UserInputValidator::checkNotEqual(const QString &name, double x, double y, double tolerance) {
275 double delta = x - y;
276
277 if (std::abs(delta) <= tolerance) {
278 std::stringstream msg;
279 msg << name.toStdString() << " (" << x << ")"
280 << " should not be equal to " << y << ".";
281 addErrorMessage(msg.str());
282 return false;
283 }
284
285 return true;
286}
287
295bool UserInputValidator::checkWorkspaceExists(QString const &workspaceName, bool silent) {
296 if (workspaceName.isEmpty()) {
297 addErrorMessage("No workspace added.", silent);
298 return false;
299 }
300
301 if (!doesExistInADS(workspaceName.toStdString())) {
302 addErrorMessage(workspaceName.toStdString() + " not found.", silent);
303 return false;
304 }
305 return true;
306}
307
315bool UserInputValidator::checkWorkspaceNumberOfHistograms(QString const &workspaceName, std::size_t const &validSize) {
316 if (checkWorkspaceExists(workspaceName))
317 return checkWorkspaceNumberOfHistograms(WorkspaceUtils::getADSWorkspace(workspaceName.toStdString()), validSize);
318 return false;
319}
320
329 std::size_t const &validSize) {
330 if (workspace->getNumberHistograms() != validSize) {
331 addErrorMessage(workspace->getName() + " should contain " + std::to_string(validSize) + " spectra.");
332 return false;
333 }
334 return true;
335}
336
344bool UserInputValidator::checkWorkspaceNumberOfBins(QString const &workspaceName, std::size_t const &validSize) {
345 if (checkWorkspaceExists(workspaceName))
346 return checkWorkspaceNumberOfBins(WorkspaceUtils::getADSWorkspace(workspaceName.toStdString()), validSize);
347 return false;
348}
349
358 std::size_t const &validSize) {
359 if (workspace->x(0).size() != validSize) {
360 addErrorMessage(workspace->getName() + " should contain " + std::to_string(validSize) + " bins.");
361 return false;
362 }
363 return true;
364}
365
375bool UserInputValidator::checkWorkspaceGroupIsValid(QString const &groupName, QString const &inputType, bool silent) {
376 if (checkWorkspaceType<WorkspaceGroup>(groupName, inputType, "WorkspaceGroup", silent)) {
377 if (auto const group = WorkspaceUtils::getADSWorkspace<WorkspaceGroup>(groupName.toStdString())) {
378 if (auto const error = containsInvalidWorkspace(group)) {
379 addErrorMessage(error.value(), silent);
380 return false;
381 }
382 return true;
383 }
384 }
385 return false;
386}
387
394void UserInputValidator::addErrorMessage(const std::string &message, bool const silent) {
395 if (!silent && !m_errorMessages.contains(QString::fromStdString(message)))
396 m_errorMessages.append(QString::fromStdString(message));
397 m_error = true;
398}
399
406 if (m_errorMessages.isEmpty())
407 return "";
408
409 return "Please correct the following:\n" + m_errorMessages.join("\n").toStdString();
410}
411
418
425void UserInputValidator::setErrorLabel(QLabel *errorLabel, bool valid) {
426 // Do nothing if no error label was provided
427 if (errorLabel == nullptr)
428 return;
429
430 if (!valid) {
431 // Set the label to be red
432 QPalette palette = errorLabel->palette();
433 palette.setColor(errorLabel->foregroundRole(), Qt::red);
434 errorLabel->setPalette(palette);
435
436 errorLabel->setText("*");
437 } else {
438 errorLabel->setText("");
439 }
440
441 // Only show the label if input is invalid
442 errorLabel->setVisible(!valid);
443}
444} // namespace MantidQt::CustomInterfaces
std::string name
Definition Run.cpp:60
double error
IPeaksWorkspace_sptr workspace
double tolerance
double lower
lower and upper bounds on the multiplier, if known
double upper
This class defines a widget for file searching.
bool isValid() const
Is the input within the widget valid?
const QString & getFileProblem() const
Get file problem, empty string means no error.
bool m_error
True if there has been an error.
bool checkFileFinderWidgetIsValid(const QString &name, const FileFinderWidget *widget) override
Check that the given FileFinderWidget widget has valid files.
bool checkDataSelectorIsValid(const QString &name, DataSelector *widget, bool const silent=false, bool const autoLoad=true) override
Check that the given DataSelector widget has valid input.
bool checkWorkspaceGroupIsValid(QString const &groupName, QString const &inputType, bool silent=false) override
Checks that a workspace group contains valid matrix workspace's.
bool checkBins(double lower, double binWidth, double upper, double tolerance=0.00000001) override
Check that the given range can be split evenly into bins of the given width.
void setErrorLabel(QLabel *errorLabel, bool valid) override
Sets a validation label.
bool checkRangeIsEnclosed(const QString &outerName, std::pair< double, double > outer, const QString &innerName, std::pair< double, double > inner) override
Check that the given "outer" range completely encloses the given "inner" range.
bool checkRangesDontOverlap(std::pair< double, double > rangeA, std::pair< double, double > rangeB) override
Check that the given ranges dont overlap.
bool checkWorkspaceExists(QString const &workspaceName, bool silent=false) override
Checks that a workspace exists in the ADS.
std::string generateErrorMessage() const override
Returns an error message which contains all the error messages raised by the check functions.
bool checkFieldIsValid(const QString &errorMessage, QLineEdit *field, QLabel *errorLabel=nullptr) override
Check that the given QLineEdit field is valid as per any validators it might have.
bool checkValidRange(const QString &name, std::pair< double, double > range) override
Check that the given start and end range is valid.
bool checkNotEqual(const QString &name, double x, double y=0.0, double tolerance=0.00000001)
Checks two values are not equal.
bool checkFieldIsNotEmpty(const QString &name, QLineEdit *field, QLabel *errorLabel=nullptr) override
Check that the given QLineEdit field is not empty.
bool checkWorkspaceNumberOfHistograms(QString const &workspaceName, std::size_t const &validSize)
Checks the number of histograms in a workspace.
QStringList m_errorMessages
Any raised error messages.
void addErrorMessage(const std::string &message, bool const silent=false) override
Add a custom error message to the list.
bool checkWorkspaceNumberOfBins(QString const &workspaceName, std::size_t const &validSize)
Checks the number of bins in a workspace.
bool isAllInputValid() const override
Checks to see if all input is valid.
bool checkWorkspaceSelectorIsNotEmpty(const QString &name, WorkspaceSelector *workspaceSelector) override
Check that the given WorkspaceSelector is not empty.
This class defines a widget for selecting a workspace of file path by using a combination of two chil...
virtual bool isValid(bool const autoLoad=true)
Checks if widget is in a valid state.
QString getProblem() const
Get file problem, empty string means no error.
This class defines a widget for selecting a workspace present in the AnalysisDataService.
std::shared_ptr< T > getADSWorkspace(std::string const &workspaceName)
EXPORT_OPT_MANTIDQT_COMMON bool doesExistInADS(std::string const &workspaceName)
std::shared_ptr< const WorkspaceGroup > WorkspaceGroup_const_sptr
shared pointer to Mantid::API::WorkspaceGroup, pointer to const version
std::shared_ptr< MatrixWorkspace > MatrixWorkspace_sptr
shared pointer to the matrix workspace base class
std::string to_string(const wide_integer< Bits, Signed > &n)