File indexing completed on 2024-04-28 03:59:11

0001 /*
0002     SPDX-FileCopyrightText: 2017 Montel Laurent <montel@kde.org>
0003     SPDX-FileCopyrightText: 2015 Elvis Angelaccio <elvis.angelaccio@kde.org>
0004 
0005     SPDX-License-Identifier: LGPL-2.0-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
0006 */
0007 
0008 #include "kpasswordlineedit.h"
0009 
0010 #include <QAction>
0011 #include <QContextMenuEvent>
0012 #include <QHBoxLayout>
0013 #include <QIcon>
0014 #include <QMenu>
0015 
0016 class KPasswordLineEditPrivate
0017 {
0018 public:
0019     KPasswordLineEditPrivate(KPasswordLineEdit *qq)
0020         : q(qq)
0021     {
0022     }
0023     void initialize();
0024     void echoModeToggled();
0025     void showToggleEchoModeAction(const QString &text);
0026     void slotCustomContextMenuRequested(const QPoint &pos);
0027 
0028     QIcon passwordIcon;
0029     QIcon visibleIcon;
0030 
0031     QLineEdit *passwordLineEdit = nullptr;
0032     QAction *toggleEchoModeAction = nullptr;
0033     bool isToggleEchoModeAvailable = true;
0034     KPassword::RevealMode revealPasswordMode = KPassword::RevealMode::OnlyNew;
0035     KPasswordLineEdit *const q;
0036 };
0037 
0038 void KPasswordLineEditPrivate::initialize()
0039 {
0040     QIcon visibilityIcon = QIcon::fromTheme(QStringLiteral("visibility"), QIcon(QStringLiteral(":/icons/visibility.svg")));
0041     toggleEchoModeAction = passwordLineEdit->addAction(visibilityIcon, QLineEdit::TrailingPosition);
0042     toggleEchoModeAction->setObjectName(QStringLiteral("visibilityAction"));
0043     toggleEchoModeAction->setVisible(false);
0044     toggleEchoModeAction->setToolTip(QObject::tr("Change the visibility of the password", "@info:tooltip"));
0045     q->connect(toggleEchoModeAction, &QAction::triggered, q, [this]() {
0046         echoModeToggled();
0047     });
0048     q->connect(passwordLineEdit, &QLineEdit::textChanged, q, [this](const QString &str) {
0049         showToggleEchoModeAction(str);
0050     });
0051 }
0052 
0053 void KPasswordLineEditPrivate::showToggleEchoModeAction(const QString &text)
0054 {
0055     if (revealPasswordMode != KPassword::RevealMode::Never) {
0056         toggleEchoModeAction->setVisible(isToggleEchoModeAvailable && (passwordLineEdit->echoMode() == QLineEdit::Normal || !text.isEmpty()));
0057     } else {
0058         toggleEchoModeAction->setVisible(false);
0059     }
0060 }
0061 
0062 void KPasswordLineEditPrivate::echoModeToggled()
0063 {
0064     if (passwordLineEdit->echoMode() == QLineEdit::Password) {
0065         passwordLineEdit->setEchoMode(QLineEdit::Normal);
0066         if (passwordIcon.isNull()) {
0067             passwordIcon = QIcon::fromTheme(QStringLiteral("hint"), QIcon(QStringLiteral(":/icons/hint.svg")));
0068         }
0069         toggleEchoModeAction->setIcon(passwordIcon);
0070     } else if (passwordLineEdit->echoMode() == QLineEdit::Normal) {
0071         if (visibleIcon.isNull()) {
0072             visibleIcon = QIcon::fromTheme(QStringLiteral("visibility"), QIcon(QStringLiteral(":/icons/visibility.svg")));
0073         }
0074         passwordLineEdit->setEchoMode(QLineEdit::Password);
0075         toggleEchoModeAction->setIcon(visibleIcon);
0076     }
0077     Q_EMIT q->echoModeChanged(passwordLineEdit->echoMode());
0078 }
0079 
0080 void KPasswordLineEditPrivate::slotCustomContextMenuRequested(const QPoint &pos)
0081 {
0082     auto popup = std::unique_ptr<QMenu>(passwordLineEdit->createStandardContextMenu());
0083     if (popup) {
0084         if (toggleEchoModeAction->isVisible()) {
0085             popup->addSeparator();
0086 
0087             toggleEchoModeAction->setText(passwordLineEdit->echoMode() == QLineEdit::Password ? QObject::tr("Show Password", "@action:inmenu")
0088                                                                                               : QObject::tr("Hide Password", "@action:inmenu"));
0089             popup->addAction(toggleEchoModeAction);
0090         }
0091         popup->exec(pos);
0092     }
0093 }
0094 
0095 KPasswordLineEdit::KPasswordLineEdit(QWidget *parent)
0096     : QWidget(parent)
0097     , d(new KPasswordLineEditPrivate(this))
0098 {
0099     QHBoxLayout *mainLayout = new QHBoxLayout(this);
0100     mainLayout->setObjectName(QStringLiteral("mainlayout"));
0101     mainLayout->setContentsMargins(0, 0, 0, 0);
0102     d->passwordLineEdit = new QLineEdit(this);
0103     d->passwordLineEdit->setObjectName(QStringLiteral("passwordlineedit"));
0104     d->passwordLineEdit->setEchoMode(QLineEdit::Password);
0105     d->passwordLineEdit->setContextMenuPolicy(Qt::CustomContextMenu);
0106     connect(d->passwordLineEdit, &QWidget::customContextMenuRequested, this, [this](const QPoint &pos) {
0107         d->slotCustomContextMenuRequested(pos);
0108     });
0109     connect(d->passwordLineEdit, &QLineEdit::textChanged, this, &KPasswordLineEdit::passwordChanged);
0110     setFocusProxy(d->passwordLineEdit);
0111     setFocusPolicy(d->passwordLineEdit->focusPolicy());
0112     mainLayout->addWidget(d->passwordLineEdit);
0113     d->initialize();
0114 }
0115 
0116 KPasswordLineEdit::~KPasswordLineEdit() = default;
0117 
0118 void KPasswordLineEdit::setPassword(const QString &password)
0119 {
0120     if (d->passwordLineEdit->text() != password) {
0121         if (d->revealPasswordMode == KPassword::RevealMode::OnlyNew) {
0122             d->isToggleEchoModeAvailable = password.isEmpty();
0123         }
0124         d->passwordLineEdit->setText(password);
0125     }
0126 }
0127 
0128 QString KPasswordLineEdit::password() const
0129 {
0130     return d->passwordLineEdit->text();
0131 }
0132 
0133 void KPasswordLineEdit::clear()
0134 {
0135     d->passwordLineEdit->clear();
0136 }
0137 
0138 void KPasswordLineEdit::setClearButtonEnabled(bool clear)
0139 {
0140     d->passwordLineEdit->setClearButtonEnabled(clear);
0141 }
0142 
0143 bool KPasswordLineEdit::isClearButtonEnabled() const
0144 {
0145     return d->passwordLineEdit->isClearButtonEnabled();
0146 }
0147 
0148 void KPasswordLineEdit::setEchoMode(QLineEdit::EchoMode mode)
0149 {
0150     d->passwordLineEdit->setEchoMode(mode);
0151 }
0152 
0153 QLineEdit::EchoMode KPasswordLineEdit::echoMode() const
0154 {
0155     return d->passwordLineEdit->echoMode();
0156 }
0157 
0158 void KPasswordLineEdit::setReadOnly(bool readOnly)
0159 {
0160     d->passwordLineEdit->setReadOnly(readOnly);
0161 }
0162 
0163 bool KPasswordLineEdit::isReadOnly() const
0164 {
0165     return d->passwordLineEdit->isReadOnly();
0166 }
0167 
0168 QLineEdit *KPasswordLineEdit::lineEdit() const
0169 {
0170     return d->passwordLineEdit;
0171 }
0172 
0173 #if KWIDGETSADDONS_ENABLE_DEPRECATED_SINCE(6, 0)
0174 void KPasswordLineEdit::setRevealPasswordAvailable(bool reveal)
0175 {
0176     d->revealPasswordMode = reveal ? KPassword::RevealMode::OnlyNew : KPassword::RevealMode::Never;
0177     d->showToggleEchoModeAction(password());
0178 }
0179 
0180 bool KPasswordLineEdit::isRevealPasswordAvailable() const
0181 {
0182     return d->revealPasswordMode != KPassword::RevealMode::Never;
0183 }
0184 #endif
0185 
0186 void KPasswordLineEdit::setRevealPasswordMode(KPassword::RevealMode mode)
0187 {
0188     d->revealPasswordMode = mode;
0189     d->showToggleEchoModeAction(password());
0190 }
0191 
0192 KPassword::RevealMode KPasswordLineEdit::revealPasswordMode() const
0193 {
0194     return d->revealPasswordMode;
0195 }
0196 
0197 QAction *KPasswordLineEdit::toggleEchoModeAction() const
0198 {
0199     return d->toggleEchoModeAction;
0200 }
0201 
0202 #include "moc_kpasswordlineedit.cpp"