19class SemiSortableHeader :
public QHeaderView {
22 explicit SemiSortableHeader(Qt::Orientation ori, QWidget *parent =
nullptr)
23 : QHeaderView(ori, parent) {
24 setSectionsClickable(
true);
25 setSortIndicatorShown(
true);
26 setSortIndicatorClearable(
false);
27 setMouseTracking(
true);
30 void attachTo(QTableWidget *table) {
32 table_->setHorizontalHeader(
this);
35 table_->setSortingEnabled(
true);
38 sortCol_ = firstSortableSection();
39 sortOrder_ = Qt::DescendingOrder;
42 QSignalBlocker b(
this);
43 setSortIndicator(sortCol_, sortOrder_);
46 connect(
this, &QHeaderView::sectionClicked,
this,
47 &SemiSortableHeader::onSectionClicked, Qt::UniqueConnection);
51 void setNonSortableColumns(
const QSet<int> &cols) {
53 normalizeSortIfNeeded();
57 void addNonSortableColumn(
int col) {
59 nonSortable_.insert(col);
60 normalizeSortIfNeeded();
65 void removeNonSortableColumn(
int col) {
66 nonSortable_.remove(col);
67 normalizeSortIfNeeded();
71 bool isSortableColumn(
int col)
const {
72 return col >= 0 && !nonSortable_.contains(col);
76 void onSectionClicked(
int column) {
79 if (!isSortableColumn(column))
82 if (column == sortCol_) {
83 sortOrder_ = (sortOrder_ == Qt::AscendingOrder) ? Qt::DescendingOrder
87 sortOrder_ = Qt::AscendingOrder;
92 QSignalBlocker b(
this);
93 setSortIndicator(sortCol_, sortOrder_);
97 table_->setSortingEnabled(
false);
98 table_->sortItems(sortCol_, sortOrder_);
99 table_->setSortingEnabled(
true);
103 void paintSection(QPainter *painter,
const QRect &rect,
104 int logicalIndex)
const override {
106 if (isSortableColumn(logicalIndex)) {
107 QHeaderView::paintSection(painter, rect, logicalIndex);
113 QStyleOptionHeader opt;
114 initStyleOption(&opt);
117 opt.section = logicalIndex;
119 if (
auto *m = model()) {
120 opt.text = m->headerData(logicalIndex, orientation(), Qt::DisplayRole)
123 const QVariant align =
124 m->headerData(logicalIndex, orientation(), Qt::TextAlignmentRole);
126 opt.textAlignment = Qt::Alignment(align.toInt());
128 const QVariant deco =
129 m->headerData(logicalIndex, orientation(), Qt::DecorationRole);
131 opt.icon = deco.value<QIcon>();
135 const int v = visualIndex(logicalIndex);
136 const int n = count();
138 opt.position = QStyleOptionHeader::OnlyOneSection;
140 opt.position = QStyleOptionHeader::Beginning;
142 opt.position = QStyleOptionHeader::End;
144 opt.position = QStyleOptionHeader::Middle;
146 opt.state &= ~QStyle::State_MouseOver;
147 opt.state &= ~QStyle::State_Sunken;
150 opt.sortIndicator = QStyleOptionHeader::None;
152 style()->drawControl(QStyle::CE_Header, &opt, painter,
this);
155 void mousePressEvent(QMouseEvent *e)
override {
156 const int col = logicalIndexAt(e->pos());
157 if (!isSortableColumn(col)) {
161 QHeaderView::mousePressEvent(e);
165 int firstSortableSection()
const {
166 for (
int logical = 0; logical < count(); ++logical) {
167 if (isSortableColumn(logical))
173 void normalizeSortIfNeeded() {
175 if (sortCol_ >= 0 && !isSortableColumn(sortCol_)) {
176 sortCol_ = firstSortableSection();
177 sortOrder_ = Qt::DescendingOrder;
179 QSignalBlocker b(
this);
180 setSortIndicator(sortCol_, sortOrder_);
182 QSignalBlocker b(
this);
183 setSortIndicator(-1, Qt::AscendingOrder);
189 QPointer<QTableWidget> table_;
190 QSet<int> nonSortable_;
193 Qt::SortOrder sortOrder_ = Qt::AscendingOrder;