Page Menu
Home
GnuPG
Search
Configure Global Search
Log In
Files
F36276704
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Size
8 KB
Subscribers
None
View Options
diff --git a/src/view/formtextinput.cpp b/src/view/formtextinput.cpp
index 8df658703..3aa0219ff 100644
--- a/src/view/formtextinput.cpp
+++ b/src/view/formtextinput.cpp
@@ -1,326 +1,329 @@
/* view/formtextinput.cpp
This file is part of Kleopatra, the KDE keymanager
SPDX-FileCopyrightText: 2022 g10 Code GmbH
SPDX-FileContributor: Ingo Klöcker <dev@ingo-kloecker.de>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "formtextinput.h"
#include "errorlabel.h"
#include "utils/accessibility.h"
#include <KLocalizedString>
#include <QLabel>
#include <QLineEdit>
#include <QPointer>
#include <QValidator>
#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
{
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}
, mValueRequiredErrorMessage{defaultValueRequiredErrorMessage()}
, mInvalidEntryErrorMessage{defaultInvalidEntryErrorMessage()}
{}
void updateLabel();
QString errorMessage(Error error) const;
void updateError();
void updateAccessibleNameAndDescription();
QPointer<QLabel> mLabel;
QPointer<QWidget> mWidget;
QPointer<ErrorLabel> mErrorLabel;
QPointer<const QValidator> mValidator;
QString mLabelText;
QString mAccessibleName;
QString mAccessibleDescription;
QString mValueRequiredErrorMessage;
QString mInvalidEntryErrorMessage;
Error mError = EntryOK;
bool mRequired = false;
bool mEditingInProgress = false;
};
void FormTextInputBase::Private::updateLabel()
{
if (!mLabel) {
return;
}
const auto text = mRequired
? i18nc("@label label text (required)", "%1 (required)", mLabelText)
: mLabelText;
mLabel->setText(text);
}
QString FormTextInputBase::Private::errorMessage(Error error) const
{
switch (error) {
case EntryOK:
return {};
case EntryMissing:
return mValueRequiredErrorMessage;
case InvalidEntry:
return mInvalidEntryErrorMessage;
}
return {};
}
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(mError);
if (newErrorMessage == currentErrorMessage) {
return;
}
if (currentErrorMessage.isEmpty() && mEditingInProgress) {
// delay showing the error message until editing is finished, so that we
// do not annoy the user with an error message while they are still
// entering the recipient;
// on the other hand, we clear the error message immediately if it does
// not apply anymore and we update the error message immediately if it
// changed
return;
}
mErrorLabel->setVisible(!newErrorMessage.isEmpty());
mErrorLabel->setText(newErrorMessage);
updateAccessibleNameAndDescription();
}
void FormTextInputBase::Private::updateAccessibleNameAndDescription()
{
// fall back to default accessible name/description if accessible name/description wasn't set explicitly
if (mAccessibleName.isEmpty()) {
mAccessibleName = getAccessibleName(mWidget);
}
if (mAccessibleDescription.isEmpty()) {
mAccessibleDescription = getAccessibleDescription(mWidget);
}
const bool errorShown = mErrorLabel && mErrorLabel->isVisible();
// Qt does not support "described-by" relations (like WCAG's "aria-describedby" relationship attribute);
// emulate this by adding the error message to the accessible description of the input field
const auto description = errorShown ? mAccessibleDescription + QLatin1String{" "} + mErrorLabel->text()
: mAccessibleDescription;
if (mWidget && mWidget->accessibleDescription() != description) {
mWidget->setAccessibleDescription(description);
}
// Qt does not support IA2's "invalid entry" state (like WCAG's "aria-invalid" state attribute);
// 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
QString name = mAccessibleName;
if (errorShown) {
name += QLatin1String{", "} + invalidEntryText();
};
if (mLabel && mLabel->accessibleName() != name) {
mLabel->setAccessibleName(name);
}
if (mWidget && mWidget->accessibleName() != name) {
mWidget->setAccessibleName(name);
}
}
FormTextInputBase::FormTextInputBase()
: d{new Private{this}}
{
}
FormTextInputBase::~FormTextInputBase() = default;
QWidget *FormTextInputBase::widget() const
{
return d->mWidget;
}
QLabel *FormTextInputBase::label() const
{
return d->mLabel;
}
ErrorLabel *FormTextInputBase::errorLabel() const
{
return d->mErrorLabel;
}
void FormTextInputBase::setLabelText(const QString &text)
{
d->mLabelText = text;
d->updateLabel();
}
void FormTextInputBase::setIsRequired(bool required)
{
d->mRequired = required;
d->updateLabel();
}
bool FormTextInputBase::isRequired() const
{
return d->mRequired;
}
void FormTextInputBase::setValidator(const QValidator *validator)
{
d->mValidator = validator;
}
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->mInvalidEntryErrorMessage = defaultInvalidEntryErrorMessage();
} else {
d->mInvalidEntryErrorMessage = text;
}
}
void FormTextInputBase::setToolTip(const QString &toolTip)
{
if (d->mLabel) {
d->mLabel->setToolTip(toolTip);
}
if (d->mWidget) {
d->mWidget->setToolTip(toolTip);
}
}
void FormTextInputBase::setAccessibleName(const QString &name)
{
d->mAccessibleName = name;
d->updateAccessibleNameAndDescription();
}
void FormTextInputBase::setAccessibleDescription(const QString &description)
{
d->mAccessibleDescription = description;
d->updateAccessibleNameAndDescription();
}
void FormTextInputBase::setWidget(QWidget *widget)
{
auto parent = widget ? widget->parentWidget() : nullptr;
d->mWidget = widget;
d->mLabel = new QLabel{parent};
+ QFont font = d->mLabel->font();
+ font.setBold(true);
+ d->mLabel->setFont(font);
d->mErrorLabel = new ErrorLabel{parent};
if (d->mLabel) {
d->mLabel->setBuddy(d->mWidget);
}
if (d->mErrorLabel) {
d->mErrorLabel->setVisible(false);
}
connectWidget();
}
void FormTextInputBase::setEnabled(bool enabled)
{
if (d->mLabel) {
d->mLabel->setEnabled(enabled);
}
if (d->mWidget) {
d->mWidget->setEnabled(enabled);
}
if (d->mErrorLabel) {
d->mErrorLabel->setVisible(enabled && !d->mErrorLabel->text().isEmpty());
}
}
bool FormTextInputBase::validate(const QString &text, int pos) const
{
QString textCopy = text;
if (d->mValidator && d->mValidator->validate(textCopy, pos) != QValidator::Acceptable)
{
return false;
}
return true;
}
void FormTextInputBase::onTextChanged()
{
d->mEditingInProgress = true;
d->updateError();
}
void FormTextInputBase::onEditingFinished()
{
d->mEditingInProgress = false;
d->updateError();
}
}
template<>
bool Kleo::FormTextInput<QLineEdit>::hasValue() const
{
const auto w = widget();
return w && !w->text().trimmed().isEmpty();
}
template<>
bool Kleo::FormTextInput<QLineEdit>::hasAcceptableInput() const
{
const auto w = widget();
return w && validate(w->text(), w->cursorPosition());
}
template<>
void Kleo::FormTextInput<QLineEdit>::connectWidget()
{
const auto w = widget();
QObject::connect(w, &QLineEdit::editingFinished,
w, [this]() { onEditingFinished(); });
QObject::connect(w, &QLineEdit::textChanged,
w, [this]() { onTextChanged(); });
}
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Sun, Feb 22, 6:51 PM (4 h, 59 m)
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
c4/51/b0df48401ce99d89b6ad89a092db
Attached To
rKLEOPATRA Kleopatra
Event Timeline
Log In to Comment