mirror of
https://github.com/keepassxreboot/keepassxc.git
synced 2025-08-12 08:20:46 -04:00
Improve UX of database statistics page
* Fix #3766 - move database statistics processing into async task and only perform the calculation when the statistics tab is activated.
This commit is contained in:
parent
f9d2696046
commit
87ca7c7f7b
3 changed files with 61 additions and 31 deletions
|
@ -18,6 +18,7 @@
|
||||||
#include "DatabaseSettingsWidgetStatistics.h"
|
#include "DatabaseSettingsWidgetStatistics.h"
|
||||||
#include "ui_DatabaseSettingsWidgetStatistics.h"
|
#include "ui_DatabaseSettingsWidgetStatistics.h"
|
||||||
|
|
||||||
|
#include "core/AsyncTask.h"
|
||||||
#include "core/Database.h"
|
#include "core/Database.h"
|
||||||
#include "core/FilePath.h"
|
#include "core/FilePath.h"
|
||||||
#include "core/Group.h"
|
#include "core/Group.h"
|
||||||
|
@ -123,7 +124,8 @@ namespace
|
||||||
++nPwdsShort;
|
++nPwdsShort;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ZxcvbnMatch(pwd.toLatin1(), nullptr, nullptr) < 65) {
|
// Speed up Zxcvbn process by excluding very long passwords and most passphrases
|
||||||
|
if (pwd.size() < 25 && ZxcvbnMatch(pwd.toLatin1(), nullptr, nullptr) < 65) {
|
||||||
++nPwdsWeak;
|
++nPwdsWeak;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -142,6 +144,11 @@ DatabaseSettingsWidgetStatistics::DatabaseSettingsWidgetStatistics(QWidget* pare
|
||||||
, m_errIcon(FilePath::instance()->icon("status", "dialog-error"))
|
, m_errIcon(FilePath::instance()->icon("status", "dialog-error"))
|
||||||
{
|
{
|
||||||
m_ui->setupUi(this);
|
m_ui->setupUi(this);
|
||||||
|
|
||||||
|
m_referencesModel.reset(new QStandardItemModel());
|
||||||
|
m_referencesModel->setHorizontalHeaderLabels(QStringList() << tr("Name") << tr("Value"));
|
||||||
|
m_ui->statisticsTableView->setModel(m_referencesModel.data());
|
||||||
|
m_ui->statisticsTableView->horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents);
|
||||||
}
|
}
|
||||||
|
|
||||||
DatabaseSettingsWidgetStatistics::~DatabaseSettingsWidgetStatistics()
|
DatabaseSettingsWidgetStatistics::~DatabaseSettingsWidgetStatistics()
|
||||||
|
@ -165,48 +172,63 @@ void DatabaseSettingsWidgetStatistics::addStatsRow(QString name, QString value,
|
||||||
|
|
||||||
void DatabaseSettingsWidgetStatistics::loadSettings(QSharedPointer<Database> db)
|
void DatabaseSettingsWidgetStatistics::loadSettings(QSharedPointer<Database> db)
|
||||||
{
|
{
|
||||||
m_referencesModel.reset(new QStandardItemModel());
|
m_db = std::move(db);
|
||||||
m_referencesModel->setHorizontalHeaderLabels(QStringList() << tr("Name") << tr("Value"));
|
m_statsCalculated = false;
|
||||||
|
m_referencesModel->clear();
|
||||||
|
addStatsRow(tr("Please wait, database statistics are being calculated..."), "");
|
||||||
|
}
|
||||||
|
|
||||||
const auto stats = Stats(db);
|
void DatabaseSettingsWidgetStatistics::showEvent(QShowEvent* event)
|
||||||
addStatsRow(tr("Database name"), db->metadata()->name());
|
{
|
||||||
addStatsRow(tr("Description"), db->metadata()->description());
|
QWidget::showEvent(event);
|
||||||
addStatsRow(tr("Location"), db->filePath());
|
|
||||||
addStatsRow(tr("Last saved"), stats.modified.toString(Qt::DefaultLocaleShortDate));
|
if (!m_statsCalculated) {
|
||||||
|
// Perform stats calculation on next event loop to allow widget to appear
|
||||||
|
m_statsCalculated = true;
|
||||||
|
QTimer::singleShot(0, this, SLOT(calculateStats()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DatabaseSettingsWidgetStatistics::calculateStats()
|
||||||
|
{
|
||||||
|
const auto stats = AsyncTask::runAndWaitForFuture([this] { return new Stats(m_db); });
|
||||||
|
|
||||||
|
m_referencesModel->clear();
|
||||||
|
addStatsRow(tr("Database name"), m_db->metadata()->name());
|
||||||
|
addStatsRow(tr("Description"), m_db->metadata()->description());
|
||||||
|
addStatsRow(tr("Location"), m_db->filePath());
|
||||||
|
addStatsRow(tr("Last saved"), stats->modified.toString(Qt::DefaultLocaleShortDate));
|
||||||
addStatsRow(tr("Unsaved changes"),
|
addStatsRow(tr("Unsaved changes"),
|
||||||
db->isModified() ? tr("yes") : tr("no"),
|
m_db->isModified() ? tr("yes") : tr("no"),
|
||||||
db->isModified(),
|
m_db->isModified(),
|
||||||
tr("The database was modified, but the changes have not yet been saved to disk."));
|
tr("The database was modified, but the changes have not yet been saved to disk."));
|
||||||
addStatsRow(tr("Number of groups"), QString::number(stats.nGroups));
|
addStatsRow(tr("Number of groups"), QString::number(stats->nGroups));
|
||||||
addStatsRow(tr("Number of entries"), QString::number(stats.nEntries));
|
addStatsRow(tr("Number of entries"), QString::number(stats->nEntries));
|
||||||
addStatsRow(tr("Number of expired entries"),
|
addStatsRow(tr("Number of expired entries"),
|
||||||
QString::number(stats.nExpired),
|
QString::number(stats->nExpired),
|
||||||
stats.isAnyExpired(),
|
stats->isAnyExpired(),
|
||||||
tr("The database contains entries that have expired."));
|
tr("The database contains entries that have expired."));
|
||||||
addStatsRow(tr("Unique passwords"), QString::number(stats.nPwdsUnique));
|
addStatsRow(tr("Unique passwords"), QString::number(stats->nPwdsUnique));
|
||||||
addStatsRow(tr("Non-unique passwords"),
|
addStatsRow(tr("Non-unique passwords"),
|
||||||
QString::number(stats.nPwdsReused),
|
QString::number(stats->nPwdsReused),
|
||||||
stats.areTooManyPwdsReused(),
|
stats->areTooManyPwdsReused(),
|
||||||
tr("More than 10% of passwords are reused. Use unique passwords when possible."));
|
tr("More than 10% of passwords are reused. Use unique passwords when possible."));
|
||||||
addStatsRow(tr("Maximum password reuse"),
|
addStatsRow(tr("Maximum password reuse"),
|
||||||
QString::number(stats.maxPwdReuse()),
|
QString::number(stats->maxPwdReuse()),
|
||||||
stats.arePwdsReusedTooOften(),
|
stats->arePwdsReusedTooOften(),
|
||||||
tr("Some passwords are used more than three times. Use unique passwords when possible."));
|
tr("Some passwords are used more than three times. Use unique passwords when possible."));
|
||||||
addStatsRow(tr("Number of short passwords"),
|
addStatsRow(tr("Number of short passwords"),
|
||||||
QString::number(stats.nPwdsShort),
|
QString::number(stats->nPwdsShort),
|
||||||
stats.nPwdsShort > 0,
|
stats->nPwdsShort > 0,
|
||||||
tr("Recommended minimum password length is at least 8 characters."));
|
tr("Recommended minimum password length is at least 8 characters."));
|
||||||
addStatsRow(tr("Number of weak passwords"),
|
addStatsRow(tr("Number of weak passwords"),
|
||||||
QString::number(stats.nPwdsWeak),
|
QString::number(stats->nPwdsWeak),
|
||||||
stats.nPwdsWeak > 0,
|
stats->nPwdsWeak > 0,
|
||||||
tr("Recommend using long, randomized passwords with a rating of 'good' or 'excellent'."));
|
tr("Recommend using long, randomized passwords with a rating of 'good' or 'excellent'."));
|
||||||
addStatsRow(tr("Average password length"),
|
addStatsRow(tr("Average password length"),
|
||||||
tr("%1 characters").arg(stats.averagePwdLength()),
|
tr("%1 characters").arg(stats->averagePwdLength()),
|
||||||
stats.isAvgPwdTooShort(),
|
stats->isAvgPwdTooShort(),
|
||||||
tr("Average password length is less than ten characters. Longer passwords provide more security."));
|
tr("Average password length is less than ten characters. Longer passwords provide more security."));
|
||||||
|
|
||||||
m_ui->sharedGroupsView->setModel(m_referencesModel.data());
|
|
||||||
m_ui->sharedGroupsView->horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void DatabaseSettingsWidgetStatistics::saveSettings()
|
void DatabaseSettingsWidgetStatistics::saveSettings()
|
||||||
|
|
|
@ -39,11 +39,19 @@ public:
|
||||||
void loadSettings(QSharedPointer<Database> db);
|
void loadSettings(QSharedPointer<Database> db);
|
||||||
void saveSettings();
|
void saveSettings();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void showEvent(QShowEvent* event) override;
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void calculateStats();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QScopedPointer<Ui::DatabaseSettingsWidgetStatistics> m_ui;
|
QScopedPointer<Ui::DatabaseSettingsWidgetStatistics> m_ui;
|
||||||
|
|
||||||
|
bool m_statsCalculated = false;
|
||||||
QIcon m_errIcon;
|
QIcon m_errIcon;
|
||||||
QScopedPointer<QStandardItemModel> m_referencesModel;
|
QScopedPointer<QStandardItemModel> m_referencesModel;
|
||||||
|
QSharedPointer<Database> m_db;
|
||||||
|
|
||||||
void addStatsRow(QString name, QString value, bool bad = false, QString badMsg = "");
|
void addStatsRow(QString name, QString value, bool bad = false, QString badMsg = "");
|
||||||
};
|
};
|
||||||
|
|
|
@ -24,13 +24,13 @@
|
||||||
<number>0</number>
|
<number>0</number>
|
||||||
</property>
|
</property>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QGroupBox" name="enableGroupBox">
|
<widget class="QGroupBox" name="statisticsGroupBox">
|
||||||
<property name="title">
|
<property name="title">
|
||||||
<string>Statistics</string>
|
<string>Statistics</string>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||||
<item>
|
<item>
|
||||||
<widget class="QTableView" name="sharedGroupsView">
|
<widget class="QTableView" name="statisticsTableView">
|
||||||
<property name="editTriggers">
|
<property name="editTriggers">
|
||||||
<set>QAbstractItemView::NoEditTriggers</set>
|
<set>QAbstractItemView::NoEditTriggers</set>
|
||||||
</property>
|
</property>
|
||||||
|
@ -58,7 +58,7 @@
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QLabel" name="label">
|
<widget class="QLabel" name="tipLabel">
|
||||||
<property name="font">
|
<property name="font">
|
||||||
<font>
|
<font>
|
||||||
<italic>true</italic>
|
<italic>true</italic>
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue