Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/keepassxreboot/keepassxc.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/src/gui
diff options
context:
space:
mode:
authorSami Vänttinen <sami.vanttinen@protonmail.com>2021-12-30 15:31:06 +0300
committerGitHub <noreply@github.com>2021-12-30 15:31:06 +0300
commitcd642e7fee3f46847cc5020f33058d4bceef6805 (patch)
tree1e1facfe49d050609e5ba4ddf9e428f858fbc003 /src/gui
parent15d1b2f0abc128969aa2054e4e9ce9283daf8591 (diff)
Add support for Browser statistics (#7197)
Co-authored-by: Jonathan White <support@dmapps.us>
Diffstat (limited to 'src/gui')
-rw-r--r--src/gui/reports/ReportsDialog.cpp24
-rw-r--r--src/gui/reports/ReportsDialog.h8
-rw-r--r--src/gui/reports/ReportsPageBrowserStatistics.cpp53
-rw-r--r--src/gui/reports/ReportsPageBrowserStatistics.h39
-rw-r--r--src/gui/reports/ReportsWidgetBrowserStatistics.cpp372
-rw-r--r--src/gui/reports/ReportsWidgetBrowserStatistics.h71
-rw-r--r--src/gui/reports/ReportsWidgetBrowserStatistics.ui100
-rw-r--r--src/gui/styles/StateColorPalette.cpp8
-rw-r--r--src/gui/styles/StateColorPalette.h6
9 files changed, 675 insertions, 6 deletions
diff --git a/src/gui/reports/ReportsDialog.cpp b/src/gui/reports/ReportsDialog.cpp
index ecd015b89..406237459 100644
--- a/src/gui/reports/ReportsDialog.cpp
+++ b/src/gui/reports/ReportsDialog.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2019 KeePassXC Team <team@keepassxc.org>
+ * Copyright (C) 2021 KeePassXC Team <team@keepassxc.org>
*
* 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
@@ -21,6 +21,10 @@
#include "ReportsPageHealthcheck.h"
#include "ReportsPageHibp.h"
#include "ReportsPageStatistics.h"
+#ifdef WITH_XC_BROWSER
+#include "ReportsPageBrowserStatistics.h"
+#include "ReportsWidgetBrowserStatistics.h"
+#endif
#include "ReportsWidgetHealthcheck.h"
#include "ReportsWidgetHibp.h"
@@ -58,14 +62,20 @@ ReportsDialog::ReportsDialog(QWidget* parent)
, m_healthPage(new ReportsPageHealthcheck())
, m_hibpPage(new ReportsPageHibp())
, m_statPage(new ReportsPageStatistics())
+#ifdef WITH_XC_BROWSER
+ , m_browserStatPage(new ReportsPageBrowserStatistics())
+#endif
, m_editEntryWidget(new EditEntryWidget(this))
{
m_ui->setupUi(this);
connect(m_ui->buttonBox, SIGNAL(rejected()), SLOT(reject()));
+ addPage(m_statPage);
+#ifdef WITH_XC_BROWSER
+ addPage(m_browserStatPage);
+#endif
addPage(m_healthPage);
addPage(m_hibpPage);
- addPage(m_statPage);
m_ui->stackedWidget->setCurrentIndex(0);
@@ -77,6 +87,11 @@ ReportsDialog::ReportsDialog(QWidget* parent)
connect(m_ui->categoryList, SIGNAL(categoryChanged(int)), m_ui->stackedWidget, SLOT(setCurrentIndex(int)));
connect(m_healthPage->m_healthWidget, SIGNAL(entryActivated(Entry*)), SLOT(entryActivationSignalReceived(Entry*)));
connect(m_hibpPage->m_hibpWidget, SIGNAL(entryActivated(Entry*)), SLOT(entryActivationSignalReceived(Entry*)));
+#ifdef WITH_XC_BROWSER
+ connect(m_browserStatPage->m_browserWidget,
+ SIGNAL(entryActivated(Entry*)),
+ SLOT(entryActivationSignalReceived(Entry*)));
+#endif
connect(m_editEntryWidget, SIGNAL(editFinished(bool)), SLOT(switchToMainView(bool)));
}
@@ -142,6 +157,11 @@ void ReportsDialog::switchToMainView(bool previousDialogAccepted)
} else if (m_sender == m_hibpPage->m_hibpWidget) {
m_hibpPage->m_hibpWidget->refreshAfterEdit();
}
+#ifdef WITH_XC_BROWSER
+ if (m_sender == m_browserStatPage->m_browserWidget) {
+ m_browserStatPage->m_browserWidget->calculateBrowserStatistics();
+ }
+#endif
}
// Don't process the same sender twice
diff --git a/src/gui/reports/ReportsDialog.h b/src/gui/reports/ReportsDialog.h
index 99da7f25f..25cb623eb 100644
--- a/src/gui/reports/ReportsDialog.h
+++ b/src/gui/reports/ReportsDialog.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2019 KeePassXC Team <team@keepassxc.org>
+ * Copyright (C) 2021 KeePassXC Team <team@keepassxc.org>
*
* 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
@@ -29,6 +29,9 @@ class QTabWidget;
class ReportsPageHealthcheck;
class ReportsPageHibp;
class ReportsPageStatistics;
+#ifdef WITH_XC_BROWSER
+class ReportsPageBrowserStatistics;
+#endif
namespace Ui
{
@@ -74,6 +77,9 @@ private:
const QSharedPointer<ReportsPageHealthcheck> m_healthPage;
const QSharedPointer<ReportsPageHibp> m_hibpPage;
const QSharedPointer<ReportsPageStatistics> m_statPage;
+#ifdef WITH_XC_BROWSER
+ const QSharedPointer<ReportsPageBrowserStatistics> m_browserStatPage;
+#endif
QPointer<EditEntryWidget> m_editEntryWidget;
QWidget* m_sender = nullptr;
diff --git a/src/gui/reports/ReportsPageBrowserStatistics.cpp b/src/gui/reports/ReportsPageBrowserStatistics.cpp
new file mode 100644
index 000000000..97325745c
--- /dev/null
+++ b/src/gui/reports/ReportsPageBrowserStatistics.cpp
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2021 KeePassXC Team <team@keepassxc.org>
+ *
+ * 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 "ReportsPageBrowserStatistics.h"
+
+#include "ReportsWidgetBrowserStatistics.h"
+#include "gui/Icons.h"
+
+ReportsPageBrowserStatistics::ReportsPageBrowserStatistics()
+ : m_browserWidget(new ReportsWidgetBrowserStatistics())
+{
+}
+
+QString ReportsPageBrowserStatistics::name()
+{
+ return QObject::tr("Browser Statistics");
+}
+
+QIcon ReportsPageBrowserStatistics::icon()
+{
+ return icons()->icon("internet-web-browser");
+}
+
+QWidget* ReportsPageBrowserStatistics::createWidget()
+{
+ return m_browserWidget;
+}
+
+void ReportsPageBrowserStatistics::loadSettings(QWidget* widget, QSharedPointer<Database> db)
+{
+ const auto settingsWidget = reinterpret_cast<ReportsWidgetBrowserStatistics*>(widget);
+ settingsWidget->loadSettings(db);
+}
+
+void ReportsPageBrowserStatistics::saveSettings(QWidget* widget)
+{
+ const auto settingsWidget = reinterpret_cast<ReportsWidgetBrowserStatistics*>(widget);
+ settingsWidget->saveSettings();
+}
diff --git a/src/gui/reports/ReportsPageBrowserStatistics.h b/src/gui/reports/ReportsPageBrowserStatistics.h
new file mode 100644
index 000000000..fb1b20a9f
--- /dev/null
+++ b/src/gui/reports/ReportsPageBrowserStatistics.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2021 KeePassXC Team <team@keepassxc.org>
+ *
+ * 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 KEEPASSXC_REPORTSPAGEBROWSERSTATISTICS_H
+#define KEEPASSXC_REPORTSPAGEBROWSERSTATISTICS_H
+
+#include "ReportsDialog.h"
+
+class ReportsWidgetBrowserStatistics;
+
+class ReportsPageBrowserStatistics : public IReportsPage
+{
+public:
+ ReportsWidgetBrowserStatistics* m_browserWidget;
+
+ ReportsPageBrowserStatistics();
+
+ QString name() override;
+ QIcon icon() override;
+ QWidget* createWidget() override;
+ void loadSettings(QWidget* widget, QSharedPointer<Database> db) override;
+ void saveSettings(QWidget* widget) override;
+};
+
+#endif // KEEPASSXC_REPORTSPAGEBROWSERSTATISTICS_H
diff --git a/src/gui/reports/ReportsWidgetBrowserStatistics.cpp b/src/gui/reports/ReportsWidgetBrowserStatistics.cpp
new file mode 100644
index 000000000..1a3ad5d7e
--- /dev/null
+++ b/src/gui/reports/ReportsWidgetBrowserStatistics.cpp
@@ -0,0 +1,372 @@
+/*
+ * Copyright (C) 2021 KeePassXC Team <team@keepassxc.org>
+ *
+ * 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 "ReportsWidgetBrowserStatistics.h"
+#include "ui_ReportsWidgetBrowserStatistics.h"
+
+#include "browser/BrowserService.h"
+#include "core/AsyncTask.h"
+#include "core/Group.h"
+#include "core/Metadata.h"
+#include "gui/GuiTools.h"
+#include "gui/Icons.h"
+#include "gui/styles/StateColorPalette.h"
+
+#include <QJsonDocument>
+#include <QJsonObject>
+#include <QMenu>
+#include <QShortcut>
+#include <QSortFilterProxyModel>
+#include <QStandardItemModel>
+
+namespace
+{
+ class BrowserStatistics
+ {
+ public:
+ struct Item
+ {
+ QPointer<Group> group;
+ QPointer<Entry> entry;
+ bool hasUrls;
+ bool hasSettings;
+ bool exclude = false;
+
+ Item(Group* g, Entry* e, bool hU, bool hS)
+ : group(g)
+ , entry(e)
+ , hasUrls(hU)
+ , hasSettings(hS)
+ , exclude(e->excludeFromReports())
+ {
+ }
+ };
+
+ explicit BrowserStatistics(QSharedPointer<Database>);
+
+ const QList<QSharedPointer<Item>>& items() const
+ {
+ return m_items;
+ }
+
+ private:
+ QSharedPointer<Database> m_db;
+ QList<QSharedPointer<Item>> m_items;
+ };
+} // namespace
+
+BrowserStatistics::BrowserStatistics(QSharedPointer<Database> db)
+ : m_db(db)
+{
+ for (auto group : db->rootGroup()->groupsRecursive(true)) {
+ // Skip recycle bin
+ if (group->isRecycled()) {
+ continue;
+ }
+
+ for (auto entry : group->entries()) {
+ if (entry->isRecycled()) {
+ continue;
+ }
+
+ auto hasUrls = !entry->getAllUrls().isEmpty();
+ auto hasSettings = entry->customData()->contains(BrowserService::KEEPASSXCBROWSER_NAME);
+
+ const auto item = QSharedPointer<Item>(new Item(group, entry, hasUrls, hasSettings));
+ m_items.append(item);
+ }
+ }
+}
+
+ReportsWidgetBrowserStatistics::ReportsWidgetBrowserStatistics(QWidget* parent)
+ : QWidget(parent)
+ , m_ui(new Ui::ReportsWidgetBrowserStatistics())
+ , m_referencesModel(new QStandardItemModel(this))
+ , m_modelProxy(new QSortFilterProxyModel(this))
+{
+ m_ui->setupUi(this);
+
+ m_modelProxy->setSourceModel(m_referencesModel.data());
+ m_modelProxy->setSortLocaleAware(true);
+ m_ui->browserStatisticsTableView->setModel(m_modelProxy.data());
+ m_ui->browserStatisticsTableView->horizontalHeader()->setSectionResizeMode(QHeaderView::Interactive);
+ m_ui->browserStatisticsTableView->verticalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents);
+
+ connect(m_ui->browserStatisticsTableView,
+ SIGNAL(customContextMenuRequested(QPoint)),
+ SLOT(customMenuRequested(QPoint)));
+ connect(
+ m_ui->browserStatisticsTableView, SIGNAL(doubleClicked(QModelIndex)), SLOT(emitEntryActivated(QModelIndex)));
+ connect(m_ui->showEntriesWithUrlOnlyCheckBox, SIGNAL(stateChanged(int)), this, SLOT(calculateBrowserStatistics()));
+ connect(m_ui->showConnectedOnlyCheckBox, SIGNAL(stateChanged(int)), this, SLOT(calculateBrowserStatistics()));
+ connect(m_ui->excludeExpired, SIGNAL(stateChanged(int)), this, SLOT(calculateBrowserStatistics()));
+
+ new QShortcut(Qt::Key_Delete, this, SLOT(deleteSelectedEntries()));
+}
+
+ReportsWidgetBrowserStatistics::~ReportsWidgetBrowserStatistics()
+{
+}
+
+void ReportsWidgetBrowserStatistics::addStatisticsRow(bool hasUrls,
+ bool hasSettings,
+ Group* group,
+ Entry* entry,
+ bool excluded)
+{
+ StateColorPalette statePalette;
+
+ auto urlList = entry->getAllUrls();
+ auto urlToolTip = hasUrls ? tr("List of entry URLs") : tr("Entry has no URLs set");
+
+ auto browserConfig = getBrowserConfigFromEntry(entry);
+ auto allowedUrlsList = browserConfig["Allow"];
+ auto deniedUrlsList = browserConfig["Deny"];
+
+ auto allowedUrlsToolTip = hasSettings ? tr("Allowed URLs") : tr("Entry has no Browser Integration settings");
+ auto deniedUrlsToolTip = hasSettings ? tr("Denied URLs") : tr("Entry has no Browser Integration settings");
+
+ auto title = entry->title();
+ if (excluded) {
+ title.append(tr(" (Excluded)"));
+ }
+
+ auto row = QList<QStandardItem*>();
+ row << new QStandardItem(Icons::entryIconPixmap(entry), title);
+ row << new QStandardItem(Icons::groupIconPixmap(group), group->hierarchy().join("/"));
+ row << new QStandardItem(urlList.join('\n'));
+ row << new QStandardItem(allowedUrlsList.join('\n'));
+ row << new QStandardItem(deniedUrlsList.join('\n'));
+
+ // Set tooltips
+ row[2]->setToolTip(urlToolTip);
+ row[3]->setToolTip(allowedUrlsToolTip);
+ row[4]->setToolTip(deniedUrlsToolTip);
+ if (excluded) {
+ row[0]->setToolTip(tr("This entry is being excluded from reports"));
+ }
+
+ // Store entry pointer per table row (used in double click handler)
+ m_referencesModel->appendRow(row);
+ m_rowToEntry.append({group, entry});
+}
+
+void ReportsWidgetBrowserStatistics::loadSettings(QSharedPointer<Database> db)
+{
+ m_db = std::move(db);
+ m_statisticsCalculated = false;
+ m_referencesModel->clear();
+ m_rowToEntry.clear();
+
+ auto row = QList<QStandardItem*>();
+ row << new QStandardItem(tr("Please wait, browser statistics is being calculated…"));
+ m_referencesModel->appendRow(row);
+}
+
+void ReportsWidgetBrowserStatistics::showEvent(QShowEvent* event)
+{
+ QWidget::showEvent(event);
+
+ if (!m_statisticsCalculated) {
+ // Perform stats calculation on next event loop to allow widget to appear
+ m_statisticsCalculated = true;
+ QTimer::singleShot(0, this, SLOT(calculateBrowserStatistics()));
+ }
+}
+
+void ReportsWidgetBrowserStatistics::calculateBrowserStatistics()
+{
+ m_referencesModel->clear();
+
+ // Perform the statistics check
+ const QScopedPointer<BrowserStatistics> browserStatistics(
+ AsyncTask::runAndWaitForFuture([this] { return new BrowserStatistics(m_db); }));
+
+ const auto showExcluded = m_ui->showConnectedOnlyCheckBox->isChecked();
+ const auto showEntriesWithUrlOnly = m_ui->showEntriesWithUrlOnlyCheckBox->isChecked();
+ const auto showOnlyEntriesWithSettings = m_ui->showConnectedOnlyCheckBox->isChecked();
+
+ // Display the entries
+ m_rowToEntry.clear();
+ for (const auto& item : browserStatistics->items()) {
+ auto excluded = item->exclude || (item->entry->isExpired() && m_ui->excludeExpired->isChecked());
+ if (excluded && !showExcluded) {
+ // Exclude this entry from the report
+ continue;
+ }
+
+ // Exclude this entry if URL are not set
+ if (showEntriesWithUrlOnly && !item->hasUrls) {
+ continue;
+ }
+
+ // Exclude this entry if it doesn't have any Browser Integration settings
+ if (showOnlyEntriesWithSettings
+ && !item->entry->customData()->contains(BrowserService::KEEPASSXCBROWSER_NAME)) {
+ continue;
+ }
+
+ // Show the entry in the report
+ addStatisticsRow(item->hasUrls, item->hasSettings, item->group, item->entry, item->exclude);
+ }
+
+ // Set the table header
+ if (m_referencesModel->rowCount() == 0) {
+ m_referencesModel->setHorizontalHeaderLabels(
+ QStringList() << tr("No entries with a URL, or none has browser extension settings saved."));
+ } else {
+ m_referencesModel->setHorizontalHeaderLabels(QStringList() << tr("Title") << tr("Path") << tr("URLs")
+ << tr("Allowed URLs") << tr("Denied URLs"));
+ m_ui->browserStatisticsTableView->sortByColumn(0, Qt::AscendingOrder);
+ }
+
+ m_ui->browserStatisticsTableView->resizeColumnsToContents();
+}
+
+void ReportsWidgetBrowserStatistics::emitEntryActivated(const QModelIndex& index)
+{
+ if (!index.isValid()) {
+ return;
+ }
+
+ auto mappedIndex = m_modelProxy->mapToSource(index);
+ const auto row = m_rowToEntry[mappedIndex.row()];
+ const auto group = row.first;
+ const auto entry = row.second;
+
+ if (group && entry) {
+ emit entryActivated(const_cast<Entry*>(entry));
+ }
+}
+
+void ReportsWidgetBrowserStatistics::customMenuRequested(QPoint pos)
+{
+ auto selected = m_ui->browserStatisticsTableView->selectionModel()->selectedRows();
+ if (selected.isEmpty()) {
+ return;
+ }
+
+ // Create the context menu
+ const auto menu = new QMenu(this);
+
+ // Create the "edit entry" menu item (only if 1 row is selected)
+ if (selected.size() == 1) {
+ const auto edit = new QAction(icons()->icon("entry-edit"), tr("Edit Entry…"), this);
+ menu->addAction(edit);
+ connect(edit, &QAction::triggered, edit, [this, selected] {
+ auto row = m_modelProxy->mapToSource(selected[0]).row();
+ auto entry = m_rowToEntry[row].second;
+ emit entryActivated(entry);
+ });
+ }
+
+ // Create the "delete entry" menu item
+ const auto delEntry = new QAction(icons()->icon("entry-delete"), tr("Delete Entry(s)…", "", selected.size()), this);
+ menu->addAction(delEntry);
+ connect(delEntry, &QAction::triggered, this, &ReportsWidgetBrowserStatistics::deleteSelectedEntries);
+
+ // Create the "exclude from reports" menu item
+ const auto exclude = new QAction(icons()->icon("reports-exclude"), tr("Exclude from reports"), this);
+
+ bool isExcluded = false;
+ for (auto index : selected) {
+ auto row = m_modelProxy->mapToSource(index).row();
+ auto entry = m_rowToEntry[row].second;
+ if (entry && entry->excludeFromReports()) {
+ // If at least one entry is excluded switch to inclusion
+ isExcluded = true;
+ break;
+ }
+ }
+ exclude->setCheckable(true);
+ exclude->setChecked(isExcluded);
+
+ menu->addAction(exclude);
+ connect(exclude, &QAction::toggled, exclude, [this, selected](bool state) {
+ for (auto index : selected) {
+ auto row = m_modelProxy->mapToSource(index).row();
+ auto entry = m_rowToEntry[row].second;
+ if (entry) {
+ entry->setExcludeFromReports(state);
+ }
+ }
+ calculateBrowserStatistics();
+ });
+
+ // Show the context menu
+ menu->popup(m_ui->browserStatisticsTableView->viewport()->mapToGlobal(pos));
+}
+
+void ReportsWidgetBrowserStatistics::saveSettings()
+{
+ // Nothing to do - the tab is passive
+}
+
+void ReportsWidgetBrowserStatistics::deleteSelectedEntries()
+{
+ QList<Entry*> selectedEntries;
+ for (auto index : m_ui->browserStatisticsTableView->selectionModel()->selectedRows()) {
+ auto row = m_modelProxy->mapToSource(index).row();
+ auto entry = m_rowToEntry[row].second;
+ if (entry) {
+ selectedEntries << entry;
+ }
+ }
+
+ bool permanent = !m_db->metadata()->recycleBinEnabled();
+ if (GuiTools::confirmDeleteEntries(this, selectedEntries, permanent)) {
+ GuiTools::deleteEntriesResolveReferences(this, selectedEntries, permanent);
+ }
+
+ calculateBrowserStatistics();
+}
+
+QMap<QString, QStringList> ReportsWidgetBrowserStatistics::getBrowserConfigFromEntry(Entry* entry) const
+{
+ QMap<QString, QStringList> configList;
+
+ auto config = entry->customData()->value(BrowserService::KEEPASSXCBROWSER_NAME);
+ if (!config.isEmpty()) {
+ QJsonDocument doc = QJsonDocument::fromJson(config.toUtf8());
+ if (!doc.isNull()) {
+ auto jsonObject = doc.object();
+ auto allowedSites = jsonObject["Allow"].toArray();
+ auto deniedSites = jsonObject["Deny"].toArray();
+
+ QStringList allowed;
+ foreach (const auto& value, allowedSites) {
+ auto url = value.toString();
+ if (!url.isEmpty()) {
+ allowed << url;
+ }
+ }
+
+ QStringList denied;
+ foreach (const auto& value, deniedSites) {
+ auto url = value.toString();
+ if (!url.isEmpty()) {
+ denied << url;
+ }
+ }
+
+ configList.insert("Allow", allowed);
+ configList.insert("Deny", denied);
+ }
+ }
+
+ return configList;
+}
diff --git a/src/gui/reports/ReportsWidgetBrowserStatistics.h b/src/gui/reports/ReportsWidgetBrowserStatistics.h
new file mode 100644
index 000000000..8aa6651ee
--- /dev/null
+++ b/src/gui/reports/ReportsWidgetBrowserStatistics.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2021 KeePassXC Team <team@keepassxc.org>
+ *
+ * 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 KEEPASSXC_REPORTSWIDGETBROWSERSTATISTICS_H
+#define KEEPASSXC_REPORTSWIDGETBROWSERSTATISTICS_H
+
+#include "gui/entry/EntryModel.h"
+#include <QWidget>
+
+class Database;
+class Entry;
+class Group;
+class PasswordHealth;
+class QSortFilterProxyModel;
+class QStandardItemModel;
+
+namespace Ui
+{
+ class ReportsWidgetBrowserStatistics;
+}
+
+class ReportsWidgetBrowserStatistics : public QWidget
+{
+ Q_OBJECT
+public:
+ explicit ReportsWidgetBrowserStatistics(QWidget* parent = nullptr);
+ ~ReportsWidgetBrowserStatistics() override;
+
+ void loadSettings(QSharedPointer<Database> db);
+ void saveSettings();
+
+protected:
+ void showEvent(QShowEvent* event) override;
+
+signals:
+ void entryActivated(Entry*);
+
+public slots:
+ void calculateBrowserStatistics();
+ void emitEntryActivated(const QModelIndex& index);
+ void customMenuRequested(QPoint);
+ void deleteSelectedEntries();
+
+private:
+ void addStatisticsRow(bool hasUrls, bool hasSettings, Group*, Entry*, bool);
+ QMap<QString, QStringList> getBrowserConfigFromEntry(Entry* entry) const;
+
+ QScopedPointer<Ui::ReportsWidgetBrowserStatistics> m_ui;
+
+ bool m_statisticsCalculated = false;
+ QScopedPointer<QStandardItemModel> m_referencesModel;
+ QScopedPointer<QSortFilterProxyModel> m_modelProxy;
+ QSharedPointer<Database> m_db;
+ QList<QPair<Group*, Entry*>> m_rowToEntry;
+};
+
+#endif // KEEPASSXC_REPORTSWIDGETBROWSERSTATISTICS_H
diff --git a/src/gui/reports/ReportsWidgetBrowserStatistics.ui b/src/gui/reports/ReportsWidgetBrowserStatistics.ui
new file mode 100644
index 000000000..4236da6e1
--- /dev/null
+++ b/src/gui/reports/ReportsWidgetBrowserStatistics.ui
@@ -0,0 +1,100 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>ReportsWidgetBrowserStatistics</class>
+ <widget class="QWidget" name="ReportsWidgetBrowserStatistics">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>505</width>
+ <height>379</height>
+ </rect>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout" stretch="0,0,0,0">
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item>
+ <widget class="QTableView" name="browserStatisticsTableView">
+ <property name="contextMenuPolicy">
+ <enum>Qt::CustomContextMenu</enum>
+ </property>
+ <property name="editTriggers">
+ <set>QAbstractItemView::NoEditTriggers</set>
+ </property>
+ <property name="showDropIndicator" stdset="0">
+ <bool>false</bool>
+ </property>
+ <property name="alternatingRowColors">
+ <bool>true</bool>
+ </property>
+ <property name="selectionBehavior">
+ <enum>QAbstractItemView::SelectRows</enum>
+ </property>
+ <property name="textElideMode">
+ <enum>Qt::ElideMiddle</enum>
+ </property>
+ <property name="sortingEnabled">
+ <bool>true</bool>
+ </property>
+ <attribute name="horizontalHeaderStretchLastSection">
+ <bool>true</bool>
+ </attribute>
+ <attribute name="verticalHeaderVisible">
+ <bool>false</bool>
+ </attribute>
+ </widget>
+ </item>
+ <item>
+ <widget class="QCheckBox" name="excludeExpired">
+ <property name="text">
+ <string>Exclude expired entries from the report</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QCheckBox" name="showEntriesWithUrlOnlyCheckBox">
+ <property name="text">
+ <string>Show only entries which have URL set</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QCheckBox" name="showConnectedOnlyCheckBox">
+ <property name="text">
+ <string>Show only entries which have browser settings in custom data</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="tipLabel">
+ <property name="font">
+ <font>
+ <italic>true</italic>
+ </font>
+ </property>
+ <property name="text">
+ <string>Double-click entries to edit.</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <tabstops>
+ <tabstop>browserStatisticsTableView</tabstop>
+ <tabstop>excludeExpired</tabstop>
+ <tabstop>showEntriesWithUrlOnlyCheckBox</tabstop>
+ <tabstop>showConnectedOnlyCheckBox</tabstop>
+ </tabstops>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/src/gui/styles/StateColorPalette.cpp b/src/gui/styles/StateColorPalette.cpp
index c729e3269..8a2b563da 100644
--- a/src/gui/styles/StateColorPalette.cpp
+++ b/src/gui/styles/StateColorPalette.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2020 KeePassXC Team <team@keepassxc.org>
+ * Copyright (C) 2021 KeePassXC Team <team@keepassxc.org>
*
* 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
@@ -40,6 +40,9 @@ void StateColorPalette::initDefaultPaletteLight()
setColor(ColorRole::HealthWeak, QStringLiteral("#FFD30F"));
setColor(ColorRole::HealthOk, QStringLiteral("#5EA10E"));
setColor(ColorRole::HealthExcellent, QStringLiteral("#118f17"));
+
+ setColor(ColorRole::True, QStringLiteral("#5EA10E"));
+ setColor(ColorRole::False, QStringLiteral("#C43F31"));
}
void StateColorPalette::initDefaultPaletteDark()
@@ -54,4 +57,7 @@ void StateColorPalette::initDefaultPaletteDark()
setColor(ColorRole::HealthWeak, QStringLiteral("#F0C400"));
setColor(ColorRole::HealthOk, QStringLiteral("#608A22"));
setColor(ColorRole::HealthExcellent, QStringLiteral("#1F8023"));
+
+ setColor(ColorRole::True, QStringLiteral("#608A22"));
+ setColor(ColorRole::False, QStringLiteral("#C43F31"));
}
diff --git a/src/gui/styles/StateColorPalette.h b/src/gui/styles/StateColorPalette.h
index 408fe032a..082f6a893 100644
--- a/src/gui/styles/StateColorPalette.h
+++ b/src/gui/styles/StateColorPalette.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2020 KeePassXC Team <team@keepassxc.org>
+ * Copyright (C) 2021 KeePassXC Team <team@keepassxc.org>
*
* 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
@@ -43,7 +43,9 @@ public:
HealthPoor,
HealthWeak,
HealthOk,
- HealthExcellent
+ HealthExcellent,
+ True,
+ False
};
inline void setColor(ColorRole role, const QColor& color)