/
friendlyperch
/
QGrid
Обзор
Документация
Войти
/
friendlyperch
/
QGrid
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
dev-ver1
src/FilterHeaderView.cpp
442 строки
12 KB
FriendlyPerch
prepare for deploy
17 янв 2026, 15:26
17 янв 2026, 15:26
d7fce50
Код
Авторство
О чём код?
#include "FilterHeaderView.h" #include "HeaderTableFilterWidget.h" #include "QGrid/GridColumn.h" #include "QGrid/HeaderRenderer.h" #include "QGrid/Filter.h" #include "QGrid/Group.h" #include <QContextMenuEvent> #include <QHeaderView> #include <QLineEdit> #include <QMenu> #include <QMouseEvent> #include <QResizeEvent> #include <QShowEvent> #include <QSortFilterProxyModel> FilterHeaderView::FilterHeaderView(Qt::Orientation orientation, QWidget *parent) : QHeaderView(orientation, parent) { mFilters = new Group(this); mFilters->setOperation(GroupOperation::Or); setSectionsClickable(true); setSortIndicatorShown(true); connect(this, &QHeaderView::sectionResized, this, &FilterHeaderView::onSectionResized); connect(this, &QHeaderView::sectionClicked, this, [this](int logicalIndex) { bool isCheckboxColumn = (logicalIndex == 0 && mCheckboxColumnOffset > 0); if (isCheckboxColumn) { return; } int columnIndex = logicalIndex - mCheckboxColumnOffset; if (columnIndex >= 0 && columnIndex < mColumns.count()) { GridColumn *column = mColumns.at(columnIndex); if (column && column->getSortable()) { QSortFilterProxyModel *proxyModel = qobject_cast<QSortFilterProxyModel *>(model()); if (proxyModel) { Qt::SortOrder newOrder = Qt::AscendingOrder; if (proxyModel->sortColumn() == logicalIndex && proxyModel->sortOrder() == Qt::AscendingOrder) { newOrder = Qt::DescendingOrder; } proxyModel->sort(logicalIndex, newOrder); update(); } } } }); } FilterHeaderView::~FilterHeaderView() { clearFilterWidgets(); } void FilterHeaderView::setColumns(const QVector<GridColumn *> &columns) { mColumns = columns; clearFilterWidgets(); mFilters->clear(); updateGeometry(); if (isVisible()) { setupFilterWidgets(); updateFilterWidgetsGeometry(); } } void FilterHeaderView::setCheckboxColumnOffset(int offset) { if (mCheckboxColumnOffset != offset) { mCheckboxColumnOffset = offset; if (isVisible()) { setupFilterWidgets(); updateFilterWidgetsGeometry(); } } } void FilterHeaderView::setupFilterWidgets() { if (count() == 0 || !mSearchBarShow) { clearFilterWidgets(); updateGeometry(); return; } clearFilterWidgets(); for (int i = 0; i < mColumns.count(); ++i) { GridColumn *column = mColumns.at(i); if (column->getShowInSearchBar()) { int visualColumnIndex = i + mCheckboxColumnOffset; if (visualColumnIndex >= count()) continue; HeaderTableFilterWidget *filterWidget = new HeaderTableFilterWidget(this); filterWidget->setMainWidget(new QLineEdit()); filterWidget->setOperations(column->getOperations()); connect(filterWidget, &HeaderTableFilterWidget::dataChanged, this, &FilterHeaderView::onFilterWidgetDataChanged); filterWidgets[visualColumnIndex] = filterWidget; filterWidget->show(); updateFilterWidgetPosition(visualColumnIndex); } } updateGeometry(); } void FilterHeaderView::clearFilterWidgets() { for (auto it = filterWidgets.begin(); it != filterWidgets.end(); ++it) { if (it.value()) { it.value()->deleteLater(); } } filterWidgets.clear(); } void FilterHeaderView::onFilterWidgetDataChanged() { updateFilters(); } void FilterHeaderView::updateFilterWidgetPosition(int columnIndex) { if (!filterWidgets.contains(columnIndex)) return; QWidget *widget = filterWidgets[columnIndex]; if (!widget) return; QRect rect = getFilterWidgetRect(columnIndex); widget->setGeometry(rect); } QRect FilterHeaderView::getFilterWidgetRect(int columnIndex) const { if (columnIndex >= count()) return QRect(); int x = sectionPosition(columnIndex); int width = sectionSize(columnIndex); QSize baseHeaderSize = QHeaderView::sectionSizeFromContents(columnIndex); int headerTextHeight = baseHeaderSize.height(); int y = headerTextHeight; return QRect(x, y, width, mFilterRowHeight); } QRect FilterHeaderView::getHeaderRect(int logicalIndex) const { if (logicalIndex >= count()) return QRect(); int x = sectionPosition(logicalIndex); int width = sectionSize(logicalIndex); QSize baseHeaderSize = QHeaderView::sectionSizeFromContents(logicalIndex); int headerHeight = baseHeaderSize.height(); return QRect(x, 0, width, headerHeight); } void FilterHeaderView::resizeEvent(QResizeEvent *event) { QHeaderView::resizeEvent(event); updateFilterWidgetsGeometry(); } void FilterHeaderView::showEvent(QShowEvent *event) { QHeaderView::showEvent(event); if (filterWidgets.isEmpty() && count() > 0) { setupFilterWidgets(); } updateFilterWidgetsGeometry(); updateGeometry(); } void FilterHeaderView::updateFilterWidgetsGeometry() { for (auto it = filterWidgets.begin(); it != filterWidgets.end(); ++it) { updateFilterWidgetPosition(it.key()); } } QSize FilterHeaderView::sizeHint() const { auto size = QHeaderView::sizeHint(); if (orientation() == Qt::Horizontal && mSearchBarShow) { size.setHeight(size.height() + mFilterRowHeight); } return size; } void FilterHeaderView::paintSection(QPainter *painter, const QRect &rect, int logicalIndex) const { bool isCheckboxColumn = (logicalIndex == 0 && mCheckboxColumnOffset > 0); int columnIndex = logicalIndex - mCheckboxColumnOffset; GridColumn *column = nullptr; if (columnIndex >= 0 && columnIndex < mColumns.count()) { column = mColumns.at(columnIndex); } const auto sectionSize = QHeaderView::sectionSizeFromContents(logicalIndex); auto headerRect = rect; headerRect.setHeight(sectionSize.height()); if (isCheckboxColumn) { QStyleOptionHeader opt; initStyleOption(&opt); if (isEnabled()) opt.state |= QStyle::State_Enabled; if (window()->isActiveWindow()) opt.state |= QStyle::State_Active; opt.sortIndicator = QStyleOptionHeader::None; opt.section = logicalIndex; opt.text = ""; opt.textAlignment = Qt::AlignCenter; opt.position = QStyleOptionHeader::Beginning; opt.selectedPosition = QStyleOptionHeader::NotAdjacent; opt.rect = headerRect; style()->drawControl(QStyle::CE_Header, &opt, painter, this); return; } HeaderRenderer *headerRenderer = column ? column->getHeaderRenderer() : nullptr; if(!headerRenderer) { QHeaderView::paintSection(painter, headerRect, logicalIndex); return; } QStyleOptionHeader option; option.initFrom(this); option.rect = headerRect; option.section = logicalIndex; option.text = column ? column->getHeader() : QString(); option.textAlignment = column ? column->getTextAlignment() : Qt::AlignCenter; if (column && column->getSortable()) { QSortFilterProxyModel *proxyModel = qobject_cast<QSortFilterProxyModel *>(model()); if (proxyModel) { int sortColumn = proxyModel->sortColumn(); Qt::SortOrder sortOrder = proxyModel->sortOrder(); if (logicalIndex == sortColumn) { option.sortIndicator = (sortOrder == Qt::AscendingOrder) ? QStyleOptionHeader::SortUp : QStyleOptionHeader::SortDown; } else { option.sortIndicator = QStyleOptionHeader::None; } } else { option.sortIndicator = QStyleOptionHeader::None; } } else { option.sortIndicator = QStyleOptionHeader::None; } headerRenderer->paint(painter, option, column ? column->getHeader() : QString()); } void FilterHeaderView::onSectionResized(int logicalIndex, int oldSize, int newSize) { Q_UNUSED(oldSize) if (filterWidgets.contains(logicalIndex)) { updateFilterWidgetPosition(logicalIndex); } for (int i = logicalIndex + 1; i < count(); ++i) { if (filterWidgets.contains(i)) { updateFilterWidgetPosition(i); } } } void FilterHeaderView::setSearchBarShow(bool show) { if (mSearchBarShow != show) { mSearchBarShow = show; if (isVisible()) { setupFilterWidgets(); updateFilterWidgetsGeometry(); } } emit geometriesChanged(); } void FilterHeaderView::updateFilters() { mFilters->clearFilters(); mFilters->setOperation(GroupOperation::Or); for (auto it = filterWidgets.begin(); it != filterWidgets.end(); ++it) { int visualColumnIndex = it.key(); int columnIndex = visualColumnIndex - mCheckboxColumnOffset; if (columnIndex >= 0 && columnIndex < mColumns.count()) { HeaderTableFilterWidget *widget = qobject_cast<HeaderTableFilterWidget *>(it.value()); if (widget) { QVariant data = widget->getData(); if (!data.toString().isEmpty()) { GridColumn *column = mColumns.at(columnIndex); Operation operation = widget->getSelectOperation(); mFilters->addFilter(column->getFieldName(), operation, data); } } } } Group filtersCopy(*mFilters); emit filtersChanged(filtersCopy); } Group FilterHeaderView::getFilters() const { if (mFilters) { return Group(*mFilters); } return Group(); } void FilterHeaderView::contextMenuEvent(QContextMenuEvent *event) { QMenu menu(this); for (auto column : mColumns) { QAction *action = menu.addAction(column->getHeader()); action->setCheckable(true); action->setChecked(column->getVisible()); connect(action, &QAction::triggered, this, [this, column](bool checked) { column->setVisible(checked); emit columnVisibilityChanged(); }); } menu.exec(event->globalPos()); } void FilterHeaderView::mousePressEvent(QMouseEvent *event) { if (event->button() == Qt::LeftButton) { int logicalIndex = logicalIndexAt(event->pos()); if (logicalIndex >= 0) { bool isCheckboxColumn = (logicalIndex == 0 && mCheckboxColumnOffset > 0); if (isCheckboxColumn) { event->accept(); return; } QRect headerRect = getHeaderRect(logicalIndex); bool clickInHeaderArea = headerRect.isValid() && headerRect.contains(event->pos()); if (!clickInHeaderArea) { QRect filterRect = getFilterWidgetRect(logicalIndex); bool clickInFilterArea = filterRect.isValid() && filterRect.contains(event->pos()); if (clickInFilterArea) { event->accept(); return; } } if (clickInHeaderArea) { int columnIndex = logicalIndex - mCheckboxColumnOffset; GridColumn *column = nullptr; if (columnIndex >= 0 && columnIndex < mColumns.count()) { column = mColumns.at(columnIndex); } if (!column || !column->getSortable()) { event->accept(); return; } } } } QHeaderView::mousePressEvent(event); }