diff --git a/src/gui/reports/ReportsWidgetHibp.cpp b/src/gui/reports/ReportsWidgetHibp.cpp index 21e8ac7fd..7568eb903 100644 --- a/src/gui/reports/ReportsWidgetHibp.cpp +++ b/src/gui/reports/ReportsWidgetHibp.cpp @@ -24,42 +24,17 @@ #include "gui/GuiTools.h" #include "gui/Icons.h" #include "gui/MessageBox.h" +#include "gui/reports/ProxyModels.h" #include #include -#include #include #include -namespace -{ - class ReportSortProxyModel : public QSortFilterProxyModel - { - public: - ReportSortProxyModel(QObject* parent) - : QSortFilterProxyModel(parent){}; - ~ReportSortProxyModel() override = default; - - protected: - bool lessThan(const QModelIndex& left, const QModelIndex& right) const override - { - // Sort count column by user data - if (left.column() == 2) { - return sourceModel()->data(left, Qt::UserRole).toInt() - < sourceModel()->data(right, Qt::UserRole).toInt(); - } - // Otherwise use default sorting - return QSortFilterProxyModel::lessThan(left, right); - } - }; -} // namespace - ReportsWidgetHibp::ReportsWidgetHibp(QWidget* parent) - : QWidget(parent) + : ReportsWidgetBase(parent, SortProxyModelKind::Hibp) , m_ui(new Ui::ReportsWidgetHibp()) - , m_referencesModel(new QStandardItemModel(this)) - , m_modelProxy(new ReportSortProxyModel(this)) { m_ui->setupUi(this); @@ -183,7 +158,7 @@ void ReportsWidgetHibp::makeHibpTable() m_referencesModel->appendRow(row); // Store entry pointer per table row (used in double click handler) - m_rowToEntry.append(entry); + m_rowToEntry.append({group, entry}); } // If there was an error, append the error message to the table @@ -318,12 +293,12 @@ void ReportsWidgetHibp::emitEntryActivated(const QModelIndex& index) // Find which database entry was double-clicked auto mappedIndex = m_modelProxy->mapToSource(index); const auto entry = m_rowToEntry[mappedIndex.row()]; - if (entry) { + if (entry.second) { // Found it, invoke entry editor - m_editedEntry = entry; - m_editedPassword = entry->password(); - m_editedExcluded = entry->excludeFromReports(); - emit entryActivated(const_cast(entry)); + m_editedEntry = entry.second; + m_editedPassword = entry.second->password(); + m_editedExcluded = entry.second->excludeFromReports(); + emit entryActivated(const_cast(entry.second)); } } @@ -362,171 +337,28 @@ void ReportsWidgetHibp::refreshAfterEdit() void ReportsWidgetHibp::customMenuRequested(QPoint pos) { - auto selected = m_ui->hibpTableView->selectionModel()->selectedRows(); - if (selected.isEmpty()) { + // Create the context menu + const auto menu = customMenuRequestedBase(); + + if(!menu) { return; } - // Create the context menu - const auto menu = new QMenu(this); - - // Create the "edit entry" menu item 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]; - emit entryActivated(entry); - }); - } - - // Create the "Expire entry" menu item - const auto expEntry = new QAction(icons()->icon("entry-expire"), tr("Expire Entry(s)…", "", selected.size()), this); - menu->addAction(expEntry); - connect(expEntry, &QAction::triggered, this, &ReportsWidgetHibp::expireSelectedEntries); - - // 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, &ReportsWidgetHibp::deleteSelectedEntries); - - // Create the "exclude from reports" menu item - const auto excludeAction = new QAction(icons()->icon("reports-exclude"), tr("Exclude Entry(s) from reports"), this); - const auto excludeGroupsAction = - new QAction(icons()->icon("reports-exclude"), tr("Exclude Group(s) from reports"), this); - - bool isExcluded = false; - bool isGroupExcluded = false; - - for (auto index : selected) { - auto row = m_modelProxy->mapToSource(index).row(); - auto entry = m_rowToEntry[row]; - if (entry) { - // If at least one entry is excluded switch to inclusion - if (entry->excludeFromReports() || entry->group()->excludeFromReports()) { - isExcluded = true; - } - if (entry->group()->excludeFromReports()) { - isGroupExcluded = true; - } - - break; - } - } - - excludeAction->setCheckable(true); - excludeAction->setChecked(isExcluded); - - excludeGroupsAction->setCheckable(true); - excludeGroupsAction->setChecked(isGroupExcluded); - - menu->addAction(excludeAction); - connect(excludeAction, &QAction::toggled, excludeAction, [this, selected](bool checked) { - QSet groups; - - // If we are including entries (checked is false) but a group is excluded, ask the user if they - // would like to include the rest of the group as well (or keep it excluded). - // If they exclude it, we need to include the whole group, and then exclude - // the entries that aren't selected here. - if (!checked) { - for (const auto index : selected) { - auto row = m_modelProxy->mapToSource(index).row(); - auto entry = m_rowToEntry[row]; - - if (entry) { - auto* group = entry->group(); - if (group->excludeFromReports() && !groups.contains(group)) { - QString msg = tr("The Group for \"%1\" is excluded. Would you like to include all Entries from " - "there as well?") - .arg(entry->title()); - auto response = MessageBox::question(this, - tr("Include Group?"), - msg, - MessageBox::Yes | MessageBox::No | MessageBox::Cancel, - MessageBox::No); - - if (response == MessageBox::Cancel) { - return; - } else if (response == MessageBox::Yes) { - group->setExcludeFromReports(false); - } else if (response == MessageBox::No) { - // We'll exclude all entries from the group here and then - // include the selected ones below - group->setExcludeFromReports(false); - group->markAllEntriesExcludedFromReports(); - } - - groups.insert(group); - } - } - } - } - - for (auto index : selected) { - auto row = m_modelProxy->mapToSource(index).row(); - auto entry = m_rowToEntry[row]; - - // If the containing group is excluded but the user wants to include - // this entry, ask if they want to keep the remaining items in the group - // excluded or included - if (entry) { - entry->setExcludeFromReports(checked); - } - } - makeHibpTable(); - }); - - menu->addAction(excludeGroupsAction); - connect(excludeGroupsAction, &QAction::toggled, excludeGroupsAction, [this, selected](bool checked) { - for (const auto index : selected) { - auto row = m_modelProxy->mapToSource(index).row(); - auto entry = m_rowToEntry[row]; - if (entry) { - entry->group()->setExcludeFromReports(checked); - } - } - makeHibpTable(); - }); - // Show the context menu menu->popup(m_ui->hibpTableView->viewport()->mapToGlobal(pos)); } -QList ReportsWidgetHibp::getSelectedEntries() -{ - QList selectedEntries; - for (auto index : m_ui->hibpTableView->selectionModel()->selectedRows()) { - auto row = m_modelProxy->mapToSource(index).row(); - auto entry = m_rowToEntry[row]; - if (entry) { - selectedEntries << entry; - } - } - return selectedEntries; -} - -void ReportsWidgetHibp::expireSelectedEntries() -{ - for (auto entry : getSelectedEntries()) { - entry->expireNow(); - } - - makeHibpTable(); -} - -void ReportsWidgetHibp::deleteSelectedEntries() -{ - QList selectedEntries = getSelectedEntries(); - bool permanent = !m_db->metadata()->recycleBinEnabled(); - if (GuiTools::confirmDeleteEntries(this, selectedEntries, permanent)) { - GuiTools::deleteEntriesResolveReferences(this, selectedEntries, permanent); - } - - makeHibpTable(); -} - void ReportsWidgetHibp::saveSettings() { // nothing to do - the tab is passive } + +void ReportsWidgetHibp::updateWidget() +{ + makeHibpTable(); +} + +QTableView *ReportsWidgetHibp::getTableView() const +{ + return m_ui->hibpTableView; +} diff --git a/src/gui/reports/ReportsWidgetHibp.h b/src/gui/reports/ReportsWidgetHibp.h index 8e0d5e47b..5d6ec7e1f 100644 --- a/src/gui/reports/ReportsWidgetHibp.h +++ b/src/gui/reports/ReportsWidgetHibp.h @@ -20,6 +20,7 @@ #include "config-keepassx.h" #include "gui/entry/EntryModel.h" +#include "gui/reports/ReportsWidgetBase.h" #include @@ -32,13 +33,14 @@ class Entry; class Group; class QSortFilterProxyModel; class QStandardItemModel; +class QTableView; namespace Ui { class ReportsWidgetHibp; } -class ReportsWidgetHibp : public QWidget +class ReportsWidgetHibp : public ReportsWidgetBase { Q_OBJECT public: @@ -49,6 +51,10 @@ public: void saveSettings(); void refreshAfterEdit(); +protected: + void updateWidget() override; + QTableView *getTableView() const override; + signals: void entryActivated(Entry*); @@ -58,22 +64,15 @@ public slots: void fetchFailed(const QString& error); void makeHibpTable(); void customMenuRequested(QPoint); - QList getSelectedEntries(); - void expireSelectedEntries(); - void deleteSelectedEntries(); private: void startValidation(); static QString countToText(int count); QScopedPointer m_ui; - QScopedPointer m_referencesModel; - QScopedPointer m_modelProxy; - QSharedPointer m_db; QMap m_pwndPasswords; // Passwords we found to have been pwned (value is pwn count) QString m_error; // Error message if download failed, else empty - QList m_rowToEntry; // List index is table row QPointer m_editedEntry; // The entry we're currently editing QString m_editedPassword; // The old password of the entry we're editing bool m_editedExcluded; // The old "known bad" flag of the entry we're editing