KWidgetsAddons

kpassworddialog.cpp
1/*
2 This file is part of the KDE libraries
3 SPDX-FileCopyrightText: 2000 David Faure <faure@kde.org>
4 SPDX-FileCopyrightText: 2007 Olivier Goffart <ogoffart at kde.org>
5 SPDX-FileCopyrightText: 2020 Harald Sitter <sitter@kde.org>
6
7 SPDX-License-Identifier: LGPL-2.0-only
8*/
9#include "kpassworddialog.h"
10
11#include <QCheckBox>
12#include <QComboBox>
13#include <QLabel>
14#include <QLayout>
15#include <QPushButton>
16#include <QScreen>
17#include <QStyleOption>
18#include <QTimer>
19
20#include <ktitlewidget.h>
21
22#include "ui_kpassworddialog.h"
23
24/** @internal */
25class KPasswordDialogPrivate
26{
27public:
28 KPasswordDialogPrivate(KPasswordDialog *qq)
29 : q(qq)
30 {
31 }
32
33 void actuallyAccept();
34 void activated(const QString &userName);
35
36 void updateFields();
37 void init();
38
39 KPasswordDialog *const q;
40 Ui_KPasswordDialog ui;
41 QMap<QString, QString> knownLogins;
42 QComboBox *userEditCombo = nullptr;
43 QIcon icon;
45 unsigned int commentRow = 0;
46};
47
49 : QDialog(parent)
50 , d(new KPasswordDialogPrivate(this))
51{
52 setWindowTitle(tr("Password", "@title:window"));
53 setWindowIcon(QIcon::fromTheme(QStringLiteral("dialog-password"), windowIcon()));
54 d->m_flags = flags;
55 d->init();
56}
57
59
60void KPasswordDialogPrivate::updateFields()
61{
63 ui.userEdit->setReadOnly(true);
64 ui.credentialsGroup->setFocusProxy(ui.passEdit);
65 }
66 ui.domainEdit->setReadOnly((m_flags & KPasswordDialog::DomainReadOnly));
67 ui.credentialsGroup->setEnabled(!q->anonymousMode());
68}
69
70void KPasswordDialogPrivate::init()
71{
72 ui.setupUi(q);
73 ui.buttonBox->setStandardButtons(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
74 ui.errorMessage->setHidden(true);
75
76 ui.userEditContextHelpButton->hide();
77 ui.userEditContextHelpButton->setFlat(true);
78 ui.userEditContextHelpButton->setIcon(QIcon::fromTheme(QStringLiteral("help-contextual")));
79 ui.userEditContextHelpButton->setText(QString());
80 const QString description = QApplication::translate("KPasswordDialog", "Show Contextual Help");
81 ui.userEditContextHelpButton->setAccessibleName(description);
82 ui.userEditContextHelpButton->setToolTip(description);
83 QObject::connect(ui.userEditContextHelpButton, &QPushButton::released, q, [this] {
84 QEvent ev(QEvent::WhatsThis);
85 qApp->sendEvent(ui.userEdit, &ev);
86 });
87
88 // Row 4: Username field
90 ui.userEdit->setFocus();
91 ui.credentialsGroup->setFocusProxy(ui.userEdit);
92 QObject::connect(ui.userEdit, &QLineEdit::returnPressed, ui.passEdit, qOverload<>(&QWidget::setFocus));
93 } else {
94 ui.userNameLabel->hide();
95 ui.userEdit->hide();
96 ui.domainLabel->hide();
97 ui.domainEdit->hide();
98 ui.passEdit->setFocus();
99 ui.credentialsGroup->setFocusProxy(ui.passEdit);
100 ui.prompt->setText(QApplication::translate("KPasswordDialog", "Supply a password below."));
101 }
102
104 ui.anonymousRadioButton->hide();
105 ui.usePasswordButton->hide();
106 }
107
108 if (!(m_flags & KPasswordDialog::ShowDomainLine)) {
109 ui.domainLabel->hide();
110 ui.domainEdit->hide();
111 }
112
113 if (!(m_flags & KPasswordDialog::ShowKeepPassword)) {
114 ui.keepCheckBox->hide();
115 }
116
117 updateFields();
118
119 QRect desktop = q->topLevelWidget()->screen()->geometry();
120 q->setMinimumWidth(qMin(1000, qMax(q->sizeHint().width(), desktop.width() / 4)));
121 q->setIcon(QIcon::fromTheme(QStringLiteral("dialog-password")));
122}
123
125{
126 d->icon = icon;
127
128 QStyleOption option;
129 option.initFrom(this);
130 const int iconSize = style()->pixelMetric(QStyle::PM_MessageBoxIconSize, &option, this);
131 d->ui.pixmapLabel->setPixmap(icon.pixmap(iconSize));
132}
133
135{
136 return d->icon;
137}
138
140{
141 d->ui.userEdit->setText(user);
142 if (user.isEmpty()) {
143 return;
144 }
145
146 d->activated(user);
147 if (d->ui.userEdit->isVisibleTo(this)) {
148 d->ui.passEdit->setFocus();
149 }
150}
151
153{
154 return d->ui.userEdit->text();
155}
156
158{
159 return d->ui.passEdit->password();
160}
161
163{
164 d->ui.domainEdit->setText(domain);
165}
166
168{
169 return d->ui.domainEdit->text();
170}
171
173{
175 // This is an error case, but we can at least let user see what's about
176 // to happen if they proceed.
177 d->ui.anonymousRadioButton->setVisible(true);
178
179 d->ui.usePasswordButton->setVisible(true);
180 d->ui.usePasswordButton->setEnabled(false);
181 }
182
183 d->ui.anonymousRadioButton->setChecked(anonymous);
184}
185
187{
188 return d->ui.anonymousRadioButton->isChecked();
189}
190
192{
193 d->ui.keepCheckBox->setChecked(b);
194}
195
197{
198 return d->ui.keepCheckBox->isChecked();
199}
200
201void KPasswordDialog::addCommentLine(const QString &label, const QString &comment)
202{
203 int gridMarginLeft;
204 int gridMarginTop;
205 int gridMarginRight;
207 d->ui.formLayout->getContentsMargins(&gridMarginLeft, &gridMarginTop, &gridMarginRight, &gridMarginBottom);
208
209 int spacing = d->ui.formLayout->horizontalSpacing();
210 if (spacing < 0) {
211 // same inter-column spacing for all rows, see comment in qformlayout.cpp
213 }
214
215 QLabel *c = new QLabel(comment, this);
216 c->setWordWrap(true);
218
219 d->ui.formLayout->insertRow(d->commentRow, label, c);
220 ++d->commentRow;
221
222 // cycle through column 0 widgets and see the max width so we can set the minimum height of
223 // column 2 wordwrapable labels
224 int firstColumnWidth = 0;
225 for (int i = 0; i < d->ui.formLayout->rowCount(); ++i) {
226 QLayoutItem *li = d->ui.formLayout->itemAt(i, QFormLayout::LabelRole);
227 if (li) {
228 QWidget *w = li->widget();
229 if (w && !w->isHidden()) {
231 }
232 }
233 }
234 for (int i = 0; i < d->ui.formLayout->rowCount(); ++i) {
235 QLayoutItem *li = d->ui.formLayout->itemAt(i, QFormLayout::FieldRole);
236 if (li) {
237 QLabel *l = qobject_cast<QLabel *>(li->widget());
238 if (l && l->wordWrap()) {
239 auto *style = this->style();
240 const int leftMargin = style->pixelMetric(QStyle::PM_LayoutLeftMargin);
241 const int rightMargin = style->pixelMetric(QStyle::PM_LayoutRightMargin);
242 int w = sizeHint().width() - firstColumnWidth - leftMargin - rightMargin - gridMarginLeft - gridMarginRight - spacing;
243 l->setMinimumSize(w, l->heightForWidth(w));
244 }
245 }
246 }
247}
248
250{
251 d->ui.errorMessage->setText(message, KTitleWidget::ErrorMessage);
252
253 QFont bold = font();
254 bold.setBold(true);
255 switch (type) {
256 case PasswordError:
257 d->ui.passwordLabel->setFont(bold);
258 d->ui.passEdit->clear();
259 d->ui.passEdit->setFocus();
260 break;
261 case UsernameError:
262 if (d->ui.userEdit->isVisibleTo(this)) {
263 d->ui.userNameLabel->setFont(bold);
264 d->ui.userEdit->setFocus();
265 }
266 break;
267 case DomainError:
268 if (d->ui.domainEdit->isVisibleTo(this)) {
269 d->ui.domainLabel->setFont(bold);
270 d->ui.domainEdit->setFocus();
271 }
272 break;
273 case FatalError:
274 d->ui.userNameLabel->setEnabled(false);
275 d->ui.userEdit->setEnabled(false);
276 d->ui.passwordLabel->setEnabled(false);
277 d->ui.passEdit->setEnabled(false);
278 d->ui.keepCheckBox->setEnabled(false);
279 d->ui.buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false);
280 break;
281 default:
282 break;
283 }
284 adjustSize();
285}
286
288{
289 d->ui.prompt->setText(prompt);
290 d->ui.prompt->setWordWrap(true);
291 auto *style = this->style();
294 d->ui.prompt->setMinimumHeight(d->ui.prompt->heightForWidth(width() - leftMarginHint - rightMarginHint));
295}
296
298{
299 return d->ui.prompt->text();
300}
301
303{
304 d->ui.passEdit->setPassword(p);
305}
306
308{
309 d->ui.userEdit->setReadOnly(readOnly);
310
311 if (readOnly && d->ui.userEdit->hasFocus()) {
312 d->ui.passEdit->setFocus();
313 }
314}
315
317{
318 const int nr = knownLogins.count();
319 if (nr == 0) {
320 return;
321 }
322
323 if (nr == 1) {
324 d->ui.userEdit->setText(knownLogins.begin().key());
325 setPassword(knownLogins.begin().value());
326 return;
327 }
328
329 Q_ASSERT(!d->ui.userEdit->isReadOnly());
330 if (!d->userEditCombo) {
331 int row = -1;
333
334 d->ui.formLayout->getWidgetPosition(d->ui.userEdit, &row, &userEditRole);
335 d->ui.formLayout->removeWidget(d->ui.userEdit);
336 delete d->ui.userEdit;
337 d->userEditCombo = new QComboBox(d->ui.credentialsGroup);
338 d->userEditCombo->setEditable(true);
339 d->ui.userEdit = d->userEditCombo->lineEdit();
340 d->ui.userNameLabel->setBuddy(d->userEditCombo);
341 d->ui.formLayout->setWidget(row > -1 ? row : 0, userEditRole, d->userEditCombo);
342
343 setTabOrder(d->ui.userEdit, d->ui.anonymousRadioButton);
344 setTabOrder(d->ui.anonymousRadioButton, d->ui.domainEdit);
345 setTabOrder(d->ui.domainEdit, d->ui.passEdit);
346 setTabOrder(d->ui.passEdit, d->ui.keepCheckBox);
347 connect(d->ui.userEdit, &QLineEdit::returnPressed, d->ui.passEdit, qOverload<>(&QWidget::setFocus));
348 }
349
350 d->knownLogins = knownLogins;
351 d->userEditCombo->addItems(knownLogins.keys());
352 d->userEditCombo->setFocus();
353
354 connect(d->userEditCombo, &QComboBox::textActivated, this, [this](const QString &text) {
355 d->activated(text);
356 });
357}
358
359#if KWIDGETSADDONS_ENABLE_DEPRECATED_SINCE(6, 0)
360#pragma GCC diagnostic push
361#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
363{
364 d->ui.passEdit->setRevealPasswordAvailable(reveal);
365}
366
368{
369 return d->ui.passEdit->isRevealPasswordAvailable();
370}
371#pragma GCC diagnostic pop
372#endif
373
374KPassword::RevealMode KPasswordDialog::revealPasswordMode() const
375{
376 return d->ui.passEdit->revealPasswordMode();
377}
378
379void KPasswordDialog::setRevealPasswordMode(KPassword::RevealMode revealPasswordMode)
380{
381 d->ui.passEdit->setRevealPasswordMode(revealPasswordMode);
382}
383
384void KPasswordDialogPrivate::activated(const QString &userName)
385{
386 QMap<QString, QString>::ConstIterator it = knownLogins.constFind(userName);
387 if (it != knownLogins.constEnd()) {
388 q->setPassword(it.value());
389 }
390}
391
393{
394 if (!d->ui.errorMessage->isHidden()) {
395 d->ui.errorMessage->setText(QString());
396 }
397
398 // reset the font in case we had an error previously
399 if (!d->ui.passwordLabel->isHidden()) {
400 d->ui.passwordLabel->setFont(font());
401 d->ui.userNameLabel->setFont(font());
402 }
403
404 // we do this to allow the error message, if any, to go away
405 // checkPassword() may block for a period of time
406 QTimer::singleShot(0, this, [this] {
407 d->actuallyAccept();
408 });
409}
410
411void KPasswordDialogPrivate::actuallyAccept()
412{
413 if (!q->checkPassword()) {
414 return;
415 }
416
417 bool keep = ui.keepCheckBox->isVisibleTo(q) && ui.keepCheckBox->isChecked();
418 Q_EMIT q->gotPassword(q->password(), keep);
419
420 if (ui.userEdit->isVisibleTo(q)) {
421 Q_EMIT q->gotUsernameAndPassword(q->username(), q->password(), keep);
422 }
423
424 q->QDialog::accept();
425}
426
428{
429 return true;
430}
431
433{
434 return d->ui.buttonBox;
435}
436
438{
439 d->ui.userEditContextHelpButton->setVisible(true);
440 d->ui.userEdit->setWhatsThis(help);
441}
442
443#include "moc_kpassworddialog.cpp"
A dialog for requesting a password and optionally a login from the end user.
QString prompt() const
Returns the prompt.
void setDomain(const QString &)
set the default domain.
void setKeepPassword(bool b)
Check or uncheck the "keep password" checkbox.
bool anonymousMode() const
void setAnonymousMode(bool anonymous)
set anonymous mode (all other fields will be grayed out)
@ ShowAnonymousLoginCheckBox
If this flag is set, the Anonymous Login checkbox will be displayed.
@ ShowKeepPassword
If this flag is set, the "keep this password" checkbox will been shown, otherwise,...
@ UsernameReadOnly
If this flag is set, the login lineedit will be in read only mode.
@ DomainReadOnly
If this flag is set, the domain lineedit will be in read only mode.
@ ShowDomainLine
If this flag is set, there will be an additional line to let the user enter the domain.
@ ShowUsernameLine
If this flag is set, there will be an additional line to let the user enter his login.
QString password() const
Returns the password entered by the user.
QString domain() const
Returns the domain entered by the user.
void gotUsernameAndPassword(const QString &username, const QString &password, bool keep)
emitted when the dialog has been accepted, and ShowUsernameLine was set on the constructor
~KPasswordDialog() override
Destructor.
void setUsername(const QString &)
set the default username.
@ PasswordError
Incorrect password.
@ UsernameError
A problem with the user name as entered.
@ DomainError
A problem with the domain as entered.
@ FatalError
Error preventing further attempts, will result in disabling most of the interface.
bool isRevealPasswordAvailable() const
Whether the visibility trailing action in the line edit is visible.
void setPrompt(const QString &prompt)
Sets the prompt to show to the user.
void gotPassword(const QString &password, bool keep)
emitted when the dialog has been accepted
void setIcon(const QIcon &icon)
Set the icon that appears next to the prompt.
void setRevealPasswordAvailable(bool reveal)
Whether to show the visibility trailing action in the line edit.
virtual bool checkPassword()
Virtual function that can be overridden to provide password checking in derived classes.
void setPassword(const QString &password)
Presets the password.
KPasswordDialog(QWidget *parent=nullptr, const KPasswordDialogFlags &flags=KPasswordDialog::NoFlags)
create a password dialog
void addCommentLine(const QString &label, const QString &comment)
Adds a comment line to the dialog.
QDialogButtonBox * buttonBox() const
Returns the button box used in the dialog.
void setUsernameReadOnly(bool readOnly)
Sets the username field read-only and sets the focus to the password field.
void setKnownLogins(const QMap< QString, QString > &knownLogins)
Presets a number of login+password pairs that the user can choose from.
bool keepPassword() const
Determines whether supplied authorization should persist even after the application has been closed.
QString username() const
Returns the username entered by the user.
KPassword::RevealMode revealPasswordMode() const
Return when the reveal password button is visible.
void setUsernameContextHelp(const QString &help)
Sets contextual help for the username input field.
void accept() override
void setRevealPasswordMode(KPassword::RevealMode revealPasswordMode)
Set when the reveal password button will be visible.
QIcon icon() const
Returns the icon that appears next to the prompt.
void showErrorMessage(const QString &message, const ErrorType type=PasswordError)
Shows an error message in the dialog box.
@ ErrorMessage
An error message.
void textActivated(const QString &text)
QString translate(const char *context, const char *sourceText, const char *disambiguation, int n)
virtual QSize sizeHint() const const override
void setBold(bool enable)
QPixmap pixmap(QWindow *window, const QSize &size, Mode mode, State state) const const
QIcon fromTheme(const QString &name)
virtual int heightForWidth(int w) const const override
void setTextInteractionFlags(Qt::TextInteractionFlags flags)
void setWordWrap(bool on)
void returnPressed()
iterator begin()
const_iterator constEnd() const const
const_iterator constFind(const Key &key) const const
size_type count() const const
QList< Key > keys() const const
T value(const Key &key, const T &defaultValue) const const
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
T qobject_cast(QObject *object)
QString tr(const char *sourceText, const char *disambiguation, int n)
int width() const const
int width() const const
bool isEmpty() const const
PM_MessageBoxIconSize
int combinedLayoutSpacing(QSizePolicy::ControlTypes controls1, QSizePolicy::ControlTypes controls2, Qt::Orientation orientation, QStyleOption *option, QWidget *widget) const const
virtual int pixelMetric(PixelMetric metric, const QStyleOption *option, const QWidget *widget) const const=0
void initFrom(const QWidget *widget)
Horizontal
TextBrowserInteraction
QWidget * topLevelWidget() const const
void adjustSize()
bool isHidden() const const
void setMinimumSize(const QSize &)
void setMinimumWidth(int minw)
QScreen * screen() const const
void setFocus()
void setTabOrder(QWidget *first, QWidget *second)
QStyle * style() const const
void setWindowIcon(const QIcon &icon)
void setWindowTitle(const QString &)
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Tue Mar 26 2024 11:14:43 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.