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

github.com/owncloud/client.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorErik Verbruggen <erik@verbruggen.consulting>2021-09-24 17:36:41 +0300
committerHannah von Reth <vonreth@kde.org>2021-09-29 16:38:47 +0300
commit2397475f85908136570e1fd5051501e73b924295 (patch)
tree3e3a28ac85b4464c6ef0b324c6bc0e71cf2c0214 /src/gui/issueswidget.cpp
parentb6809421a9bfc0b3bd6a5bd6abb743318750c242 (diff)
Allow to filter issue table by issue type
Fixes: #9000
Diffstat (limited to 'src/gui/issueswidget.cpp')
-rw-r--r--src/gui/issueswidget.cpp158
1 files changed, 154 insertions, 4 deletions
diff --git a/src/gui/issueswidget.cpp b/src/gui/issueswidget.cpp
index b463187df..41a7b006a 100644
--- a/src/gui/issueswidget.cpp
+++ b/src/gui/issueswidget.cpp
@@ -24,7 +24,6 @@
#include "folderman.h"
#include "syncfileitem.h"
#include "folder.h"
-#include "models/expandingheaderview.h"
#include "models/models.h"
#include "openfilemanager.h"
#include "protocolwidget.h"
@@ -50,6 +49,60 @@ bool persistsUntilLocalDiscovery(const OCC::ProtocolItem &data)
}
namespace OCC {
+class SyncFileItemStatusSetSortFilterProxyModel : public QSortFilterProxyModel
+{
+public:
+ using StatusSet = std::array<bool, SyncFileItem::StatusCount>;
+
+ explicit SyncFileItemStatusSetSortFilterProxyModel(QObject *parent = nullptr)
+ : QSortFilterProxyModel(parent)
+ {
+ resetFilter();
+ }
+
+ ~SyncFileItemStatusSetSortFilterProxyModel() override
+ {
+ }
+
+ StatusSet filter() const
+ {
+ return _filter;
+ }
+
+ void setFilter(const StatusSet &newFilter)
+ {
+ if (_filter != newFilter) {
+ _filter = newFilter;
+ invalidateFilter();
+ }
+ }
+
+ void resetFilter()
+ {
+ StatusSet defaultFilter;
+ defaultFilter.fill(true);
+ defaultFilter[SyncFileItem::NoStatus] = false;
+ defaultFilter[SyncFileItem::Success] = false;
+ setFilter(defaultFilter);
+ }
+
+ bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const override
+ {
+ QModelIndex idx = sourceModel()->index(sourceRow, filterKeyColumn(), sourceParent);
+
+ bool ok = false;
+ int sourceData = sourceModel()->data(idx, filterRole()).toInt(&ok);
+ if (!ok) {
+ return false;
+ }
+
+ return _filter[static_cast<SyncFileItem::Status>(sourceData)];
+ }
+
+private:
+ StatusSet _filter;
+};
+
/**
* If more issues are reported than this they will not show up
* to avoid performance issues around sorting this many issues.
@@ -90,7 +143,12 @@ IssuesWidget::IssuesWidget(QWidget *parent)
_model = new ProtocolItemModel(20000, true, this);
_sortModel = new QSortFilterProxyModel(this);
_sortModel->setSourceModel(_model);
- _ui->_tableView->setModel(_sortModel);
+ _statusSortModel = new SyncFileItemStatusSetSortFilterProxyModel(this);
+ _statusSortModel->setSourceModel(_sortModel);
+ _statusSortModel->setSortRole(Qt::DisplayRole); // Sorting should be done based on the text in the column cells, but...
+ _statusSortModel->setFilterRole(Models::UnderlyingDataRole); // ... filtering should be done on the underlying enum value.
+ _statusSortModel->setFilterKeyColumn(static_cast<int>(ProtocolItemModel::ProtocolItemRole::Status));
+ _ui->_tableView->setModel(_statusSortModel);
auto header = new ExpandingHeaderView(QStringLiteral("ActivityErrorListHeaderV2"), _ui->_tableView);
_ui->_tableView->setHorizontalHeader(header);
@@ -100,8 +158,13 @@ IssuesWidget::IssuesWidget(QWidget *parent)
connect(_ui->_tableView, &QTreeView::customContextMenuRequested, this, &IssuesWidget::slotItemContextMenu);
_ui->_tableView->horizontalHeader()->setContextMenuPolicy(Qt::CustomContextMenu);
- connect(header, &QHeaderView::customContextMenuRequested, header, [header, this] {
- ProtocolWidget::showHeaderContextMenu(header, _sortModel);
+ connect(header, &QHeaderView::customContextMenuRequested, [this, header]() {
+ auto menu = showFilterMenu(header);
+ menu->addAction(tr("Reset column sizes"), header, [header] { header->resizeColumns(true); });
+ });
+
+ connect(_ui->_filterButton, &QAbstractButton::clicked, this, [this] {
+ showFilterMenu(_ui->_filterButton);
});
_ui->_tooManyIssuesWarning->hide();
@@ -131,6 +194,33 @@ IssuesWidget::~IssuesWidget()
delete _ui;
}
+QMenu *IssuesWidget::showFilterMenu(QWidget *parent)
+{
+ auto menu = new QMenu(parent);
+ menu->setAttribute(Qt::WA_DeleteOnClose);
+
+ auto accountFilterReset = Models::addFilterMenuItems(menu, AccountManager::instance()->accountNames(), _sortModel, static_cast<int>(ProtocolItemModel::ProtocolItemRole::Account), tr("Account"), Qt::DisplayRole);
+ menu->addSeparator();
+ auto statusFilterReset = addStatusFilter(menu);
+ menu->addSeparator();
+ addResetFiltersAction(menu, { accountFilterReset, statusFilterReset });
+
+ QTimer::singleShot(0, menu, [menu] {
+ menu->popup(QCursor::pos());
+ });
+
+ return menu;
+}
+
+void IssuesWidget::addResetFiltersAction(QMenu *menu, const QList<std::function<void()>> &resetFunctions)
+{
+ menu->addAction(QCoreApplication::translate("OCC::Models", "Reset Filters"), [resetFunctions]() {
+ for (const auto &reset : resetFunctions) {
+ reset();
+ }
+ });
+}
+
void IssuesWidget::slotProgressInfo(const QString &folder, const ProgressInfo &progress)
{
if (progress.status() == ProgressInfo::Reconcile) {
@@ -195,9 +285,69 @@ void IssuesWidget::slotItemContextMenu()
{
auto rows = _ui->_tableView->selectionModel()->selectedRows();
for (int i = 0; i < rows.size(); ++i) {
+ rows[i] = _statusSortModel->mapToSource(rows[i]);
rows[i] = _sortModel->mapToSource(rows[i]);
}
ProtocolWidget::showContextMenu(this, _model, rows);
}
+std::function<void(void)> IssuesWidget::addStatusFilter(QMenu *menu)
+{
+ menu->addAction(QCoreApplication::translate("OCC::Models", "Status Filter:"))->setEnabled(false);
+
+ // Use a QActionGroup to contain all status filter items, so we can find them back easily to reset.
+ auto statusFilterGroup = new QActionGroup(menu);
+ statusFilterGroup->setExclusive(false);
+
+ const auto initialFilter = _statusSortModel->filter();
+
+ { // Add all errors under 1 action:
+ const std::array<SyncFileItem::Status, 5> ErrorStatusItems = {
+ SyncFileItem::Status::FatalError,
+ SyncFileItem::Status::NormalError,
+ SyncFileItem::Status::SoftError,
+ SyncFileItem::Status::DetailError
+ };
+
+ auto action = menu->addAction(SyncFileItem::statusEnumDisplayName(SyncFileItem::NormalError), [this, ErrorStatusItems](bool checked) {
+ auto currentFilter = _statusSortModel->filter();
+ for (const auto &item : ErrorStatusItems) {
+ currentFilter[item] = checked;
+ }
+ _statusSortModel->setFilter(currentFilter);
+ });
+ action->setCheckable(true);
+ action->setChecked(initialFilter[ErrorStatusItems[0]]);
+ statusFilterGroup->addAction(action);
+ }
+
+ // Add the other non-error items:
+ const std::array<SyncFileItem::Status, 5> OtherStatusItems = {
+ SyncFileItem::Status::Conflict,
+ SyncFileItem::Status::FileIgnored,
+ SyncFileItem::Status::Restoration,
+ SyncFileItem::Status::BlacklistedError,
+ SyncFileItem::Status::Excluded
+ };
+ for (const auto &item : OtherStatusItems) {
+ auto action = menu->addAction(SyncFileItem::statusEnumDisplayName(item), [this, item](bool checked) {
+ auto currentFilter = _statusSortModel->filter();
+ currentFilter[item] = checked;
+ _statusSortModel->setFilter(currentFilter);
+ });
+ action->setCheckable(true);
+ action->setChecked(initialFilter[item]);
+ statusFilterGroup->addAction(action);
+ }
+
+ menu->addSeparator();
+
+ // Add action to reset all filters at once:
+ return [statusFilterGroup, this]() {
+ for (QAction *action : statusFilterGroup->actions()) {
+ action->setChecked(true);
+ }
+ _statusSortModel->resetFilter();
+ };
+}
}