forked from qt-creator/qt-creator
Axivion: Implement multi sort for issues table
The issue table can be sorted by multiple columns. The sorting itself happens on the server side, so it is only necessary to reflect the sort state and adapt the search according to the sort columns. Sorting may now happen the following way: * click sort ascending or descending marker to set the column as sort column or remove the marker if it is set * hold Shift while click appends the column to the current sort columns with the respective sort order or removes it from the list if this marker was set already Change-Id: I180f14bc6b4785d13a6fd4669830dc323c0c32a7 Reviewed-by: Jarek Kobus <jaroslaw.kobus@qt.io>
This commit is contained in:
@@ -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<QPair<int, Qt::SortOrder>> 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;
|
||||
}
|
||||
|
||||
|
@@ -38,16 +38,20 @@ static QIcon iconForSorted(std::optional<Qt::SortOrder> order)
|
||||
void IssueHeaderView::setColumnInfoList(const QList<ColumnInfo> &infos)
|
||||
{
|
||||
m_columnInfoList = infos;
|
||||
int oldIndex = m_currentSortIndex;
|
||||
m_currentSortIndex = -1;
|
||||
m_currentSortOrder.reset();
|
||||
if (oldIndex != -1)
|
||||
const QList<int> 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<QPair<int, Qt::SortOrder>> IssueHeaderView::currentSortColumns() const
|
||||
{
|
||||
return m_currentSortOrder ? m_currentSortIndex : -1;
|
||||
QList<QPair<int, Qt::SortOrder>> 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<int> oldSortIndexes = m_currentSortIndexes;
|
||||
std::optional<Qt::SortOrder> 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);
|
||||
|
@@ -24,8 +24,7 @@ public:
|
||||
explicit IssueHeaderView(QWidget *parent = nullptr) : QHeaderView(Qt::Horizontal, parent) {}
|
||||
void setColumnInfoList(const QList<ColumnInfo> &infos);
|
||||
|
||||
std::optional<Qt::SortOrder> currentSortOrder() const { return m_currentSortOrder; }
|
||||
int currentSortColumn() const;
|
||||
QList<QPair<int, Qt::SortOrder>> 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<Qt::SortOrder> m_currentSortOrder = std::nullopt;
|
||||
QList<ColumnInfo> m_columnInfoList;
|
||||
QList<int> m_currentSortIndexes;
|
||||
};
|
||||
|
||||
} // namespace Axivion::Internal
|
||||
|
Reference in New Issue
Block a user