diff --git a/src/core/Group.cpp b/src/core/Group.cpp index 422c4bbb1..7b93dee21 100644 --- a/src/core/Group.cpp +++ b/src/core/Group.cpp @@ -1284,6 +1284,22 @@ void Group::setPreviousParentGroup(const Group* group) void Group::setExcludeFromReports(bool excluded) { customData()->set(CustomData::ExcludeFromReportsLegacy, excluded ? TRUE_STR : FALSE_STR); + + // Clear out the exclusion flag on entries when we set it on the + // group because it'll make it easier to individually set it for an + // entry later on + if (excluded) { + for (auto &entry : m_entries) { + entry->setExcludeFromReports(false); + } + } +} + +void Group::markAllEntriesExcludedFromReports() +{ + for (auto &entry : m_entries) { + entry->setExcludeFromReports(true); + } } bool Group::excludeFromReports() const diff --git a/src/core/Group.h b/src/core/Group.h index 0fb633035..b6cfbfe71 100644 --- a/src/core/Group.h +++ b/src/core/Group.h @@ -142,6 +142,7 @@ public: void setPreviousParentGroup(const Group* group); void setPreviousParentGroupUuid(const QUuid& uuid); void setExcludeFromReports(bool exclude); + void markAllEntriesExcludedFromReports(); bool canUpdateTimeinfo() const; void setUpdateTimeinfo(bool value); diff --git a/src/gui/reports/ReportsWidgetBrowserStatistics.cpp b/src/gui/reports/ReportsWidgetBrowserStatistics.cpp index 8feedf670..e5515299c 100644 --- a/src/gui/reports/ReportsWidgetBrowserStatistics.cpp +++ b/src/gui/reports/ReportsWidgetBrowserStatistics.cpp @@ -300,21 +300,33 @@ void ReportsWidgetBrowserStatistics::customMenuRequested(QPoint pos) &ReportsWidgetBrowserStatistics::deletePluginDataFromSelectedEntries); // Create the "exclude from reports" menu item - const auto exclude = new QAction(icons()->icon("reports-exclude"), tr("Exclude from reports"), this); + const auto exclude = new QAction(icons()->icon("reports-exclude"), tr("Exclude Entry(s) from reports"), this); + const auto excludeGroups = 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].second; - if (entry && entry->excludeFromReports()) { + if (entry) { // If at least one entry is excluded switch to inclusion - isExcluded = true; + if (entry->excludeFromReports()) { + isExcluded = true; + } + if (entry->group()->excludeFromReports()) { + isGroupExcluded = true; + } + break; } } exclude->setCheckable(true); exclude->setChecked(isExcluded); + excludeGroups->setCheckable(true); + exclude->setChecked(isGroupExcluded); + menu->addAction(exclude); connect(exclude, &QAction::toggled, exclude, [this, selected](bool state) { for (auto index : selected) { @@ -327,6 +339,18 @@ void ReportsWidgetBrowserStatistics::customMenuRequested(QPoint pos) calculateBrowserStatistics(); }); + menu->addAction(excludeGroups); + connect(excludeGroups, &QAction::toggled, excludeGroups, [this, selected](bool state) { + for (const auto index : selected) { + auto row = m_modelProxy->mapToSource(index).row(); + auto entry = m_rowToEntry[row].second; + if (entry) { + entry->group()->setExcludeFromReports(state); + } + } + calculateBrowserStatistics(); + }); + // Show the context menu menu->popup(m_ui->browserStatisticsTableView->viewport()->mapToGlobal(pos)); } diff --git a/src/gui/reports/ReportsWidgetHealthcheck.cpp b/src/gui/reports/ReportsWidgetHealthcheck.cpp index a6062aee2..1e87df6de 100644 --- a/src/gui/reports/ReportsWidgetHealthcheck.cpp +++ b/src/gui/reports/ReportsWidgetHealthcheck.cpp @@ -25,6 +25,7 @@ #include "gui/GuiTools.h" #include "gui/Icons.h" #include "gui/styles/StateColorPalette.h" +#include "gui/MessageBox.h" #include #include @@ -348,28 +349,92 @@ void ReportsWidgetHealthcheck::customMenuRequested(QPoint pos) connect(delEntry, &QAction::triggered, this, &ReportsWidgetHealthcheck::deleteSelectedEntries); // Create the "exclude from reports" menu item - const auto exclude = new QAction(icons()->icon("reports-exclude"), tr("Exclude from reports"), this); + 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].second; - if (entry && entry->excludeFromReports()) { + if (entry) { // If at least one entry is excluded switch to inclusion - isExcluded = true; + if (entry->excludeFromReports() || entry->group()->excludeFromReports()) { + isExcluded = true; + } + if (entry->group()->excludeFromReports()) { + isGroupExcluded = true; + } + break; } } - exclude->setCheckable(true); - exclude->setChecked(isExcluded); + 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].second; + + 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); + } + } + } + } - 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 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(state); + entry->setExcludeFromReports(checked); + } + } + calculateHealth(); + }); + + 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].second; + if (entry) { + entry->group()->setExcludeFromReports(checked); } } calculateHealth();