File indexing completed on 2024-06-16 04:56:14

0001 /*  view/formtextinput.h
0002 
0003     This file is part of Kleopatra, the KDE keymanager
0004     SPDX-FileCopyrightText: 2022 g10 Code GmbH
0005     SPDX-FileContributor: Ingo Klöcker <dev@ingo-kloecker.de>
0006 
0007     SPDX-License-Identifier: GPL-2.0-or-later
0008 */
0009 #pragma once
0010 
0011 #include <QString>
0012 
0013 #include <memory>
0014 
0015 class QLabel;
0016 class QLineEdit;
0017 class QValidator;
0018 class QWidget;
0019 
0020 namespace Kleo
0021 {
0022 class ErrorLabel;
0023 
0024 namespace _detail
0025 {
0026 class FormTextInputBase
0027 {
0028 protected:
0029     FormTextInputBase();
0030 
0031 public:
0032     virtual ~FormTextInputBase();
0033     FormTextInputBase(const FormTextInputBase &) = delete;
0034     FormTextInputBase &operator=(const FormTextInputBase &) = delete;
0035     FormTextInputBase(FormTextInputBase &&) = delete;
0036     FormTextInputBase &operator=(FormTextInputBase &&) = delete;
0037 
0038     /**
0039      * Returns the label associated to the controlled widget. Use it to add
0040      * the label to a layout, but do not use it to set properties of the label
0041      * for which this class provides setters.
0042      */
0043     QLabel *label() const;
0044 
0045     /**
0046      * Returns the hint label associated to the controlled widget.
0047      */
0048     QLabel *hintLabel() const;
0049 
0050     /**
0051      * Returns the error label associated to the controlled widget.
0052      */
0053     ErrorLabel *errorLabel() const;
0054 
0055     /**
0056      * Sets \p text as text of the label and \p accessibleName as alternative
0057      * text for assistive tools. If \p accessibleName is empty, then \p text is
0058      * used instead. Both texts must be plain text.
0059      *
0060      * Note: If input is required, then the label is annotated appropriately.
0061      */
0062     void setLabelText(const QString &text, const QString &accessibleName = {});
0063 
0064     /**
0065      * Sets \p text as hint text for this input field and \p accessibleDescription
0066      * as alternative text for assistive tools. If \p accessibleDescription is
0067      * empty, then \p text is used instead.  Both texts must be plain text.
0068      */
0069     void setHint(const QString &text, const QString &accessibleDescription = {});
0070 
0071     /**
0072      * Marks this input field as required.
0073      */
0074     void setIsRequired(bool required);
0075 
0076     /**
0077      * Returns \c true, if this field needs to be filled out.
0078      */
0079     bool isRequired() const;
0080 
0081     /**
0082      * Sets the validator to use for validating the input.
0083      *
0084      * Note: If you wrap a QLineEdit, then do not set a validator (or an input mask)
0085      *       on it because this will break the correct displaying of the error message.
0086      */
0087     void setValidator(const std::shared_ptr<QValidator> &validator);
0088 
0089     /**
0090      * Sets \p text as error message to display if a value is required for the
0091      * input field, but if no value has been entered. If \p text is empty, then
0092      * a default message will be used. Both texts must be plain text.
0093      * The optional \p accessibleText is used as alternative text for assistive
0094      * tools.
0095      */
0096     void setValueRequiredErrorMessage(const QString &text, const QString &accessibleText = {});
0097 
0098     /**
0099      * Sets \p text as error message to display if the entered value is not accepted
0100      * by the validator. If \p text is empty, then a default message will be used.
0101      * The optional \p accessibleText is used as alternative text for assistive
0102      * tools. Both texts must be plain text.
0103      */
0104     void setInvalidEntryErrorMessage(const QString &text, const QString &accessibleText = {});
0105 
0106     /**
0107      * Sets the tool tip of the controlled widget and its associated label.
0108      */
0109     void setToolTip(const QString &toolTip);
0110 
0111     /**
0112      * Enables or disables the controlled widget and its associated label.
0113      * If the widget is disables, then the error label is hidden. Otherwise,
0114      * the error label is shown if there is an error.
0115      */
0116     void setEnabled(bool enabled);
0117 
0118     /**
0119      * Returns the currently shown error message for this input field.
0120      */
0121     QString currentError() const;
0122 
0123     /**
0124      * Returns \c true, if the input has a value. This function is used to
0125      * check required input fields for non-empty user input.
0126      * Needs to be implemented for concrete widget classes.
0127      * \sa validate
0128      */
0129     virtual bool hasValue() const = 0;
0130 
0131     /**
0132      * Returns \c true, if the input satisfies the validator.
0133      * Needs to be implemented for concrete widget classes.
0134      * \sa validate
0135      */
0136     virtual bool hasAcceptableInput() const = 0;
0137 
0138 protected:
0139     /**
0140      * Connects the slots \ref onTextChanged and \ref onEditingFinished to the
0141      * corresponding signal of the controlled widget.
0142      * Needs to be implemented for concrete widget classes.
0143      */
0144     virtual void connectWidget() = 0;
0145 
0146     /**
0147      * Sets the controlled widget and creates the associated labels.
0148      */
0149     void setWidget(QWidget *widget);
0150 
0151     /**
0152      * Returns the controlled widget.
0153      */
0154     QWidget *widget() const;
0155 
0156     /**
0157      * Validates \p text with the validator. Should be used when implementing
0158      * \ref hasAcceptableInput.
0159      */
0160     bool validate(const QString &text, int pos) const;
0161 
0162     /**
0163      * This slot needs to be connected to a signal of the controlled widget
0164      * that is emitted when the text changes like \ref QLineEdit::textChanged.
0165      * \sa connectWidget
0166      */
0167     void onTextChanged();
0168 
0169     /**
0170      * This slot needs to be connected to a signal of the controlled widget
0171      * that is emitted when the widget loses focus (or some user interaction
0172      * signals that they want to commit the entered text) like
0173      * \ref QLineEdit::editingFinished.
0174      * \sa connectWidget
0175      */
0176     void onEditingFinished();
0177 
0178 private:
0179     class Private;
0180     const std::unique_ptr<Private> d;
0181 };
0182 }
0183 
0184 /**
0185  * FormTextInput is a class for simplifying the management of text input widgets
0186  * like QLineEdit or QTextEdit with associated label and error message for usage
0187  * in form-like dialogs.
0188  *
0189  * Usage hints:
0190  * * If you wrap a QLineEdit, then do not set a validator (or an input mask)
0191  *   on it. Instead set the validator on this class.
0192  *   If you set a validator on the QLineEdit, then showing the error message
0193  *   when editing is finished does not work because QLineEdit doesn't emit the
0194  *   editingFinished() signal if the input is not acceptable.
0195  */
0196 template<class Widget>
0197 class FormTextInput : public _detail::FormTextInputBase
0198 {
0199     /**
0200      * Use \ref create to create a new instance.
0201      */
0202     FormTextInput() = default;
0203 
0204 public:
0205     /**
0206      * Creates a new instance of this class with a new instance of \p Widget.
0207      */
0208     static auto create(QWidget *parent)
0209     {
0210         std::unique_ptr<FormTextInput> self{new FormTextInput};
0211         self->setWidget(new Widget{parent});
0212         return self;
0213     }
0214 
0215     /**
0216      * Returns the controlled widget.
0217      */
0218     Widget *widget() const
0219     {
0220         return static_cast<Widget *>(FormTextInputBase::widget());
0221     }
0222 
0223     bool hasValue() const override;
0224 
0225     bool hasAcceptableInput() const override;
0226 
0227 private:
0228     void connectWidget() override;
0229 };
0230 
0231 template<>
0232 bool FormTextInput<QLineEdit>::hasValue() const;
0233 
0234 template<>
0235 bool FormTextInput<QLineEdit>::hasAcceptableInput() const;
0236 
0237 template<>
0238 void FormTextInput<QLineEdit>::connectWidget();
0239 
0240 }