Reworked the PasswordGeneratorWidget.

It's loosely based on OS X PasswordAssistant. Generation happens as soon as a
change is made, and on open of the widget. A combobox has been added to allow
one to choose from some randomally-generated alternatives, and the UI is
generally been made a bit more compact.

Written by Michael Curtis <michael@moltenmercury.org> and revised by me.

Closes #119

https://github.com/keepassx/keepassx/pull/38
This commit is contained in:
Felix Geyer 2014-01-12 23:33:36 +01:00
parent 29c997e1bc
commit 3af2307468
8 changed files with 449 additions and 197 deletions

View File

@ -85,6 +85,7 @@ set(keepassx_SOURCES
gui/MessageBox.cpp gui/MessageBox.cpp
gui/PasswordEdit.cpp gui/PasswordEdit.cpp
gui/PasswordGeneratorWidget.cpp gui/PasswordGeneratorWidget.cpp
gui/PasswordComboBox.cpp
gui/SettingsWidget.cpp gui/SettingsWidget.cpp
gui/SortFilterHideProxyModel.cpp gui/SortFilterHideProxyModel.cpp
gui/UnlockDatabaseWidget.cpp gui/UnlockDatabaseWidget.cpp
@ -163,6 +164,7 @@ set(keepassx_MOC
gui/MainWindow.h gui/MainWindow.h
gui/PasswordEdit.h gui/PasswordEdit.h
gui/PasswordGeneratorWidget.h gui/PasswordGeneratorWidget.h
gui/PasswordComboBox.h
gui/SettingsWidget.h gui/SettingsWidget.h
gui/SortFilterHideProxyModel.h gui/SortFilterHideProxyModel.h
gui/UnlockDatabaseWidget.h gui/UnlockDatabaseWidget.h

View File

@ -19,15 +19,33 @@
#include "crypto/Random.h" #include "crypto/Random.h"
PasswordGenerator* PasswordGenerator::m_instance = Q_NULLPTR; PasswordGenerator::PasswordGenerator()
: m_length(0)
QString PasswordGenerator::generatePassword(int length, , m_classes(0)
const PasswordGenerator::CharClasses& classes, , m_flags(0)
const PasswordGenerator::GeneratorFlags& flags)
{ {
Q_ASSERT(isValidCombination(length, classes, flags)); }
QVector<PasswordGroup> groups = passwordGroups(classes, flags); void PasswordGenerator::setLength(int length)
{
m_length = length;
}
void PasswordGenerator::setCharClasses(const CharClasses& classes)
{
m_classes = classes;
}
void PasswordGenerator::setFlags(const GeneratorFlags& flags)
{
m_flags = flags;
}
QString PasswordGenerator::generatePassword() const
{
Q_ASSERT(isValid());
QVector<PasswordGroup> groups = passwordGroups();
QVector<QChar> passwordChars; QVector<QChar> passwordChars;
Q_FOREACH (const PasswordGroup& group, groups) { Q_FOREACH (const PasswordGroup& group, groups) {
@ -38,14 +56,14 @@ QString PasswordGenerator::generatePassword(int length,
QString password; QString password;
if (flags & CharFromEveryGroup) { if (m_flags & CharFromEveryGroup) {
for (int i = 0; i < groups.size(); i++) { for (int i = 0; i < groups.size(); i++) {
int pos = randomGen()->randomUInt(groups[i].size()); int pos = randomGen()->randomUInt(groups[i].size());
password.append(groups[i][pos]); password.append(groups[i][pos]);
} }
for (int i = groups.size(); i < length; i++) { for (int i = groups.size(); i < m_length; i++) {
int pos = randomGen()->randomUInt(passwordChars.size()); int pos = randomGen()->randomUInt(passwordChars.size());
password.append(passwordChars[pos]); password.append(passwordChars[pos]);
@ -61,7 +79,7 @@ QString PasswordGenerator::generatePassword(int length,
} }
} }
else { else {
for (int i = 0; i < length; i++) { for (int i = 0; i < m_length; i++) {
int pos = randomGen()->randomUInt(passwordChars.size()); int pos = randomGen()->randomUInt(passwordChars.size());
password.append(passwordChars[pos]); password.append(passwordChars[pos]);
@ -71,34 +89,31 @@ QString PasswordGenerator::generatePassword(int length,
return password; return password;
} }
bool PasswordGenerator::isValidCombination(int length, bool PasswordGenerator::isValid() const
const PasswordGenerator::CharClasses& classes,
const PasswordGenerator::GeneratorFlags& flags)
{ {
if (classes == 0) { if (m_classes == 0) {
return false; return false;
} }
else if (length == 0) { else if (m_length == 0) {
return false; return false;
} }
if ((flags & CharFromEveryGroup) && (length < numCharClasses(classes))) { if ((m_flags & CharFromEveryGroup) && (m_length < numCharClasses())) {
return false; return false;
} }
return true; return true;
} }
QVector<PasswordGroup> PasswordGenerator::passwordGroups(const PasswordGenerator::CharClasses& classes, QVector<PasswordGroup> PasswordGenerator::passwordGroups() const
const PasswordGenerator::GeneratorFlags& flags)
{ {
QVector<PasswordGroup> passwordGroups; QVector<PasswordGroup> passwordGroups;
if (classes & LowerLetters) { if (m_classes & LowerLetters) {
PasswordGroup group; PasswordGroup group;
for (int i = 97; i < (97 + 26); i++) { for (int i = 97; i < (97 + 26); i++) {
if ((flags & ExcludeLookAlike) && (i == 108)) { // "l" if ((m_flags & ExcludeLookAlike) && (i == 108)) { // "l"
continue; continue;
} }
@ -107,11 +122,11 @@ QVector<PasswordGroup> PasswordGenerator::passwordGroups(const PasswordGenerator
passwordGroups.append(group); passwordGroups.append(group);
} }
if (classes & UpperLetters) { if (m_classes & UpperLetters) {
PasswordGroup group; PasswordGroup group;
for (int i = 65; i < (65 + 26); i++) { for (int i = 65; i < (65 + 26); i++) {
if ((flags & ExcludeLookAlike) && (i == 73 || i == 79)) { // "I" and "O" if ((m_flags & ExcludeLookAlike) && (i == 73 || i == 79)) { // "I" and "O"
continue; continue;
} }
@ -120,11 +135,11 @@ QVector<PasswordGroup> PasswordGenerator::passwordGroups(const PasswordGenerator
passwordGroups.append(group); passwordGroups.append(group);
} }
if (classes & Numbers) { if (m_classes & Numbers) {
PasswordGroup group; PasswordGroup group;
for (int i = 48; i < (48 + 10); i++) { for (int i = 48; i < (48 + 10); i++) {
if ((flags & ExcludeLookAlike) && (i == 48 || i == 49)) { // "0" and "1" if ((m_flags & ExcludeLookAlike) && (i == 48 || i == 49)) { // "0" and "1"
continue; continue;
} }
@ -133,7 +148,7 @@ QVector<PasswordGroup> PasswordGenerator::passwordGroups(const PasswordGenerator
passwordGroups.append(group); passwordGroups.append(group);
} }
if (classes & SpecialCharacters) { if (m_classes & SpecialCharacters) {
PasswordGroup group; PasswordGroup group;
for (int i = 33; i <= 47; i++) { for (int i = 33; i <= 47; i++) {
@ -149,7 +164,7 @@ QVector<PasswordGroup> PasswordGenerator::passwordGroups(const PasswordGenerator
} }
for (int i = 123; i <= 126; i++) { for (int i = 123; i <= 126; i++) {
if ((flags & ExcludeLookAlike) && (i == 124)) { // "|" if ((m_flags & ExcludeLookAlike) && (i == 124)) { // "|"
continue; continue;
} }
@ -162,35 +177,23 @@ QVector<PasswordGroup> PasswordGenerator::passwordGroups(const PasswordGenerator
return passwordGroups; return passwordGroups;
} }
int PasswordGenerator::numCharClasses(const PasswordGenerator::CharClasses& classes) int PasswordGenerator::numCharClasses() const
{ {
int numClasses = 0; int numClasses = 0;
if (classes & LowerLetters) { if (m_classes & LowerLetters) {
numClasses++; numClasses++;
} }
if (classes & UpperLetters) { if (m_classes & UpperLetters) {
numClasses++; numClasses++;
} }
if (classes & Numbers) { if (m_classes & Numbers) {
numClasses++; numClasses++;
} }
if (classes & SpecialCharacters) { if (m_classes & SpecialCharacters) {
numClasses++; numClasses++;
} }
return numClasses; return numClasses;
} }
PasswordGenerator* PasswordGenerator::instance()
{
if (!m_instance) {
m_instance = new PasswordGenerator();
}
return m_instance;
}
PasswordGenerator::PasswordGenerator()
{
}

View File

@ -45,29 +45,28 @@ public:
}; };
Q_DECLARE_FLAGS(GeneratorFlags, GeneratorFlag) Q_DECLARE_FLAGS(GeneratorFlags, GeneratorFlag)
QString generatePassword(int length, const PasswordGenerator::CharClasses& classes, public:
const PasswordGenerator::GeneratorFlags& flags);
bool isValidCombination(int length, const PasswordGenerator::CharClasses& classes,
const PasswordGenerator::GeneratorFlags& flags);
static PasswordGenerator* instance();
private:
PasswordGenerator(); PasswordGenerator();
QVector<PasswordGroup> passwordGroups(const PasswordGenerator::CharClasses& classes, void setLength(int length);
const PasswordGenerator::GeneratorFlags& flags); void setCharClasses(const CharClasses& classes);
int numCharClasses(const PasswordGenerator::CharClasses& classes); void setFlags(const GeneratorFlags& flags);
static PasswordGenerator* m_instance; bool isValid() const;
QString generatePassword() const;
private:
QVector<PasswordGroup> passwordGroups() const;
int numCharClasses() const;
int m_length;
CharClasses m_classes;
GeneratorFlags m_flags;
Q_DISABLE_COPY(PasswordGenerator) Q_DISABLE_COPY(PasswordGenerator)
}; };
inline PasswordGenerator* passwordGenerator() {
return PasswordGenerator::instance();
}
Q_DECLARE_OPERATORS_FOR_FLAGS(PasswordGenerator::CharClasses) Q_DECLARE_OPERATORS_FOR_FLAGS(PasswordGenerator::CharClasses)
Q_DECLARE_OPERATORS_FOR_FLAGS(PasswordGenerator::GeneratorFlags) Q_DECLARE_OPERATORS_FOR_FLAGS(PasswordGenerator::GeneratorFlags)

View File

@ -0,0 +1,88 @@
/*
* Copyright (C) 2013 Michael Curtis <michael@moltenmercury.org>
* Copyright (C) 2014 Felix Geyer <debfx@fobos.de>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 or (at your option)
* version 3 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "PasswordComboBox.h"
#include <QLineEdit>
#include "core/PasswordGenerator.h"
PasswordComboBox::PasswordComboBox(QWidget* parent)
: QComboBox(parent)
, m_generator(Q_NULLPTR)
, m_alternatives(10)
{
setEditable(true);
setEcho(false);
}
PasswordComboBox::~PasswordComboBox()
{
}
void PasswordComboBox::setEcho(bool echo)
{
lineEdit()->setEchoMode(echo ? QLineEdit::Normal : QLineEdit::Password);
QString current = currentText();
if (echo) {
// add fake item to show visual indication that a popup is available
addItem("");
}
else {
// clear items so the combobox indicates that no popup menu is available
clear();
}
setEditText(current);
}
void PasswordComboBox::setGenerator(PasswordGenerator* generator)
{
m_generator = generator;
}
void PasswordComboBox::setNumberAlternatives(int alternatives)
{
m_alternatives = alternatives;
}
void PasswordComboBox::showPopup()
{
// no point in showing a bunch of hidden passwords
if (lineEdit()->echoMode() == QLineEdit::Password) {
hidePopup();
return;
}
// keep existing password as the first item in the popup
QString current = currentText();
clear();
addItem(current);
if (m_generator && m_generator->isValid()) {
for (int alternative = 0; alternative < m_alternatives; alternative++) {
QString password = m_generator->generatePassword();
addItem(password);
}
}
QComboBox::showPopup();
}

View File

@ -0,0 +1,46 @@
/*
* Copyright (C) 2013 Michael Curtis <michael@moltenmercury.org>
* Copyright (C) 2014 Felix Geyer <debfx@fobos.de>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 or (at your option)
* version 3 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef KEEPASSX_PASSWORDCOMBOBOX_H
#define KEEPASSX_PASSWORDCOMBOBOX_H
#include <QComboBox>
#include "core/Global.h"
class PasswordGenerator;
class PasswordComboBox : public QComboBox
{
Q_OBJECT
public:
explicit PasswordComboBox(QWidget* parent = Q_NULLPTR);
~PasswordComboBox();
void setEcho(bool echo);
void setGenerator(PasswordGenerator* generator);
void setNumberAlternatives(int alternatives);
void showPopup();
private:
PasswordGenerator* m_generator;
int m_alternatives;
};
#endif // KEEPASSX_PASSWORDCOMBOBOX_H

View File

@ -18,22 +18,36 @@
#include "PasswordGeneratorWidget.h" #include "PasswordGeneratorWidget.h"
#include "ui_PasswordGeneratorWidget.h" #include "ui_PasswordGeneratorWidget.h"
#include <QLineEdit>
#include "core/Config.h" #include "core/Config.h"
#include "core/PasswordGenerator.h"
#include "core/FilePath.h"
PasswordGeneratorWidget::PasswordGeneratorWidget(QWidget* parent) PasswordGeneratorWidget::PasswordGeneratorWidget(QWidget* parent)
: QWidget(parent) : QWidget(parent)
, m_updatingSpinBox(false)
, m_generator(new PasswordGenerator())
, m_ui(new Ui::PasswordGeneratorWidget()) , m_ui(new Ui::PasswordGeneratorWidget())
{ {
m_ui->setupUi(this); m_ui->setupUi(this);
connect(m_ui->editNewPassword, SIGNAL(textChanged(QString)), SLOT(updateApplyEnabled(QString))); m_ui->togglePasswordButton->setIcon(filePath()->onOffIcon("actions", "password-show"));
connect(m_ui->editNewPassword->lineEdit(), SIGNAL(textChanged(QString)), SLOT(updateApplyEnabled(QString)));
connect(m_ui->togglePasswordButton, SIGNAL(toggled(bool)), SLOT(togglePassword(bool))); connect(m_ui->togglePasswordButton, SIGNAL(toggled(bool)), SLOT(togglePassword(bool)));
connect(m_ui->buttonGenerate, SIGNAL(clicked()), SLOT(generatePassword()));
connect(m_ui->buttonApply, SIGNAL(clicked()), SLOT(emitNewPassword())); connect(m_ui->buttonApply, SIGNAL(clicked()), SLOT(emitNewPassword()));
connect(m_ui->buttonApply, SIGNAL(clicked()), SLOT(saveSettings())); connect(m_ui->buttonApply, SIGNAL(clicked()), SLOT(saveSettings()));
reset(); connect(m_ui->sliderLength, SIGNAL(valueChanged(int)), SLOT(sliderMoved()));
connect(m_ui->spinBoxLength, SIGNAL(valueChanged(int)), SLOT(spinBoxChanged()));
connect(m_ui->optionButtons, SIGNAL(buttonClicked(int)), SLOT(updateGenerator()));
m_ui->editNewPassword->setGenerator(m_generator.data());
loadSettings(); loadSettings();
reset();
} }
PasswordGeneratorWidget::~PasswordGeneratorWidget() PasswordGeneratorWidget::~PasswordGeneratorWidget()
@ -68,8 +82,10 @@ void PasswordGeneratorWidget::saveSettings()
void PasswordGeneratorWidget::reset() void PasswordGeneratorWidget::reset()
{ {
m_ui->editNewPassword->setText(""); m_ui->editNewPassword->lineEdit()->setText("");
m_ui->togglePasswordButton->setChecked(true); m_ui->togglePasswordButton->setChecked(config()->get("security/passwordscleartext").toBool());
updateGenerator();
} }
void PasswordGeneratorWidget::updateApplyEnabled(const QString& password) void PasswordGeneratorWidget::updateApplyEnabled(const QString& password)
@ -79,27 +95,35 @@ void PasswordGeneratorWidget::updateApplyEnabled(const QString& password)
void PasswordGeneratorWidget::togglePassword(bool checked) void PasswordGeneratorWidget::togglePassword(bool checked)
{ {
m_ui->editNewPassword->setEchoMode(checked ? QLineEdit::Password : QLineEdit::Normal); m_ui->editNewPassword->setEcho(checked);
}
void PasswordGeneratorWidget::generatePassword()
{
int length = m_ui->spinBoxLength->value();
PasswordGenerator::CharClasses classes = charClasses();
PasswordGenerator::GeneratorFlags flags = generatorFlags();
if (!passwordGenerator()->isValidCombination(length, classes, flags)) {
// TODO: display error
return;
}
QString password = passwordGenerator()->generatePassword(length, classes, flags);
m_ui->editNewPassword->setText(password);
} }
void PasswordGeneratorWidget::emitNewPassword() void PasswordGeneratorWidget::emitNewPassword()
{ {
Q_EMIT newPassword(m_ui->editNewPassword->text()); Q_EMIT newPassword(m_ui->editNewPassword->lineEdit()->text());
}
void PasswordGeneratorWidget::sliderMoved()
{
if (m_updatingSpinBox) {
return;
}
m_ui->spinBoxLength->setValue(m_ui->sliderLength->value());
updateGenerator();
}
void PasswordGeneratorWidget::spinBoxChanged()
{
// Interlock so that we don't update twice - this causes issues as the spinbox can go higher than slider
m_updatingSpinBox = true;
m_ui->sliderLength->setValue(m_ui->spinBoxLength->value());
m_updatingSpinBox = false;
updateGenerator();
} }
PasswordGenerator::CharClasses PasswordGeneratorWidget::charClasses() PasswordGenerator::CharClasses PasswordGeneratorWidget::charClasses()
@ -139,3 +163,15 @@ PasswordGenerator::GeneratorFlags PasswordGeneratorWidget::generatorFlags()
return flags; return flags;
} }
void PasswordGeneratorWidget::updateGenerator()
{
m_generator->setLength(m_ui->spinBoxLength->value());
m_generator->setCharClasses(charClasses());
m_generator->setFlags(generatorFlags());
if (m_generator->isValid()) {
QString password = m_generator->generatePassword();
m_ui->editNewPassword->setEditText(password);
}
}

View File

@ -19,6 +19,7 @@
#define KEEPASSX_PASSWORDGENERATORWIDGET_H #define KEEPASSX_PASSWORDGENERATORWIDGET_H
#include <QWidget> #include <QWidget>
#include <QComboBox>
#include "core/Global.h" #include "core/Global.h"
#include "core/PasswordGenerator.h" #include "core/PasswordGenerator.h"
@ -27,6 +28,8 @@ namespace Ui {
class PasswordGeneratorWidget; class PasswordGeneratorWidget;
} }
class PasswordGenerator;
class PasswordGeneratorWidget : public QWidget class PasswordGeneratorWidget : public QWidget
{ {
Q_OBJECT Q_OBJECT
@ -43,14 +46,21 @@ Q_SIGNALS:
private Q_SLOTS: private Q_SLOTS:
void updateApplyEnabled(const QString& password); void updateApplyEnabled(const QString& password);
void togglePassword(bool checked); void togglePassword(bool checked);
void generatePassword();
void emitNewPassword(); void emitNewPassword();
void saveSettings(); void saveSettings();
void sliderMoved();
void spinBoxChanged();
void updateGenerator();
private: private:
bool m_updatingSpinBox;
PasswordGenerator::CharClasses charClasses(); PasswordGenerator::CharClasses charClasses();
PasswordGenerator::GeneratorFlags generatorFlags(); PasswordGenerator::GeneratorFlags generatorFlags();
const QScopedPointer<PasswordGenerator> m_generator;
const QScopedPointer<Ui::PasswordGeneratorWidget> m_ui; const QScopedPointer<Ui::PasswordGeneratorWidget> m_ui;
}; };

View File

@ -6,66 +6,79 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>468</width> <width>434</width>
<height>298</height> <height>250</height>
</rect> </rect>
</property> </property>
<property name="windowTitle"> <property name="windowTitle">
<string/> <string/>
</property> </property>
<layout class="QVBoxLayout" name="verticalLayout"> <layout class="QVBoxLayout" name="verticalLayout_2">
<item> <item>
<widget class="QLabel" name="labelGroups"> <layout class="QGridLayout" name="gridLayout">
<property name="text"> <item row="0" column="0">
<string>Use the following password groups:</string> <widget class="QLabel" name="labelNewPassword">
</property> <property name="text">
</widget> <string>Password:</string>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property> </property>
<property name="sizeType"> </widget>
<enum>QSizePolicy::Maximum</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>1</height>
</size>
</property>
</spacer>
</item> </item>
<item> <item row="0" column="1">
<layout class="QGridLayout" name="gridLayout_2"> <layout class="QHBoxLayout" name="horizontalLayout_2">
<item row="0" column="0"> <property name="sizeConstraint">
<widget class="QCheckBox" name="checkBoxLower"> <enum>QLayout::SetNoConstraint</enum>
<property name="text"> </property>
<string>Lower letters</string> <item>
<widget class="PasswordComboBox" name="editNewPassword">
<property name="editable">
<bool>true</bool>
</property> </property>
</widget> </widget>
</item> </item>
<item row="0" column="1"> <item>
<widget class="QCheckBox" name="checkBoxNumbers"> <widget class="QToolButton" name="togglePasswordButton">
<property name="text"> <property name="checkable">
<string>Numbers</string> <bool>true</bool>
</property> </property>
</widget> </widget>
</item> </item>
<item row="1" column="0"> </layout>
<widget class="QCheckBox" name="checkBoxUpper"> </item>
<property name="text"> <item row="1" column="0">
<string>Upper letters</string> <widget class="QLabel" name="labelLength">
<property name="text">
<string>Length:</string>
</property>
</widget>
</item>
<item row="1" column="1">
<layout class="QHBoxLayout" name="horizontalLayout_4">
<item>
<widget class="QSlider" name="sliderLength">
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>64</number>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="tickPosition">
<enum>QSlider::TicksBelow</enum>
</property>
<property name="tickInterval">
<number>8</number>
</property> </property>
</widget> </widget>
</item> </item>
<item row="1" column="1"> <item>
<widget class="QCheckBox" name="checkBoxSpecialChars"> <widget class="QSpinBox" name="spinBoxLength">
<property name="text"> <property name="minimum">
<string>Special characters</string> <number>1</number>
</property>
<property name="maximum">
<number>999</number>
</property> </property>
</widget> </widget>
</item> </item>
@ -74,38 +87,117 @@
</layout> </layout>
</item> </item>
<item> <item>
<widget class="QCheckBox" name="checkBoxExcludeAlike"> <widget class="QGroupBox" name="groupBox">
<property name="text"> <property name="title">
<string>Exclude look-alike characters</string> <string>Character Types</string>
</property> </property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QHBoxLayout" name="horizontalLayout_5">
<item>
<widget class="QToolButton" name="checkBoxUpper">
<property name="toolTip">
<string>Upper Case Letters</string>
</property>
<property name="text">
<string>A-Z</string>
</property>
<property name="checkable">
<bool>true</bool>
</property>
<attribute name="buttonGroup">
<string notr="true">optionButtons</string>
</attribute>
</widget>
</item>
<item>
<widget class="QToolButton" name="checkBoxLower">
<property name="toolTip">
<string>Lower Case Letters</string>
</property>
<property name="text">
<string>a-z</string>
</property>
<property name="checkable">
<bool>true</bool>
</property>
<attribute name="buttonGroup">
<string notr="true">optionButtons</string>
</attribute>
</widget>
</item>
<item>
<widget class="QToolButton" name="checkBoxNumbers">
<property name="toolTip">
<string>Numbers</string>
</property>
<property name="text">
<string>0-9</string>
</property>
<property name="checkable">
<bool>true</bool>
</property>
<attribute name="buttonGroup">
<string notr="true">optionButtons</string>
</attribute>
</widget>
</item>
<item>
<widget class="QToolButton" name="checkBoxSpecialChars">
<property name="toolTip">
<string>Special Characters</string>
</property>
<property name="text">
<string>/*_&amp; ...</string>
</property>
<property name="checkable">
<bool>true</bool>
</property>
<attribute name="buttonGroup">
<string notr="true">optionButtons</string>
</attribute>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<widget class="QCheckBox" name="checkBoxExcludeAlike">
<property name="text">
<string>Exclude look-alike characters</string>
</property>
<attribute name="buttonGroup">
<string notr="true">optionButtons</string>
</attribute>
</widget>
</item>
<item>
<widget class="QCheckBox" name="checkBoxEnsureEvery">
<property name="text">
<string>Ensure that the password contains characters from every group</string>
</property>
<attribute name="buttonGroup">
<string notr="true">optionButtons</string>
</attribute>
</widget>
</item>
</layout>
</widget> </widget>
</item> </item>
<item> <item>
<widget class="QCheckBox" name="checkBoxEnsureEvery"> <layout class="QHBoxLayout" name="horizontalLayout_3">
<property name="text">
<string>Ensure that the password contains characters from every group</string>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QLabel" name="labelLength">
<property name="text">
<string>Length:</string>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="spinBoxLength">
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>999</number>
</property>
</widget>
</item>
<item> <item>
<spacer name="horizontalSpacer_2"> <spacer name="horizontalSpacer_2">
<property name="orientation"> <property name="orientation">
@ -119,51 +211,13 @@
</property> </property>
</spacer> </spacer>
</item> </item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<widget class="QLabel" name="labelNewPassword">
<property name="text">
<string>New password:</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="editNewPassword">
<property name="echoMode">
<enum>QLineEdit::Password</enum>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="togglePasswordButton">
<property name="text">
<string>...</string>
</property>
<property name="checkable">
<bool>true</bool>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="buttonGenerate">
<property name="text">
<string>Generate</string>
</property>
</widget>
</item>
<item> <item>
<widget class="QPushButton" name="buttonApply"> <widget class="QPushButton" name="buttonApply">
<property name="enabled"> <property name="enabled">
<bool>false</bool> <bool>false</bool>
</property> </property>
<property name="text"> <property name="text">
<string>Apply</string> <string>Accept</string>
</property> </property>
</widget> </widget>
</item> </item>
@ -171,19 +225,33 @@
</item> </item>
</layout> </layout>
</widget> </widget>
<customwidgets>
<customwidget>
<class>PasswordComboBox</class>
<extends>QComboBox</extends>
<header location="global">gui/PasswordComboBox.h</header>
</customwidget>
</customwidgets>
<tabstops> <tabstops>
<tabstop>editNewPassword</tabstop>
<tabstop>togglePasswordButton</tabstop>
<tabstop>sliderLength</tabstop>
<tabstop>spinBoxLength</tabstop>
<tabstop>checkBoxUpper</tabstop>
<tabstop>checkBoxLower</tabstop> <tabstop>checkBoxLower</tabstop>
<tabstop>checkBoxNumbers</tabstop> <tabstop>checkBoxNumbers</tabstop>
<tabstop>checkBoxUpper</tabstop>
<tabstop>checkBoxSpecialChars</tabstop> <tabstop>checkBoxSpecialChars</tabstop>
<tabstop>checkBoxExcludeAlike</tabstop> <tabstop>checkBoxExcludeAlike</tabstop>
<tabstop>checkBoxEnsureEvery</tabstop> <tabstop>checkBoxEnsureEvery</tabstop>
<tabstop>spinBoxLength</tabstop>
<tabstop>editNewPassword</tabstop>
<tabstop>togglePasswordButton</tabstop>
<tabstop>buttonGenerate</tabstop>
<tabstop>buttonApply</tabstop> <tabstop>buttonApply</tabstop>
</tabstops> </tabstops>
<resources/> <resources/>
<connections/> <connections/>
<buttongroups>
<buttongroup name="optionButtons">
<property name="exclusive">
<bool>false</bool>
</property>
</buttongroup>
</buttongroups>
</ui> </ui>