diff --git a/src/plugins/axivion/axivionoutputpane.cpp b/src/plugins/axivion/axivionoutputpane.cpp index b72bc0e68fc..297f27e3138 100644 --- a/src/plugins/axivion/axivionoutputpane.cpp +++ b/src/plugins/axivion/axivionoutputpane.cpp @@ -701,13 +701,18 @@ IssueListSearch IssuesWidget::searchFromUi() const search.state = "added"; else if (m_removedFilter->isChecked()) search.state = "removed"; - if (int column = m_headerView->currentSortColumn() != -1) { - QTC_ASSERT(m_currentTableInfo, return search); - QTC_ASSERT((ulong)column < m_currentTableInfo->columns.size(), return search); - search.sort = m_currentTableInfo->columns.at(m_headerView->currentSortColumn()).key - + (m_headerView->currentSortOrder() == Qt::AscendingOrder ? " asc" : " desc"); - } + QTC_ASSERT(m_currentTableInfo, return search); + QString sort; + const QList> currentSortColumns = m_headerView->currentSortColumns(); + for (const auto &pair : currentSortColumns) { + QTC_ASSERT((ulong)pair.first < m_currentTableInfo->columns.size(), return search); + if (!sort.isEmpty()) + sort.append(','); + sort.append(m_currentTableInfo->columns.at(pair.first).key + + (pair.second == Qt::AscendingOrder ? " asc" : " desc")); + } + search.sort = sort; return search; } diff --git a/src/plugins/axivion/issueheaderview.cpp b/src/plugins/axivion/issueheaderview.cpp index 019763d548b..fd5375288d9 100644 --- a/src/plugins/axivion/issueheaderview.cpp +++ b/src/plugins/axivion/issueheaderview.cpp @@ -38,16 +38,20 @@ static QIcon iconForSorted(std::optional order) void IssueHeaderView::setColumnInfoList(const QList &infos) { m_columnInfoList = infos; - int oldIndex = m_currentSortIndex; - m_currentSortIndex = -1; - m_currentSortOrder.reset(); - if (oldIndex != -1) + const QList oldIndexes = m_currentSortIndexes; + m_currentSortIndexes.clear(); + for (int i = 0; i < infos.size(); ++i) + m_columnInfoList[i].sortOrder.reset(); + for (int oldIndex : oldIndexes) headerDataChanged(Qt::Horizontal, oldIndex, oldIndex); } -int IssueHeaderView::currentSortColumn() const +QList> IssueHeaderView::currentSortColumns() const { - return m_currentSortOrder ? m_currentSortIndex : -1; + QList> result; + for (int i : m_currentSortIndexes) + result.append({i, m_columnInfoList.at(i).sortOrder.value()}); + return result; } void IssueHeaderView::mousePressEvent(QMouseEvent *event) @@ -63,6 +67,7 @@ void IssueHeaderView::mousePressEvent(QMouseEvent *event) const int end = sectionViewportPosition(logical) + sectionSize(logical) - margin; const int start = end - ICON_SIZE; m_maybeToggleSort = start < pos && end > pos; + m_withShift = event->modifiers() == Qt::ShiftModifier; } } QHeaderView::mousePressEvent(event); @@ -71,8 +76,10 @@ void IssueHeaderView::mousePressEvent(QMouseEvent *event) void IssueHeaderView::mouseReleaseEvent(QMouseEvent *event) { bool dontSkip = !m_dragging && m_maybeToggleSort; + bool withShift = m_withShift && event->modifiers() == Qt::ShiftModifier; m_dragging = false; m_maybeToggleSort = false; + m_withShift = false; if (dontSkip) { const QPoint position = event->position().toPoint(); @@ -82,9 +89,9 @@ void IssueHeaderView::mouseReleaseEvent(QMouseEvent *event) && logical > -1 && logical < m_columnInfoList.size()) { if (m_columnInfoList.at(logical).sortable) { // ignore non-sortable if (y < height() / 2) // TODO improve - onToggleSort(logical, Qt::AscendingOrder); + onToggleSort(logical, Qt::AscendingOrder, withShift); else - onToggleSort(logical, Qt::DescendingOrder); + onToggleSort(logical, Qt::DescendingOrder, withShift); } } } @@ -99,20 +106,34 @@ void IssueHeaderView::mouseMoveEvent(QMouseEvent *event) QHeaderView::mouseMoveEvent(event); } -void IssueHeaderView::onToggleSort(int index, Qt::SortOrder order) +void IssueHeaderView::onToggleSort(int index, Qt::SortOrder order, bool multi) { - if (m_currentSortIndex == index) { - if (!m_currentSortOrder || m_currentSortOrder.value() != order) - m_currentSortOrder = order; - else - m_currentSortOrder.reset(); + QTC_ASSERT(index > -1 && index < m_columnInfoList.size(), return); + const QList oldSortIndexes = m_currentSortIndexes; + std::optional oldSortOrder = m_columnInfoList.at(index).sortOrder; + int pos = m_currentSortIndexes.indexOf(index); + + if (oldSortOrder == order) + m_columnInfoList[index].sortOrder.reset(); + else + m_columnInfoList[index].sortOrder = order; + if (multi) { + if (pos == -1) + m_currentSortIndexes.append(index); + else if (oldSortOrder == order) + m_currentSortIndexes.remove(pos); } else { - m_currentSortOrder = order; + m_currentSortIndexes.clear(); + if (pos == -1 || oldSortOrder != order) + m_currentSortIndexes.append(index); + for (int oldIndex : oldSortIndexes) { + if (oldIndex == index) + continue; + m_columnInfoList[oldIndex].sortOrder.reset(); + } } - int oldIndex = m_currentSortIndex; - m_currentSortIndex = index; - if (oldIndex != -1) + for (int oldIndex : oldSortIndexes) headerDataChanged(Qt::Horizontal, oldIndex, oldIndex); headerDataChanged(Qt::Horizontal, index, index); emit sortTriggered(); @@ -137,11 +158,13 @@ void IssueHeaderView::paintSection(QPainter *painter, const QRect &rect, int log painter->restore(); if (logicalIndex < 0 || logicalIndex >= m_columnInfoList.size()) return; - if (!m_columnInfoList.at(logicalIndex).sortable) + const ColumnInfo info = m_columnInfoList.at(logicalIndex); + if (!info.sortable) return; const int margin = style()->pixelMetric(QStyle::PM_HeaderGripMargin, nullptr, this); - const QIcon icon = iconForSorted(logicalIndex == m_currentSortIndex ? m_currentSortOrder : std::nullopt); + const QIcon icon = iconForSorted(m_currentSortIndexes.contains(logicalIndex) ? info.sortOrder + : std::nullopt); const int offset = qMax((rect.height() - ICON_SIZE), 0) / 2; const int left = rect.left() + rect.width() - ICON_SIZE - margin; const QRect iconRect(left, offset, ICON_SIZE, ICON_SIZE); diff --git a/src/plugins/axivion/issueheaderview.h b/src/plugins/axivion/issueheaderview.h index 748f2faa11d..e8fef8f62fa 100644 --- a/src/plugins/axivion/issueheaderview.h +++ b/src/plugins/axivion/issueheaderview.h @@ -24,8 +24,7 @@ public: explicit IssueHeaderView(QWidget *parent = nullptr) : QHeaderView(Qt::Horizontal, parent) {} void setColumnInfoList(const QList &infos); - std::optional currentSortOrder() const { return m_currentSortOrder; } - int currentSortColumn() const; + QList> currentSortColumns() const; signals: void sortTriggered(); @@ -38,13 +37,13 @@ protected: void mouseMoveEvent(QMouseEvent *event) override; private: - void onToggleSort(int index, Qt::SortOrder order); + void onToggleSort(int index, Qt::SortOrder order, bool multi); bool m_dragging = false; bool m_maybeToggleSort = false; + bool m_withShift = false; int m_lastToggleLogicalPos = -1; - int m_currentSortIndex = -1; - std::optional m_currentSortOrder = std::nullopt; QList m_columnInfoList; + QList m_currentSortIndexes; }; } // namespace Axivion::Internal