diff options
author | Hannah von Reth <hannah.vonreth@owncloud.com> | 2021-09-30 16:48:34 +0300 |
---|---|---|
committer | Hannah von Reth <hannah.vonreth@owncloud.com> | 2021-09-30 16:48:34 +0300 |
commit | f29c794c5b4bca37190911cb2acd60b737498805 (patch) | |
tree | eeef045eec99cc34a600736bb60357c9b8ec0db4 /src/gui/issueswidget.cpp | |
parent | d987a7e7cb19367d708e21f9ef881afecffe35a3 (diff) | |
parent | 47577c51f70792244e52d8813d9da2447bd01fea (diff) |
Merge remote-tracking branch 'origin/2.9'
Diffstat (limited to 'src/gui/issueswidget.cpp')
-rw-r--r-- | src/gui/issueswidget.cpp | 158 |
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(); + }; +} } |