Enhance Password Editing Fields

* Remove repeat password on entry edit
* Move show/hide password and password generator buttons into the field as actions.
* Register keyboard shortcut Ctrl+H to toggle password visibility
* Register keyboard shortcut Ctrl+G to open the password generator
* Cleanup code and improve interactions between elements
* Simplify Password Generator button layout; convert advanced mode button to toggle button
* Update GUI tests

* Fixes #4120
This commit is contained in:
Jonathan White 2020-03-08 22:22:01 -04:00
parent 1d7ef5d4eb
commit fe1189ea79
20 changed files with 1459 additions and 1624 deletions

View File

@ -180,6 +180,8 @@ Files: share/icons/application/scalable/categories/preferences-other.svg
share/icons/application/scalable/actions/favicon-download.svg
share/icons/application/scalable/actions/document-open.svg
share/icons/application/scalable/actions/document-save-as.svg
share/icons/application/scalable/actions/refresh.svg
share/icons/application/scalable/actions/clipboard-text.svg
Copyright: 2019 Austin Andrews <http://templarian.com/>
License: SIL OPEN FONT LICENSE Version 1.1
Comment: Taken from Material Design icon set (https://github.com/templarian/MaterialDesign/)

View File

@ -0,0 +1 @@
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="24" height="24" viewBox="0 0 24 24"><path d="M19,3H14.82C14.25,1.44 12.53,0.64 11,1.2C10.14,1.5 9.5,2.16 9.18,3H5A2,2 0 0,0 3,5V19A2,2 0 0,0 5,21H19A2,2 0 0,0 21,19V5A2,2 0 0,0 19,3M12,3A1,1 0 0,1 13,4A1,1 0 0,1 12,5A1,1 0 0,1 11,4A1,1 0 0,1 12,3M7,7H17V5H19V19H5V5H7V7M17,11H7V9H17V11M15,15H7V13H15V15Z" /></svg>

After

Width:  |  Height:  |  Size: 553 B

View File

@ -0,0 +1 @@
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="24" height="24" viewBox="0 0 24 24"><path d="M17.65,6.35C16.2,4.9 14.21,4 12,4A8,8 0 0,0 4,12A8,8 0 0,0 12,20C15.73,20 18.84,17.45 19.73,14H17.65C16.83,16.33 14.61,18 12,18A6,6 0 0,1 6,12A6,6 0 0,1 12,6C13.66,6 15.14,6.69 16.22,7.78L13,11H20V4L17.65,6.35Z" /></svg>

After

Width:  |  Height:  |  Size: 505 B

View File

@ -56,9 +56,6 @@ DatabaseOpenWidget::DatabaseOpenWidget(QWidget* parent)
m_ui->comboKeyFile->lineEdit()->addAction(m_ui->keyFileClearIcon, QLineEdit::TrailingPosition);
m_ui->buttonTogglePassword->setIcon(filePath()->onOffIcon("actions", "password-show"));
connect(m_ui->buttonTogglePassword, SIGNAL(toggled(bool)), m_ui->editPassword, SLOT(setShowPassword(bool)));
connect(m_ui->buttonTogglePassword, SIGNAL(toggled(bool)), m_ui->editPassword, SLOT(setFocus()));
connect(m_ui->buttonBrowseFile, SIGNAL(clicked()), SLOT(browseKeyFile()));
connect(m_ui->buttonBox, SIGNAL(accepted()), SLOT(openDatabase()));
@ -166,10 +163,10 @@ void DatabaseOpenWidget::clearForms()
{
if (!m_isOpeningDatabase) {
m_ui->editPassword->setText("");
m_ui->editPassword->setShowPassword(false);
m_ui->comboKeyFile->clear();
m_ui->comboKeyFile->setEditText("");
m_ui->checkTouchID->setChecked(false);
m_ui->buttonTogglePassword->setChecked(false);
m_db.reset();
}
}
@ -195,7 +192,6 @@ void DatabaseOpenWidget::openDatabase()
}
m_ui->editPassword->setShowPassword(false);
m_ui->buttonTogglePassword->setChecked(false);
QCoreApplication::processEvents();
m_isOpeningDatabase = true;

View File

@ -2,6 +2,14 @@
<ui version="4.0">
<class>DatabaseOpenWidget</class>
<widget class="QWidget" name="DatabaseOpenWidget">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>580</width>
<height>410</height>
</rect>
</property>
<property name="accessibleName">
<string>Unlock KeePassXC Database</string>
</property>
@ -157,31 +165,14 @@
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="passwordLayout">
<item>
<widget class="PasswordEdit" name="editPassword">
<property name="accessibleName">
<string>Password field</string>
</property>
<property name="echoMode">
<enum>QLineEdit::Password</enum>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="buttonTogglePassword">
<property name="toolTip">
<string>Toggle password visibility</string>
</property>
<property name="accessibleName">
<string>Toggle password visibility</string>
</property>
<property name="checkable">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
<widget class="PasswordEdit" name="editPassword">
<property name="accessibleName">
<string>Password field</string>
</property>
<property name="echoMode">
<enum>QLineEdit::Password</enum>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer_4">
@ -612,8 +603,6 @@
</customwidget>
</customwidgets>
<tabstops>
<tabstop>editPassword</tabstop>
<tabstop>buttonTogglePassword</tabstop>
<tabstop>comboKeyFile</tabstop>
<tabstop>buttonBrowseFile</tabstop>
<tabstop>hardwareKeyLabelHelp</tabstop>

View File

@ -451,7 +451,7 @@ MainWindow::MainWindow()
connect(m_ui->actionSettings, SIGNAL(toggled(bool)), SLOT(switchToSettings(bool)));
connect(m_ui->actionPasswordGenerator, SIGNAL(toggled(bool)), SLOT(switchToPasswordGen(bool)));
connect(m_ui->passwordGeneratorWidget, SIGNAL(dialogTerminated()), SLOT(closePasswordGen()));
connect(m_ui->passwordGeneratorWidget, SIGNAL(closePasswordGenerator()), SLOT(closePasswordGen()));
connect(m_ui->welcomeWidget, SIGNAL(newDatabase()), SLOT(switchToNewDatabase()));
connect(m_ui->welcomeWidget, SIGNAL(openDatabase()), SLOT(switchToOpenDatabase()));

View File

@ -186,6 +186,15 @@
</widget>
<widget class="QWidget" name="pagePasswordGenerator">
<layout class="QVBoxLayout" name="verticalLayout_6">
<property name="leftMargin">
<number>60</number>
</property>
<property name="topMargin">
<number>30</number>
</property>
<property name="rightMargin">
<number>60</number>
</property>
<item>
<widget class="PasswordGeneratorWidget" name="passwordGeneratorWidget" native="true">
<property name="focusPolicy">
@ -193,6 +202,19 @@
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</widget>

View File

@ -20,14 +20,24 @@
#include "core/Config.h"
#include "core/FilePath.h"
#include "gui/Application.h"
#include "gui/Font.h"
#include "gui/PasswordGeneratorWidget.h"
const QColor PasswordEdit::CorrectSoFarColor = QColor(255, 205, 15);
const QColor PasswordEdit::ErrorColor = QColor(255, 125, 125);
#include <QDialog>
#include <QVBoxLayout>
namespace
{
const QColor CorrectSoFarColor(255, 205, 15);
const QColor CorrectSoFarColorDark(115, 104, 46);
const QColor ErrorColor(255, 125, 125);
const QColor ErrorColorDark(128, 45, 45);
} // namespace
PasswordEdit::PasswordEdit(QWidget* parent)
: QLineEdit(parent)
, m_basePasswordEdit(nullptr)
{
const QIcon errorIcon = filePath()->icon("status", "dialog-error");
m_errorAction = addAction(errorIcon, QLineEdit::TrailingPosition);
@ -40,70 +50,122 @@ PasswordEdit::PasswordEdit(QWidget* parent)
m_correctAction->setToolTip(tr("Passwords match so far"));
setEchoMode(QLineEdit::Password);
updateStylesheet();
// use a monospace font for the password field
QFont passwordFont = Font::fixedFont();
passwordFont.setLetterSpacing(QFont::PercentageSpacing, 110);
setFont(passwordFont);
m_toggleVisibleAction = new QAction(
filePath()->icon("actions", "password-show-off"),
tr("Toggle Password (%1)").arg(QKeySequence(Qt::CTRL + Qt::Key_H).toString(QKeySequence::NativeText)),
nullptr);
m_toggleVisibleAction->setCheckable(true);
m_toggleVisibleAction->setShortcut(Qt::CTRL + Qt::Key_H);
m_toggleVisibleAction->setShortcutContext(Qt::WidgetShortcut);
addAction(m_toggleVisibleAction, QLineEdit::TrailingPosition);
connect(m_toggleVisibleAction, &QAction::triggered, this, &PasswordEdit::setShowPassword);
m_passwordGeneratorAction = new QAction(
filePath()->icon("actions", "password-generator"),
tr("Generate Password (%1)").arg(QKeySequence(Qt::CTRL + Qt::Key_G).toString(QKeySequence::NativeText)),
nullptr);
m_passwordGeneratorAction->setShortcut(Qt::CTRL + Qt::Key_G);
m_passwordGeneratorAction->setShortcutContext(Qt::WidgetShortcut);
addAction(m_passwordGeneratorAction, QLineEdit::TrailingPosition);
m_passwordGeneratorAction->setVisible(false);
}
void PasswordEdit::enableVerifyMode(PasswordEdit* basePasswordEdit)
void PasswordEdit::setRepeatPartner(PasswordEdit* repeatEdit)
{
m_basePasswordEdit = basePasswordEdit;
m_repeatPasswordEdit = repeatEdit;
m_repeatPasswordEdit->setParentPasswordEdit(this);
updateStylesheet();
connect(this, SIGNAL(textChanged(QString)), m_repeatPasswordEdit, SLOT(autocompletePassword(QString)));
connect(this, SIGNAL(textChanged(QString)), m_repeatPasswordEdit, SLOT(updateRepeatStatus()));
connect(m_repeatPasswordEdit, SIGNAL(textChanged(QString)), m_repeatPasswordEdit, SLOT(updateRepeatStatus()));
}
connect(m_basePasswordEdit, SIGNAL(textChanged(QString)), SLOT(autocompletePassword(QString)));
connect(m_basePasswordEdit, SIGNAL(textChanged(QString)), SLOT(updateStylesheet()));
connect(this, SIGNAL(textChanged(QString)), SLOT(updateStylesheet()));
void PasswordEdit::setParentPasswordEdit(PasswordEdit* parent)
{
m_parentPasswordEdit = parent;
// Hide actions
m_toggleVisibleAction->setVisible(false);
m_passwordGeneratorAction->setVisible(false);
}
connect(m_basePasswordEdit, SIGNAL(showPasswordChanged(bool)), SLOT(setShowPassword(bool)));
void PasswordEdit::enablePasswordGenerator(bool signalOnly)
{
disconnect(m_passwordGeneratorAction);
m_passwordGeneratorAction->setVisible(true);
if (signalOnly) {
connect(m_passwordGeneratorAction, &QAction::triggered, this, &PasswordEdit::togglePasswordGenerator);
} else {
connect(m_passwordGeneratorAction, &QAction::triggered, this, &PasswordEdit::popupPasswordGenerator);
}
}
void PasswordEdit::setShowPassword(bool show)
{
setEchoMode(show ? QLineEdit::Normal : QLineEdit::Password);
// if I have a parent, I'm the child
if (m_basePasswordEdit) {
m_toggleVisibleAction->setIcon(filePath()->icon("actions", show ? "password-show-on" : "password-show-off"));
m_toggleVisibleAction->setChecked(show);
if (m_repeatPasswordEdit) {
m_repeatPasswordEdit->setEchoMode(show ? QLineEdit::Normal : QLineEdit::Password);
if (config()->get("security/passwordsrepeat").toBool()) {
setEnabled(!show);
setReadOnly(show);
setText(m_basePasswordEdit->text());
m_repeatPasswordEdit->setEnabled(!show);
m_repeatPasswordEdit->setText(text());
} else {
// This fix a bug when the QLineEdit is disabled while switching config
if (!isEnabled()) {
setEnabled(true);
setReadOnly(false);
}
m_repeatPasswordEdit->setEnabled(true);
}
}
updateStylesheet();
emit showPasswordChanged(show);
}
bool PasswordEdit::isPasswordVisible() const
{
return isEnabled();
return echoMode() == QLineEdit::Normal;
}
bool PasswordEdit::passwordsEqual() const
void PasswordEdit::popupPasswordGenerator()
{
return text() == m_basePasswordEdit->text();
auto pwGenerator = new PasswordGeneratorWidget();
QDialog pwDialog(this);
pwDialog.setWindowTitle(tr("Generate Password"));
auto layout = new QVBoxLayout();
pwDialog.setLayout(layout);
layout->addWidget(pwGenerator);
pwGenerator->setStandaloneMode(false);
pwGenerator->setPasswordVisible(isPasswordVisible());
connect(pwGenerator, SIGNAL(closePasswordGenerator()), &pwDialog, SLOT(close()));
connect(pwGenerator, SIGNAL(appliedPassword(QString)), SLOT(setText(QString)));
if (m_repeatPasswordEdit) {
connect(pwGenerator, SIGNAL(appliedPassword(QString)), m_repeatPasswordEdit, SLOT(setText(QString)));
}
pwDialog.exec();
}
void PasswordEdit::updateStylesheet()
void PasswordEdit::updateRepeatStatus()
{
const QString stylesheetTemplate("QLineEdit { background: %1; }");
static const auto stylesheetTemplate = QStringLiteral("QLineEdit { background: %1; }");
if (!m_parentPasswordEdit) {
return;
}
if (m_basePasswordEdit && !passwordsEqual()) {
bool isCorrect = true;
if (m_basePasswordEdit->text().startsWith(text())) {
setStyleSheet(stylesheetTemplate.arg(CorrectSoFarColor.name()));
} else {
setStyleSheet(stylesheetTemplate.arg(ErrorColor.name()));
isCorrect = false;
const auto otherPassword = m_parentPasswordEdit->text();
const auto password = text();
if (otherPassword != password) {
bool isCorrect = false;
QColor color = kpxcApp->isDarkTheme() ? ErrorColorDark : ErrorColor;
if (!password.isEmpty() && otherPassword.startsWith(password)) {
color = kpxcApp->isDarkTheme() ? CorrectSoFarColorDark : CorrectSoFarColor;
isCorrect = true;
}
setStyleSheet(stylesheetTemplate.arg(color.name()));
m_correctAction->setVisible(isCorrect);
m_errorAction->setVisible(!isCorrect);
} else {

View File

@ -28,29 +28,32 @@ class PasswordEdit : public QLineEdit
Q_OBJECT
public:
static const QColor CorrectSoFarColor;
static const QColor ErrorColor;
explicit PasswordEdit(QWidget* parent = nullptr);
void enableVerifyMode(PasswordEdit* baseEdit);
void enablePasswordGenerator(bool signalOnly = false);
void setRepeatPartner(PasswordEdit* repeatEdit);
bool isPasswordVisible() const;
public slots:
void setShowPassword(bool show);
void updateRepeatStatus();
signals:
void showPasswordChanged(bool show);
void togglePasswordGenerator();
private slots:
void updateStylesheet();
void autocompletePassword(const QString& password);
void popupPasswordGenerator();
void setParentPasswordEdit(PasswordEdit* parent);
private:
bool passwordsEqual() const;
QPointer<QAction> m_errorAction;
QPointer<QAction> m_correctAction;
QPointer<PasswordEdit> m_basePasswordEdit;
QPointer<QAction> m_toggleVisibleAction;
QPointer<QAction> m_passwordGeneratorAction;
QPointer<PasswordEdit> m_repeatPasswordEdit;
QPointer<PasswordEdit> m_parentPasswordEdit;
bool m_sendGeneratorSignal = false;
bool m_isRepeatPartner = false;
};
#endif // KEEPASSX_PASSWORDEDIT_H

View File

@ -27,36 +27,38 @@
#include "core/FilePath.h"
#include "core/PasswordGenerator.h"
#include "core/PasswordHealth.h"
#include "gui/Application.h"
#include "gui/Clipboard.h"
#include "gui/osutils/OSUtils.h"
PasswordGeneratorWidget::PasswordGeneratorWidget(QWidget* parent)
: QWidget(parent)
, m_updatingSpinBox(false)
, m_passwordGenerator(new PasswordGenerator())
, m_dicewareGenerator(new PassphraseGenerator())
, m_ui(new Ui::PasswordGeneratorWidget())
{
m_ui->setupUi(this);
m_ui->togglePasswordButton->setIcon(filePath()->onOffIcon("actions", "password-show"));
m_ui->buttonGenerate->setIcon(filePath()->icon("actions", "refresh"));
m_ui->buttonGenerate->setToolTip(
tr("Regenerate password (%1)").arg(m_ui->buttonGenerate->shortcut().toString(QKeySequence::NativeText)));
m_ui->buttonCopy->setIcon(filePath()->icon("actions", "clipboard-text"));
m_ui->buttonClose->setShortcut(Qt::Key_Escape);
connect(m_ui->editNewPassword, SIGNAL(textChanged(QString)), SLOT(updateButtonsEnabled(QString)));
connect(m_ui->editNewPassword, SIGNAL(textChanged(QString)), SLOT(updatePasswordStrength(QString)));
connect(m_ui->togglePasswordButton, SIGNAL(toggled(bool)), SLOT(setPasswordVisible(bool)));
connect(m_ui->buttonSimpleMode, SIGNAL(clicked()), SLOT(selectSimpleMode()));
connect(m_ui->buttonAdvancedMode, SIGNAL(clicked()), SLOT(selectAdvancedMode()));
connect(m_ui->buttonAdvancedMode, SIGNAL(toggled(bool)), SLOT(setAdvancedMode(bool)));
connect(m_ui->buttonAddHex, SIGNAL(clicked()), SLOT(excludeHexChars()));
connect(m_ui->editExcludedChars, SIGNAL(textChanged(QString)), SLOT(updateGenerator()));
connect(m_ui->buttonApply, SIGNAL(clicked()), SLOT(applyPassword()));
connect(m_ui->buttonCopy, SIGNAL(clicked()), SLOT(copyPassword()));
connect(m_ui->buttonGenerate, SIGNAL(clicked()), SLOT(regeneratePassword()));
connect(m_ui->buttonClose, SIGNAL(clicked()), SIGNAL(closePasswordGenerator()));
connect(m_ui->sliderLength, SIGNAL(valueChanged(int)), SLOT(passwordSliderMoved()));
connect(m_ui->spinBoxLength, SIGNAL(valueChanged(int)), SLOT(passwordSpinBoxChanged()));
connect(m_ui->sliderLength, SIGNAL(valueChanged(int)), SLOT(passwordLengthChanged(int)));
connect(m_ui->spinBoxLength, SIGNAL(valueChanged(int)), SLOT(passwordLengthChanged(int)));
connect(m_ui->sliderWordCount, SIGNAL(valueChanged(int)), SLOT(dicewareSliderMoved()));
connect(m_ui->spinBoxWordCount, SIGNAL(valueChanged(int)), SLOT(dicewareSpinBoxChanged()));
connect(m_ui->sliderWordCount, SIGNAL(valueChanged(int)), SLOT(passphraseLengthChanged(int)));
connect(m_ui->spinBoxWordCount, SIGNAL(valueChanged(int)), SLOT(passphraseLengthChanged(int)));
connect(m_ui->editWordSeparator, SIGNAL(textChanged(QString)), SLOT(updateGenerator()));
connect(m_ui->comboBoxWordList, SIGNAL(currentIndexChanged(int)), SLOT(updateGenerator()));
@ -100,12 +102,6 @@ PasswordGeneratorWidget::~PasswordGeneratorWidget()
{
}
void PasswordGeneratorWidget::showEvent(QShowEvent* event)
{
QWidget::showEvent(event);
reset();
}
void PasswordGeneratorWidget::loadSettings()
{
// Password config
@ -118,19 +114,13 @@ void PasswordGeneratorWidget::loadSettings()
config()->get("generator/SpecialChars", PasswordGenerator::DefaultSpecial).toBool());
m_ui->checkBoxNumbersAdv->setChecked(
config()->get("generator/Numbers", PasswordGenerator::DefaultNumbers).toBool());
m_ui->advancedBar->setVisible(
config()->get("generator/AdvancedMode", PasswordGenerator::DefaultAdvancedMode).toBool());
m_ui->excludedChars->setVisible(
config()->get("generator/AdvancedMode", PasswordGenerator::DefaultAdvancedMode).toBool());
m_ui->checkBoxExcludeAlike->setVisible(
config()->get("generator/AdvancedMode", PasswordGenerator::DefaultAdvancedMode).toBool());
m_ui->checkBoxEnsureEvery->setVisible(
config()->get("generator/AdvancedMode", PasswordGenerator::DefaultAdvancedMode).toBool());
m_ui->editExcludedChars->setText(
config()->get("generator/ExcludedChars", PasswordGenerator::DefaultExcludedChars).toString());
m_ui->simpleBar->setVisible(
!(config()->get("generator/AdvancedMode", PasswordGenerator::DefaultAdvancedMode).toBool()));
m_ui->buttonAdvancedMode->setChecked(
config()->get("generator/AdvancedMode", PasswordGenerator::DefaultAdvancedMode).toBool());
setAdvancedMode(m_ui->buttonAdvancedMode->isChecked());
m_ui->checkBoxBraces->setChecked(config()->get("generator/Braces", PasswordGenerator::DefaultBraces).toBool());
m_ui->checkBoxQuotes->setChecked(config()->get("generator/Quotes", PasswordGenerator::DefaultQuotes).toBool());
m_ui->checkBoxPunctuation->setChecked(
@ -174,7 +164,7 @@ void PasswordGeneratorWidget::saveSettings()
config()->set("generator/Numbers", m_ui->checkBoxNumbersAdv->isChecked());
config()->set("generator/EASCII", m_ui->checkBoxExtASCIIAdv->isChecked());
}
config()->set("generator/AdvancedMode", m_ui->advancedBar->isVisible());
config()->set("generator/AdvancedMode", m_ui->buttonAdvancedMode->isChecked());
config()->set("generator/SpecialChars", m_ui->checkBoxSpecialChars->isChecked());
config()->set("generator/Braces", m_ui->checkBoxBraces->isChecked());
config()->set("generator/Punctuation", m_ui->checkBoxPunctuation->isChecked());
@ -215,10 +205,10 @@ void PasswordGeneratorWidget::setStandaloneMode(bool standalone)
{
m_standalone = standalone;
if (standalone) {
m_ui->buttonApply->setText(tr("Close"));
m_ui->buttonApply->setVisible(false);
setPasswordVisible(true);
} else {
m_ui->buttonApply->setText(tr("Accept"));
m_ui->buttonApply->setVisible(true);
}
}
@ -230,7 +220,7 @@ QString PasswordGeneratorWidget::getGeneratedPassword()
void PasswordGeneratorWidget::keyPressEvent(QKeyEvent* e)
{
if (e->key() == Qt::Key_Escape && m_standalone) {
emit dialogTerminated();
emit closePasswordGenerator();
} else {
e->ignore();
}
@ -280,7 +270,7 @@ void PasswordGeneratorWidget::applyPassword()
{
saveSettings();
emit appliedPassword(m_ui->editNewPassword->text());
emit dialogTerminated();
emit closePasswordGenerator();
}
void PasswordGeneratorWidget::copyPassword()
@ -288,43 +278,30 @@ void PasswordGeneratorWidget::copyPassword()
clipboard()->setText(m_ui->editNewPassword->text());
}
void PasswordGeneratorWidget::passwordSliderMoved()
void PasswordGeneratorWidget::passwordLengthChanged(int length)
{
if (m_updatingSpinBox) {
return;
}
m_ui->spinBoxLength->blockSignals(true);
m_ui->sliderLength->blockSignals(true);
m_ui->spinBoxLength->setValue(m_ui->sliderLength->value());
m_ui->spinBoxLength->setValue(length);
m_ui->sliderLength->setValue(length);
m_ui->spinBoxLength->blockSignals(false);
m_ui->sliderLength->blockSignals(false);
updateGenerator();
}
void PasswordGeneratorWidget::passwordSpinBoxChanged()
void PasswordGeneratorWidget::passphraseLengthChanged(int length)
{
if (m_updatingSpinBox) {
return;
}
m_ui->spinBoxWordCount->blockSignals(true);
m_ui->sliderWordCount->blockSignals(true);
// Interlock so that we don't update twice - this causes issues as the spinbox can go higher than slider
m_updatingSpinBox = true;
m_ui->spinBoxWordCount->setValue(length);
m_ui->sliderWordCount->setValue(length);
m_ui->sliderLength->setValue(m_ui->spinBoxLength->value());
m_updatingSpinBox = false;
updateGenerator();
}
void PasswordGeneratorWidget::dicewareSliderMoved()
{
m_ui->spinBoxWordCount->setValue(m_ui->sliderWordCount->value());
updateGenerator();
}
void PasswordGeneratorWidget::dicewareSpinBoxChanged()
{
m_ui->sliderWordCount->setValue(m_ui->spinBoxWordCount->value());
m_ui->spinBoxWordCount->blockSignals(false);
m_ui->sliderWordCount->blockSignals(false);
updateGenerator();
}
@ -332,49 +309,46 @@ void PasswordGeneratorWidget::dicewareSpinBoxChanged()
void PasswordGeneratorWidget::setPasswordVisible(bool visible)
{
m_ui->editNewPassword->setShowPassword(visible);
bool blockSignals = m_ui->togglePasswordButton->blockSignals(true);
m_ui->togglePasswordButton->setChecked(visible);
m_ui->togglePasswordButton->blockSignals(blockSignals);
}
bool PasswordGeneratorWidget::isPasswordVisible() const
{
return m_ui->togglePasswordButton->isChecked();
return m_ui->editNewPassword->isPasswordVisible();
}
void PasswordGeneratorWidget::selectSimpleMode()
void PasswordGeneratorWidget::setAdvancedMode(bool state)
{
m_ui->advancedBar->hide();
m_ui->excludedChars->hide();
m_ui->checkBoxExcludeAlike->hide();
m_ui->checkBoxEnsureEvery->hide();
m_ui->checkBoxUpper->setChecked(m_ui->checkBoxUpperAdv->isChecked());
m_ui->checkBoxLower->setChecked(m_ui->checkBoxLowerAdv->isChecked());
m_ui->checkBoxNumbers->setChecked(m_ui->checkBoxNumbersAdv->isChecked());
m_ui->checkBoxSpecialChars->setChecked(m_ui->checkBoxBraces->isChecked() | m_ui->checkBoxPunctuation->isChecked()
| m_ui->checkBoxQuotes->isChecked() | m_ui->checkBoxMath->isChecked()
| m_ui->checkBoxDashes->isChecked() | m_ui->checkBoxLogograms->isChecked());
m_ui->checkBoxExtASCII->setChecked(m_ui->checkBoxExtASCIIAdv->isChecked());
m_ui->simpleBar->show();
}
void PasswordGeneratorWidget::selectAdvancedMode()
{
m_ui->simpleBar->hide();
m_ui->checkBoxUpperAdv->setChecked(m_ui->checkBoxUpper->isChecked());
m_ui->checkBoxLowerAdv->setChecked(m_ui->checkBoxLower->isChecked());
m_ui->checkBoxNumbersAdv->setChecked(m_ui->checkBoxNumbers->isChecked());
m_ui->checkBoxBraces->setChecked(m_ui->checkBoxSpecialChars->isChecked());
m_ui->checkBoxPunctuation->setChecked(m_ui->checkBoxSpecialChars->isChecked());
m_ui->checkBoxQuotes->setChecked(m_ui->checkBoxSpecialChars->isChecked());
m_ui->checkBoxMath->setChecked(m_ui->checkBoxSpecialChars->isChecked());
m_ui->checkBoxDashes->setChecked(m_ui->checkBoxSpecialChars->isChecked());
m_ui->checkBoxLogograms->setChecked(m_ui->checkBoxSpecialChars->isChecked());
m_ui->checkBoxExtASCIIAdv->setChecked(m_ui->checkBoxExtASCII->isChecked());
m_ui->advancedBar->show();
m_ui->excludedChars->show();
m_ui->checkBoxExcludeAlike->show();
m_ui->checkBoxEnsureEvery->show();
if (state) {
m_ui->simpleBar->hide();
m_ui->checkBoxUpperAdv->setChecked(m_ui->checkBoxUpper->isChecked());
m_ui->checkBoxLowerAdv->setChecked(m_ui->checkBoxLower->isChecked());
m_ui->checkBoxNumbersAdv->setChecked(m_ui->checkBoxNumbers->isChecked());
m_ui->checkBoxBraces->setChecked(m_ui->checkBoxSpecialChars->isChecked());
m_ui->checkBoxPunctuation->setChecked(m_ui->checkBoxSpecialChars->isChecked());
m_ui->checkBoxQuotes->setChecked(m_ui->checkBoxSpecialChars->isChecked());
m_ui->checkBoxMath->setChecked(m_ui->checkBoxSpecialChars->isChecked());
m_ui->checkBoxDashes->setChecked(m_ui->checkBoxSpecialChars->isChecked());
m_ui->checkBoxLogograms->setChecked(m_ui->checkBoxSpecialChars->isChecked());
m_ui->checkBoxExtASCIIAdv->setChecked(m_ui->checkBoxExtASCII->isChecked());
m_ui->advancedBar->show();
m_ui->excludedChars->show();
m_ui->checkBoxExcludeAlike->show();
m_ui->checkBoxEnsureEvery->show();
} else {
m_ui->advancedBar->hide();
m_ui->excludedChars->hide();
m_ui->checkBoxExcludeAlike->hide();
m_ui->checkBoxEnsureEvery->hide();
m_ui->checkBoxUpper->setChecked(m_ui->checkBoxUpperAdv->isChecked());
m_ui->checkBoxLower->setChecked(m_ui->checkBoxLowerAdv->isChecked());
m_ui->checkBoxNumbers->setChecked(m_ui->checkBoxNumbersAdv->isChecked());
m_ui->checkBoxSpecialChars->setChecked(
m_ui->checkBoxBraces->isChecked() | m_ui->checkBoxPunctuation->isChecked()
| m_ui->checkBoxQuotes->isChecked() | m_ui->checkBoxMath->isChecked() | m_ui->checkBoxDashes->isChecked()
| m_ui->checkBoxLogograms->isChecked());
m_ui->checkBoxExtASCII->setChecked(m_ui->checkBoxExtASCIIAdv->isChecked());
m_ui->simpleBar->show();
}
}
void PasswordGeneratorWidget::excludeHexChars()
@ -392,7 +366,7 @@ void PasswordGeneratorWidget::colorStrengthIndicator(const PasswordHealth& healt
// Set the color and background based on entropy
QList<QString> qualityColors;
if (osUtils->isDarkMode()) {
if (kpxcApp->isDarkTheme()) {
qualityColors << QStringLiteral("#C43F31") << QStringLiteral("#DB9837") << QStringLiteral("#608A22")
<< QStringLiteral("#1F8023");
} else {
@ -496,12 +470,14 @@ PasswordGenerator::GeneratorFlags PasswordGeneratorWidget::generatorFlags()
{
PasswordGenerator::GeneratorFlags flags;
if (m_ui->checkBoxExcludeAlike->isChecked()) {
flags |= PasswordGenerator::ExcludeLookAlike;
}
if (m_ui->buttonAdvancedMode->isChecked()) {
if (m_ui->checkBoxExcludeAlike->isChecked()) {
flags |= PasswordGenerator::ExcludeLookAlike;
}
if (m_ui->checkBoxEnsureEvery->isChecked()) {
flags |= PasswordGenerator::CharFromEveryGroup;
if (m_ui->checkBoxEnsureEvery->isChecked()) {
flags |= PasswordGenerator::CharFromEveryGroup;
}
}
return flags;
@ -510,62 +486,52 @@ PasswordGenerator::GeneratorFlags PasswordGeneratorWidget::generatorFlags()
void PasswordGeneratorWidget::updateGenerator()
{
if (m_ui->tabWidget->currentIndex() == Password) {
PasswordGenerator::CharClasses classes = charClasses();
PasswordGenerator::GeneratorFlags flags = generatorFlags();
auto classes = charClasses();
auto flags = generatorFlags();
int minLength = 0;
int length = 0;
if (flags.testFlag(PasswordGenerator::CharFromEveryGroup)) {
if (classes.testFlag(PasswordGenerator::LowerLetters)) {
minLength++;
++length;
}
if (classes.testFlag(PasswordGenerator::UpperLetters)) {
minLength++;
++length;
}
if (classes.testFlag(PasswordGenerator::Numbers)) {
minLength++;
++length;
}
if (classes.testFlag(PasswordGenerator::Braces)) {
minLength++;
++length;
}
if (classes.testFlag(PasswordGenerator::Punctuation)) {
minLength++;
++length;
}
if (classes.testFlag(PasswordGenerator::Quotes)) {
minLength++;
++length;
}
if (classes.testFlag(PasswordGenerator::Dashes)) {
minLength++;
++length;
}
if (classes.testFlag(PasswordGenerator::Math)) {
minLength++;
++length;
}
if (classes.testFlag(PasswordGenerator::Logograms)) {
minLength++;
++length;
}
if (classes.testFlag(PasswordGenerator::EASCII)) {
minLength++;
++length;
}
}
minLength = qMax(minLength, 1);
if (m_ui->spinBoxLength->value() < minLength) {
m_updatingSpinBox = true;
m_ui->spinBoxLength->setValue(minLength);
m_ui->sliderLength->setValue(minLength);
m_updatingSpinBox = false;
}
m_ui->spinBoxLength->setMinimum(minLength);
m_ui->sliderLength->setMinimum(minLength);
m_passwordGenerator->setLength(m_ui->spinBoxLength->value());
length = qMax(length, m_ui->spinBoxLength->value());
m_passwordGenerator->setLength(length);
m_passwordGenerator->setCharClasses(classes);
if (m_ui->simpleBar->isVisible()) {
m_passwordGenerator->setExcludedChars("");
} else {
m_passwordGenerator->setExcludedChars(m_ui->editExcludedChars->text());
}
m_passwordGenerator->setFlags(flags);
if (m_ui->buttonAdvancedMode->isChecked()) {
m_passwordGenerator->setExcludedChars(m_ui->editExcludedChars->text());
} else {
m_passwordGenerator->setExcludedChars("");
}
if (m_passwordGenerator->isValid()) {
m_ui->buttonGenerate->setEnabled(true);
@ -573,21 +539,9 @@ void PasswordGeneratorWidget::updateGenerator()
m_ui->buttonGenerate->setEnabled(false);
}
} else {
int minWordCount = 1;
if (m_ui->spinBoxWordCount->value() < minWordCount) {
m_updatingSpinBox = true;
m_ui->spinBoxWordCount->setValue(minWordCount);
m_ui->sliderWordCount->setValue(minWordCount);
m_updatingSpinBox = false;
}
m_dicewareGenerator->setWordCase(
static_cast<PassphraseGenerator::PassphraseWordCase>(m_ui->wordCaseComboBox->currentData().toInt()));
m_ui->spinBoxWordCount->setMinimum(minWordCount);
m_ui->sliderWordCount->setMinimum(minWordCount);
m_dicewareGenerator->setWordCount(m_ui->spinBoxWordCount->value());
if (!m_ui->comboBoxWordList->currentText().isEmpty()) {
QString path = filePath()->wordlistPath(m_ui->comboBoxWordList->currentText());

View File

@ -54,9 +54,6 @@ public:
QString getGeneratedPassword();
bool isPasswordVisible() const;
protected:
void showEvent(QShowEvent* event) override;
public slots:
void regeneratePassword();
void applyPassword();
@ -65,25 +62,21 @@ public slots:
signals:
void appliedPassword(const QString& password);
void dialogTerminated();
void closePasswordGenerator();
private slots:
void updateButtonsEnabled(const QString& password);
void updatePasswordStrength(const QString& password);
void selectSimpleMode();
void selectAdvancedMode();
void setAdvancedMode(bool state);
void excludeHexChars();
void passwordSliderMoved();
void passwordSpinBoxChanged();
void dicewareSliderMoved();
void dicewareSpinBoxChanged();
void passwordLengthChanged(int length);
void passphraseLengthChanged(int length);
void colorStrengthIndicator(const PasswordHealth& health);
void updateGenerator();
private:
bool m_updatingSpinBox;
bool m_standalone = false;
PasswordGenerator::CharClasses charClasses();

File diff suppressed because it is too large Load Diff

View File

@ -148,8 +148,6 @@ void EditEntryWidget::setupMain()
m_usernameCompleter->setModel(m_usernameCompleterModel);
m_mainUi->usernameComboBox->setCompleter(m_usernameCompleter);
m_mainUi->togglePasswordButton->setIcon(filePath()->onOffIcon("actions", "password-show"));
m_mainUi->togglePasswordGeneratorButton->setIcon(filePath()->icon("actions", "password-generator"));
#ifdef WITH_XC_NETWORKING
m_mainUi->fetchFaviconButton->setIcon(filePath()->icon("actions", "favicon-download"));
m_mainUi->fetchFaviconButton->setDisabled(true);
@ -157,8 +155,6 @@ void EditEntryWidget::setupMain()
m_mainUi->fetchFaviconButton->setVisible(false);
#endif
connect(m_mainUi->togglePasswordButton, SIGNAL(toggled(bool)), m_mainUi->passwordEdit, SLOT(setShowPassword(bool)));
connect(m_mainUi->togglePasswordGeneratorButton, SIGNAL(toggled(bool)), SLOT(togglePasswordGeneratorButton(bool)));
#ifdef WITH_XC_NETWORKING
connect(m_mainUi->fetchFaviconButton, SIGNAL(clicked()), m_iconsWidget, SLOT(downloadFavicon()));
connect(m_mainUi->urlEdit, SIGNAL(textChanged(QString)), m_iconsWidget, SLOT(setUrl(QString)));
@ -166,8 +162,9 @@ void EditEntryWidget::setupMain()
#endif
connect(m_mainUi->expireCheck, SIGNAL(toggled(bool)), m_mainUi->expireDatePicker, SLOT(setEnabled(bool)));
connect(m_mainUi->notesEnabled, SIGNAL(toggled(bool)), this, SLOT(toggleHideNotes(bool)));
m_mainUi->passwordRepeatEdit->enableVerifyMode(m_mainUi->passwordEdit);
connect(m_mainUi->passwordGenerator, SIGNAL(appliedPassword(QString)), SLOT(setGeneratedPassword(QString)));
connect(m_mainUi->passwordGenerator, SIGNAL(closePasswordGenerator()), SLOT(togglePasswordGenerator()));
m_mainUi->expirePresets->setMenu(createPresetsMenu());
connect(m_mainUi->expirePresets->menu(), SIGNAL(triggered(QAction*)), this, SLOT(useExpiryPreset(QAction*)));
@ -417,7 +414,6 @@ void EditEntryWidget::setupEntryUpdate()
connect(m_mainUi->titleEdit, SIGNAL(textChanged(QString)), this, SLOT(setModified()));
connect(m_mainUi->usernameComboBox->lineEdit(), SIGNAL(textChanged(QString)), this, SLOT(setModified()));
connect(m_mainUi->passwordEdit, SIGNAL(textChanged(QString)), this, SLOT(setModified()));
connect(m_mainUi->passwordRepeatEdit, SIGNAL(textChanged(QString)), this, SLOT(setModified()));
connect(m_mainUi->urlEdit, SIGNAL(textChanged(QString)), this, SLOT(setModified()));
#ifdef WITH_XC_NETWORKING
connect(m_mainUi->urlEdit, SIGNAL(textChanged(QString)), this, SLOT(updateFaviconButtonEnable(QString)));
@ -809,7 +805,6 @@ void EditEntryWidget::setForms(Entry* entry, bool restore)
m_mainUi->usernameComboBox->lineEdit()->setReadOnly(m_history);
m_mainUi->urlEdit->setReadOnly(m_history);
m_mainUi->passwordEdit->setReadOnly(m_history);
m_mainUi->passwordRepeatEdit->setReadOnly(m_history);
m_mainUi->expireCheck->setEnabled(!m_history);
m_mainUi->expireDatePicker->setReadOnly(m_history);
m_mainUi->notesEnabled->setChecked(!config()->get("security/hidenotes").toBool());
@ -821,8 +816,7 @@ void EditEntryWidget::setForms(Entry* entry, bool restore)
} else {
m_mainUi->notesEdit->setFont(Font::defaultFont());
}
m_mainUi->togglePasswordGeneratorButton->setChecked(false);
m_mainUi->togglePasswordGeneratorButton->setDisabled(m_history);
m_mainUi->passwordGenerator->setVisible(false);
m_mainUi->passwordGenerator->reset(entry->password().length());
m_advancedUi->attachmentsWidget->setReadOnly(m_history);
@ -849,11 +843,14 @@ void EditEntryWidget::setForms(Entry* entry, bool restore)
m_mainUi->usernameComboBox->lineEdit()->setText(entry->username());
m_mainUi->urlEdit->setText(entry->url());
m_mainUi->passwordEdit->setText(entry->password());
m_mainUi->passwordRepeatEdit->setText(entry->password());
m_mainUi->passwordEdit->setShowPassword(config()->get("security/passwordscleartext").toBool());
if (!m_history) {
m_mainUi->passwordEdit->enablePasswordGenerator(true);
}
m_mainUi->expireCheck->setChecked(entry->timeInfo().expires());
m_mainUi->expireDatePicker->setDateTime(entry->timeInfo().expiryTime().toLocalTime());
m_mainUi->expirePresets->setEnabled(!m_history);
m_mainUi->togglePasswordButton->setChecked(config()->get("security/passwordscleartext").toBool());
QList<QString> commonUsernames = m_db->commonUsernames();
m_usernameCompleterModel->setStringList(commonUsernames);
@ -973,13 +970,8 @@ bool EditEntryWidget::commitEntry()
return true;
}
if (!passwordsEqual()) {
showMessage(tr("Different passwords supplied."), MessageWidget::Error);
return false;
}
// Ask the user to apply the generator password, if open
if (m_mainUi->togglePasswordGeneratorButton->isChecked()
if (m_mainUi->passwordGenerator->isVisible()
&& m_mainUi->passwordGenerator->getGeneratedPassword() != m_mainUi->passwordEdit->text()) {
auto answer = MessageBox::question(this,
tr("Apply generated password?"),
@ -992,7 +984,7 @@ bool EditEntryWidget::commitEntry()
}
// Hide the password generator
m_mainUi->togglePasswordGeneratorButton->setChecked(false);
m_mainUi->passwordGenerator->setVisible(false);
if (m_advancedUi->attributesView->currentIndex().isValid() && m_advancedUi->attributesEdit->isEnabled()) {
QString key = m_attributesModel->keyByIndex(m_advancedUi->attributesView->currentIndex());
@ -1139,7 +1131,6 @@ void EditEntryWidget::clear()
m_mainUi->titleEdit->setText("");
m_mainUi->passwordEdit->setText("");
m_mainUi->passwordRepeatEdit->setText("");
m_mainUi->urlEdit->setText("");
m_mainUi->notesEdit->clear();
@ -1151,25 +1142,20 @@ void EditEntryWidget::clear()
hideMessage();
}
void EditEntryWidget::togglePasswordGeneratorButton(bool checked)
void EditEntryWidget::togglePasswordGenerator()
{
if (checked) {
bool visible = m_mainUi->passwordGenerator->isVisible();
if (!visible) {
m_mainUi->passwordGenerator->regeneratePassword();
m_mainUi->passwordGenerator->setPasswordVisible(m_mainUi->passwordEdit->isPasswordVisible());
}
m_mainUi->passwordGenerator->setVisible(checked);
}
bool EditEntryWidget::passwordsEqual()
{
return m_mainUi->passwordEdit->text() == m_mainUi->passwordRepeatEdit->text();
m_mainUi->passwordGenerator->setVisible(!visible);
}
void EditEntryWidget::setGeneratedPassword(const QString& password)
{
m_mainUi->passwordEdit->setText(password);
m_mainUi->passwordRepeatEdit->setText(password);
m_mainUi->togglePasswordGeneratorButton->setChecked(false);
m_mainUi->passwordGenerator->setVisible(false);
}
#ifdef WITH_XC_NETWORKING

View File

@ -83,7 +83,7 @@ private slots:
void acceptEntry();
bool commitEntry();
void cancel();
void togglePasswordGeneratorButton(bool checked);
void togglePasswordGenerator();
void setGeneratedPassword(const QString& password);
#ifdef WITH_XC_NETWORKING
void updateFaviconButtonEnable(const QString& url);

View File

@ -20,122 +20,16 @@
<property name="bottomMargin">
<number>0</number>
</property>
<item row="5" column="0" alignment="Qt::AlignRight">
<widget class="QLabel" name="urlLabel">
<property name="text">
<string>URL:</string>
</property>
</widget>
</item>
<item row="5" column="1">
<layout class="QHBoxLayout" name="horizontalLayout_6">
<item>
<widget class="URLEdit" name="urlEdit">
<property name="accessibleName">
<string>Url field</string>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="fetchFaviconButton">
<property name="toolTip">
<string>Download favicon for URL</string>
</property>
<property name="accessibleName">
<string>Download favicon for URL</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="4" column="1">
<widget class="PasswordGeneratorWidget" name="passwordGenerator" native="true"/>
</item>
<item row="2" column="0" alignment="Qt::AlignRight">
<widget class="QLabel" name="passwordLabel">
<property name="text">
<string>Password:</string>
</property>
</widget>
</item>
<item row="3" column="1">
<layout class="QHBoxLayout" name="horizontalLayout_4">
<item>
<widget class="PasswordEdit" name="passwordRepeatEdit">
<property name="accessibleName">
<string>Repeat password field</string>
</property>
<property name="echoMode">
<enum>QLineEdit::Password</enum>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="togglePasswordGeneratorButton">
<property name="toolTip">
<string>Toggle password generator</string>
</property>
<property name="accessibleName">
<string>Toggle password generator</string>
</property>
<property name="checkable">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</item>
<item row="2" column="1">
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="PasswordEdit" name="passwordEdit">
<property name="accessibleName">
<string>Password field</string>
</property>
<property name="echoMode">
<enum>QLineEdit::Password</enum>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="togglePasswordButton">
<property name="toolTip">
<string>Toggle password visibility</string>
</property>
<property name="accessibleName">
<string>Toggle password visibility</string>
</property>
<property name="checkable">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</item>
<item row="3" column="0" alignment="Qt::AlignRight">
<widget class="QLabel" name="passwordRepeatLabel">
<property name="text">
<string>Repeat:</string>
</property>
</widget>
</item>
<item row="0" column="0" alignment="Qt::AlignRight">
<widget class="QLabel" name="titleLabel">
<property name="text">
<string>Title:</string>
</property>
</widget>
</item>
<item row="9" column="0" alignment="Qt::AlignLeft|Qt::AlignTop">
<widget class="QCheckBox" name="notesEnabled">
<item row="7" column="0" alignment="Qt::AlignRight">
<widget class="QCheckBox" name="expireCheck">
<property name="toolTip">
<string>Toggle notes visible</string>
<string>Toggle expiration</string>
</property>
<property name="accessibleName">
<string>Toggle notes visible</string>
<string>Toggle expiration</string>
</property>
<property name="text">
<string>Notes</string>
<string>Expires</string>
</property>
</widget>
</item>
@ -194,10 +88,48 @@
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QComboBox" name="usernameComboBox">
<property name="accessibleName">
<string>Username field</string>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="PasswordGeneratorWidget" name="passwordGenerator" native="true"/>
</item>
<item row="0" column="1">
<widget class="QLineEdit" name="titleEdit">
<property name="accessibleName">
<string>Title field</string>
</property>
</widget>
</item>
<item row="5" column="1">
<layout class="QHBoxLayout" name="horizontalLayout_6">
<item>
<widget class="URLEdit" name="urlEdit">
<property name="accessibleName">
<string>Url field</string>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="fetchFaviconButton">
<property name="toolTip">
<string>Download favicon for URL</string>
</property>
<property name="accessibleName">
<string>Download favicon for URL</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="9" column="1">
<widget class="QLabel" name="notesHint">
<property name="visible">
<bool>false</bool>
<bool>true</bool>
</property>
<property name="text">
<string>Toggle the checkbox to reveal the notes section.</string>
@ -207,6 +139,13 @@
</property>
</widget>
</item>
<item row="5" column="0" alignment="Qt::AlignRight">
<widget class="QLabel" name="urlLabel">
<property name="text">
<string>URL:</string>
</property>
</widget>
</item>
<item row="1" column="0" alignment="Qt::AlignRight">
<widget class="QLabel" name="usernameLabel">
<property name="text">
@ -214,34 +153,50 @@
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLineEdit" name="titleEdit">
<property name="accessibleName">
<string>Title field</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QComboBox" name="usernameComboBox">
<property name="accessibleName">
<string>Username field</string>
</property>
</widget>
</item>
<item row="7" column="0" alignment="Qt::AlignRight">
<widget class="QCheckBox" name="expireCheck">
<item row="9" column="0" alignment="Qt::AlignLeft|Qt::AlignTop">
<widget class="QCheckBox" name="notesEnabled">
<property name="toolTip">
<string>Toggle expiration</string>
<string>Toggle notes visible</string>
</property>
<property name="accessibleName">
<string>Toggle expiration</string>
<string>Toggle notes visible</string>
</property>
<property name="text">
<string>Expires</string>
<string>Notes</string>
</property>
</widget>
</item>
<item row="2" column="0" alignment="Qt::AlignRight">
<widget class="QLabel" name="passwordLabel">
<property name="text">
<string>Password:</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="PasswordEdit" name="passwordEdit">
<property name="accessibleName">
<string>Password field</string>
</property>
<property name="echoMode">
<enum>QLineEdit::Password</enum>
</property>
</widget>
</item>
</layout>
<widget class="QLabel" name="titleLabel">
<property name="geometry">
<rect>
<x>35</x>
<y>0</y>
<width>23</width>
<height>19</height>
</rect>
</property>
<property name="text">
<string>Title:</string>
</property>
</widget>
</widget>
<customwidgets>
<customwidget>
@ -267,9 +222,6 @@
<tabstop>titleEdit</tabstop>
<tabstop>usernameComboBox</tabstop>
<tabstop>passwordEdit</tabstop>
<tabstop>togglePasswordButton</tabstop>
<tabstop>passwordRepeatEdit</tabstop>
<tabstop>togglePasswordGeneratorButton</tabstop>
<tabstop>urlEdit</tabstop>
<tabstop>fetchFaviconButton</tabstop>
<tabstop>expireCheck</tabstop>

View File

@ -53,7 +53,7 @@ bool PasswordEditWidget::addToCompositeKey(QSharedPointer<CompositeKey> key)
*/
void PasswordEditWidget::setPasswordVisible(bool visible)
{
m_compUi->togglePasswordButton->setChecked(visible);
m_compUi->enterPasswordEdit->setShowPassword(visible);
}
/**
@ -61,7 +61,7 @@ void PasswordEditWidget::setPasswordVisible(bool visible)
*/
bool PasswordEditWidget::isPasswordVisible() const
{
return m_compUi->togglePasswordButton->isChecked();
return m_compUi->enterPasswordEdit->isPasswordVisible();
}
bool PasswordEditWidget::isEmpty() const
@ -73,16 +73,8 @@ QWidget* PasswordEditWidget::componentEditWidget()
{
m_compEditWidget = new QWidget();
m_compUi->setupUi(m_compEditWidget);
m_compUi->togglePasswordButton->setIcon(filePath()->onOffIcon("actions", "password-show"));
m_compUi->passwordGeneratorButton->setIcon(filePath()->icon("actions", "password-generator"));
m_compUi->repeatPasswordEdit->enableVerifyMode(m_compUi->enterPasswordEdit);
connect(m_compUi->togglePasswordButton,
SIGNAL(toggled(bool)),
m_compUi->enterPasswordEdit,
SLOT(setShowPassword(bool)));
connect(m_compUi->passwordGeneratorButton, SIGNAL(clicked(bool)), SLOT(showPasswordGenerator()));
m_compUi->enterPasswordEdit->enablePasswordGenerator();
m_compUi->enterPasswordEdit->setRepeatPartner(m_compUi->repeatPasswordEdit);
return m_compEditWidget;
}
@ -113,26 +105,6 @@ bool PasswordEditWidget::validate(QString& errorMessage) const
return true;
}
void PasswordEditWidget::showPasswordGenerator()
{
QDialog pwDialog;
pwDialog.setWindowTitle(tr("Generate master password"));
auto layout = new QVBoxLayout();
pwDialog.setLayout(layout);
auto pwGenerator = new PasswordGeneratorWidget(&pwDialog);
layout->addWidget(pwGenerator);
pwGenerator->setStandaloneMode(false);
connect(pwGenerator, SIGNAL(appliedPassword(QString)), SLOT(setPassword(QString)));
connect(pwGenerator, SIGNAL(dialogTerminated()), &pwDialog, SLOT(close()));
pwGenerator->setPasswordVisible(isPasswordVisible());
pwDialog.exec();
}
void PasswordEditWidget::setPassword(const QString& password)
{
Q_ASSERT(m_compEditWidget);

View File

@ -47,7 +47,6 @@ protected:
void hideEvent(QHideEvent* event) override;
private slots:
void showPasswordGenerator();
void setPassword(const QString& password);
private:

View File

@ -31,49 +31,26 @@
</widget>
</item>
<item row="0" column="1">
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="PasswordEdit" name="enterPasswordEdit">
<property name="accessibleName">
<string>Password field</string>
</property>
<property name="echoMode">
<enum>QLineEdit::Password</enum>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="togglePasswordButton">
<property name="accessibleName">
<string>Toggle password visibility</string>
</property>
<property name="checkable">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</item>
<item row="1" column="1">
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="PasswordEdit" name="repeatPasswordEdit">
<property name="accessibleName">
<string>Repeat password field</string>
</property>
<property name="echoMode">
<enum>QLineEdit::Password</enum>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="passwordGeneratorButton">
<property name="accessibleName">
<string>Toggle password generator</string>
</property>
</widget>
</item>
</layout>
<widget class="PasswordEdit" name="enterPasswordEdit">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>300</width>
<height>0</height>
</size>
</property>
<property name="accessibleName">
<string>Password field</string>
</property>
<property name="echoMode">
<enum>QLineEdit::Password</enum>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="repeatPasswordLabel">
@ -82,6 +59,28 @@
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="PasswordEdit" name="repeatPasswordEdit">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>300</width>
<height>0</height>
</size>
</property>
<property name="accessibleName">
<string>Repeat password field</string>
</property>
<property name="echoMode">
<enum>QLineEdit::Password</enum>
</property>
</widget>
</item>
</layout>
</widget>
<customwidgets>
@ -95,8 +94,6 @@
<tabstops>
<tabstop>enterPasswordEdit</tabstop>
<tabstop>repeatPasswordEdit</tabstop>
<tabstop>togglePasswordButton</tabstop>
<tabstop>passwordGeneratorButton</tabstop>
</tabstops>
<resources/>
<connections/>

View File

@ -37,5 +37,5 @@ NewDatabaseWizardPageMasterKey::~NewDatabaseWizardPageMasterKey()
void NewDatabaseWizardPageMasterKey::updateWindowSize()
{
// ugly workaround for QWizard not managing to react to size changes automatically
QApplication::activeWindow()->adjustSize();
window()->adjustSize();
}

View File

@ -471,17 +471,6 @@ void TestGui::testEditEntry()
QCOMPARE(attrTextEdit->toPlainText(), attrText);
editEntryWidget->setCurrentPage(0);
// Test mismatch passwords
auto* passwordEdit = editEntryWidget->findChild<QLineEdit*>("passwordEdit");
QString originalPassword = passwordEdit->text();
passwordEdit->setText("newpass");
QTest::mouseClick(okButton, Qt::LeftButton);
auto* messageWiget = editEntryWidget->findChild<MessageWidget*>("messageWidget");
QTRY_VERIFY(messageWiget->isVisible());
QCOMPARE(m_dbWidget->currentMode(), DatabaseWidget::Mode::EditMode);
QCOMPARE(passwordEdit->text(), QString("newpass"));
passwordEdit->setText(originalPassword);
// Save the edit (press OK)
QTest::mouseClick(okButton, Qt::LeftButton);
QApplication::processEvents();
@ -506,7 +495,6 @@ void TestGui::testEditEntry()
titleEdit->setText("multiline\ntitle");
editEntryWidget->findChild<QComboBox*>("usernameComboBox")->lineEdit()->setText("multiline\nusername");
editEntryWidget->findChild<QLineEdit*>("passwordEdit")->setText("multiline\npassword");
editEntryWidget->findChild<QLineEdit*>("passwordRepeatEdit")->setText("multiline\npassword");
editEntryWidget->findChild<QLineEdit*>("urlEdit")->setText("multiline\nurl");
QTest::mouseClick(okButton, Qt::LeftButton);
@ -615,9 +603,7 @@ void TestGui::testAddEntry()
QTest::keyClicks(usernameComboBox, "Auto");
QTest::keyPress(usernameComboBox, Qt::Key_Right);
auto* passwordEdit = editEntryWidget->findChild<QLineEdit*>("passwordEdit");
auto* passwordRepeatEdit = editEntryWidget->findChild<QLineEdit*>("passwordRepeatEdit");
QTest::keyClicks(passwordEdit, "something 2");
QTest::keyClicks(passwordRepeatEdit, "something 2");
QTest::mouseClick(editEntryWidgetButtonBox->button(QDialogButtonBox::Ok), Qt::LeftButton);
QCOMPARE(m_dbWidget->currentMode(), DatabaseWidget::Mode::ViewMode);
@ -663,8 +649,10 @@ void TestGui::testPasswordEntryEntropy()
QTest::keyClicks(titleEdit, "test");
// Open the password generator
auto* generatorButton = editEntryWidget->findChild<QToolButton*>("togglePasswordGeneratorButton");
QTest::mouseClick(generatorButton, Qt::LeftButton);
auto* passwordEdit = editEntryWidget->findChild<PasswordEdit*>();
QVERIFY(passwordEdit);
QTest::mouseClick(passwordEdit, Qt::LeftButton);
QTest::keyClick(passwordEdit, Qt::Key_G, Qt::ControlModifier);
// Type in some password
auto* editNewPassword = editEntryWidget->findChild<QLineEdit*>("editNewPassword");
@ -735,8 +723,10 @@ void TestGui::testDicewareEntryEntropy()
QTest::keyClicks(titleEdit, "test");
// Open the password generator
auto* generatorButton = editEntryWidget->findChild<QToolButton*>("togglePasswordGeneratorButton");
QTest::mouseClick(generatorButton, Qt::LeftButton);
auto* passwordEdit = editEntryWidget->findChild<PasswordEdit*>();
QVERIFY(passwordEdit);
QTest::mouseClick(passwordEdit, Qt::LeftButton);
QTest::keyClick(passwordEdit, Qt::Key_G, Qt::ControlModifier);
// Select Diceware
auto* tabWidget = editEntryWidget->findChild<QTabWidget*>("tabWidget");
@ -1440,7 +1430,6 @@ int TestGui::addCannedEntries()
auto* editEntryWidget = m_dbWidget->findChild<EditEntryWidget*>("editEntryWidget");
auto* titleEdit = editEntryWidget->findChild<QLineEdit*>("titleEdit");
auto* passwordEdit = editEntryWidget->findChild<QLineEdit*>("passwordEdit");
auto* passwordRepeatEdit = editEntryWidget->findChild<QLineEdit*>("passwordRepeatEdit");
// Add entry "test" and confirm added
QTest::mouseClick(entryNewWidget, Qt::LeftButton);
@ -1453,7 +1442,6 @@ int TestGui::addCannedEntries()
QTest::mouseClick(entryNewWidget, Qt::LeftButton);
QTest::keyClicks(titleEdit, "something 2");
QTest::keyClicks(passwordEdit, "something 2");
QTest::keyClicks(passwordRepeatEdit, "something 2");
QTest::mouseClick(editEntryWidgetButtonBox->button(QDialogButtonBox::Ok), Qt::LeftButton);
++entries_added;