Commit ae0c8ddf authored by Ingo Klöcker's avatar Ingo Klöcker
Browse files

Allow marking a form input as required

This adds functionality to require a text input field to be filled out.
If input is required, then this will be indicated to assistive tools.
A special error message, that is displayed, if a required field lacks
input, can be set. hasValue() can be used to check if a value has been
entered.

GnuPG-bug-id: 5916
parent 72500b4a
......@@ -44,3 +44,10 @@ QString Kleo::invalidEntryText()
"such as a form field, has an error",
"invalid entry");
}
QString Kleo::requiredText()
{
return i18nc("text for screen readers to indicate that the associated object, "
"such as a form field must be filled out",
"required");
}
......@@ -16,4 +16,5 @@ namespace Kleo
QString getAccessibleName(QObject *object);
QString getAccessibleDescription(QObject *object);
QString invalidEntryText();
QString requiredText();
}
......@@ -21,6 +21,19 @@
#include "kleopatra_debug.h"
namespace
{
auto defaultValueRequiredErrorMessage()
{
return i18n("Error: A value is required.");
}
auto defaultInvalidEntryErrorMessage()
{
return i18n("Error: The entered text is not valid.");
}
}
namespace Kleo::_detail
{
......@@ -28,12 +41,20 @@ class FormTextInputBase::Private
{
FormTextInputBase *q;
public:
enum Error
{
EntryOK,
EntryMissing, // a required entry is missing
InvalidEntry // the validator doesn't accept the entry
};
Private(FormTextInputBase *q)
: q{q}
, mErrorMessage{i18n("Error: The entered text is not valid.")}
, mValueRequiredErrorMessage{defaultValueRequiredErrorMessage()}
, mInvalidEntryErrorMessage{defaultInvalidEntryErrorMessage()}
{}
QString errorMessage() const;
QString errorMessage(Error error) const;
void updateError();
void updateAccessibleNameAndDescription();
......@@ -43,13 +64,24 @@ public:
QPointer<const QValidator> mValidator;
QString mAccessibleName;
QString mAccessibleDescription;
QString mErrorMessage;
QString mValueRequiredErrorMessage;
QString mInvalidEntryErrorMessage;
Error mError = EntryOK;
bool mRequired = false;
bool mEditingInProgress = false;
};
QString FormTextInputBase::Private::errorMessage() const
QString FormTextInputBase::Private::errorMessage(Error error) const
{
return q->hasAcceptableInput() ? QString{} : mErrorMessage;
switch (error) {
case EntryOK:
return {};
case EntryMissing:
return mValueRequiredErrorMessage;
case InvalidEntry:
return mInvalidEntryErrorMessage;
}
return {};
}
void FormTextInputBase::Private::updateError()
......@@ -57,8 +89,17 @@ void FormTextInputBase::Private::updateError()
if (!mErrorLabel) {
return;
}
if (mRequired && !q->hasValue()) {
mError = EntryMissing;
} else if (!q->hasAcceptableInput()) {
mError = InvalidEntry;
} else {
mError = EntryOK;
}
const auto currentErrorMessage = mErrorLabel->text();
const auto newErrorMessage = errorMessage();
const auto newErrorMessage = errorMessage(mError);
if (newErrorMessage == currentErrorMessage) {
return;
}
......@@ -99,8 +140,13 @@ void FormTextInputBase::Private::updateAccessibleNameAndDescription()
// screen readers say something like "invalid entry" if this state is set;
// emulate this by adding "invalid entry" to the accessible name of the input field
// and its label
const auto name = errorShown ? mAccessibleName + QLatin1String{", "} + invalidEntryText()
: mAccessibleName;
QString name = mAccessibleName;
if (mRequired) {
name += QLatin1String{", "} + requiredText();
}
if (errorShown) {
name += QLatin1String{", "} + invalidEntryText();
};
if (mLabel && mLabel->accessibleName() != name) {
mLabel->setAccessibleName(name);
}
......@@ -131,17 +177,36 @@ ErrorLabel *FormTextInputBase::errorLabel() const
return d->mErrorLabel;
}
void FormTextInputBase::setIsRequired(bool required)
{
d->mRequired = required;
}
bool FormTextInputBase::isRequired() const
{
return d->mRequired;
}
void FormTextInputBase::setValidator(const QValidator *validator)
{
d->mValidator = validator;
}
void FormTextInputBase::setErrorMessage(const QString &text)
void FormTextInputBase::setValueRequiredErrorMessage(const QString &text)
{
if (text.isEmpty()) {
d->mValueRequiredErrorMessage = defaultValueRequiredErrorMessage();
} else {
d->mValueRequiredErrorMessage = text;
}
}
void FormTextInputBase::setInvalidEntryErrorMessage(const QString &text)
{
if (text.isEmpty()) {
d->mErrorMessage = i18n("Error: The entered text is not valid.");
d->mInvalidEntryErrorMessage = defaultInvalidEntryErrorMessage();
} else {
d->mErrorMessage = text;
d->mInvalidEntryErrorMessage = text;
}
}
......@@ -219,6 +284,13 @@ void FormTextInputBase::onEditingFinished()
}
template<>
bool Kleo::FormTextInput<QLineEdit>::hasValue() const
{
const auto w = widget();
return w && !w->text().trimmed().isEmpty();
}
template<>
bool Kleo::FormTextInput<QLineEdit>::hasAcceptableInput() const
{
......
......@@ -44,6 +44,16 @@ public:
*/
ErrorLabel *errorLabel() const;
/**
* Marks this input field as required.
*/
void setIsRequired(bool required);
/**
* Returns \c true, if this field needs to be filled out.
*/
bool isRequired() const;
/**
* Sets the validator to use for validating the input.
*
......@@ -53,10 +63,17 @@ public:
void setValidator(const QValidator *validator);
/**
* Sets the error message to display. If \p text is empty, then the default
* error message will be used.
* Sets the error message to display if a value is required for this input field,
* but if no value has been entered. If \p text is empty, then a default
* message will be used.
*/
void setValueRequiredErrorMessage(const QString &text);
/**
* Sets the error message to display if the entered value is not accepted
* by the validator. If \p text is empty, then a default message will be used.
*/
void setErrorMessage(const QString &text);
void setInvalidEntryErrorMessage(const QString &text);
/**
* Sets the tool tip of the controlled widget and its associated label.
......@@ -83,6 +100,14 @@ public:
*/
void setEnabled(bool enabled);
/**
* Returns \c true, if the input has a value. This function is used to
* check required input fields for non-empty user input.
* Needs to be implemented for concrete widget classes.
* \sa validate
*/
virtual bool hasValue() const = 0;
/**
* Returns \c true, if the input satisfies the validator.
* Needs to be implemented for concrete widget classes.
......@@ -175,12 +200,17 @@ public:
return static_cast<Widget *>(FormTextInputBase::widget());
}
bool hasValue() const override;
bool hasAcceptableInput() const override;
private:
void connectWidget() override;
};
template<>
bool FormTextInput<QLineEdit>::hasValue() const;
template<>
bool FormTextInput<QLineEdit>::hasAcceptableInput() const;
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment