/* This file is part of the KDE frameworks SPDX-FileCopyrightText: 2014 Aurélien Gâteau SPDX-License-Identifier: LGPL-2.1-or-later */ #include #include "loggingcategory.h" #include #include #include #include #include class FormLayoutWidgetItem : public QWidgetItem { public: FormLayoutWidgetItem(QWidget *widget, QFormLayout *formLayout, QFormLayout::ItemRole itemRole) : QWidgetItem(widget) , m_formLayout(formLayout) , m_itemRole(itemRole) { } void setWidth(int width) { if (width != m_width) { m_width = width; invalidate(); } } QFormLayout *formLayout() const { return m_formLayout; } QSize sizeHint() const override { QSize size = QWidgetItem::sizeHint(); if (m_width != -1) { size.setWidth(m_width); } return size; } QSize minimumSize() const override { QSize size = QWidgetItem::minimumSize(); if (m_width != -1) { size.setWidth(m_width); } return size; } QSize maximumSize() const override { QSize size = QWidgetItem::maximumSize(); if (m_width != -1) { size.setWidth(m_width); } return size; } void setGeometry(const QRect &_rect) override { QRect rect = _rect; int width = widget()->sizeHint().width(); if (m_itemRole == QFormLayout::LabelRole && m_formLayout->labelAlignment() & Qt::AlignRight) { rect.setLeft(rect.right() - width); } QWidgetItem::setGeometry(rect); } private: QFormLayout *const m_formLayout; int m_width = -1; const QFormLayout::ItemRole m_itemRole; }; struct GridColumnInfo { GridColumnInfo(QGridLayout *layout_, int column_) : layout(layout_) , column(column_) { } QGridLayout *layout; int column; }; Q_DECLARE_TYPEINFO(GridColumnInfo, Q_PRIMITIVE_TYPE); class KColumnResizerPrivate { public: KColumnResizerPrivate(KColumnResizer *q_ptr) : q(q_ptr) , m_updateTimer(new QTimer(q)) { m_updateTimer->setSingleShot(true); m_updateTimer->setInterval(0); QObject::connect(m_updateTimer, &QTimer::timeout, q, [this]() { updateWidth(); }); } void scheduleWidthUpdate() { m_updateTimer->start(); } void updateWidth() { int width = 0; for (QWidget *widget : std::as_const(m_widgets)) { width = qMax(widget->sizeHint().width(), width); } for (FormLayoutWidgetItem *item : std::as_const(m_formWidgetItemList)) { item->setWidth(width); item->formLayout()->update(); } for (const GridColumnInfo &info : std::as_const(m_gridColumnInfoList)) { info.layout->setColumnMinimumWidth(info.column, width); } } void addWidgetsFromGridLayout(QGridLayout *layout, int column) { for (int row = 0; row < layout->rowCount(); ++row) { QLayoutItem *item = layout->itemAtPosition(row, column); if (!item) { continue; } QWidget *widget = item->widget(); if (!widget) { continue; } q->addWidget(widget); } m_gridColumnInfoList << GridColumnInfo(layout, column); } void addWidgetsFromFormLayout(QFormLayout *layout, QFormLayout::ItemRole role) { for (int row = 0; row < layout->rowCount(); ++row) { QLayoutItem *item = layout->itemAt(row, role); if (!item) { continue; } QWidget *widget = item->widget(); if (!widget) { continue; } // Replace the QWidgetItem with our own layout->removeItem(item); delete item; FormLayoutWidgetItem *newItem = new FormLayoutWidgetItem(widget, layout, role); layout->setItem(row, role, newItem); m_formWidgetItemList << newItem; q->addWidget(widget); } } KColumnResizer *q; QTimer *m_updateTimer; QSet m_widgets; QList m_formWidgetItemList; QList m_gridColumnInfoList; }; KColumnResizer::KColumnResizer(QObject *parent) : QObject(parent) , d(new KColumnResizerPrivate(this)) { } KColumnResizer::~KColumnResizer() = default; void KColumnResizer::addWidget(QWidget *widget) { if (d->m_widgets.contains(widget)) { return; } d->m_widgets.insert(widget); widget->installEventFilter(this); d->scheduleWidthUpdate(); } void KColumnResizer::removeWidget(QWidget *widget) { if (!d->m_widgets.remove(widget)) { return; } widget->removeEventFilter(this); d->scheduleWidthUpdate(); } bool KColumnResizer::eventFilter(QObject *, QEvent *event) { if (event->type() == QEvent::Resize) { d->scheduleWidthUpdate(); } return false; } void KColumnResizer::addWidgetsFromLayout(QLayout *layout, int column) { Q_ASSERT(column >= 0); if (column < 0) { qCWarning(KWidgetsAddonsLog) << "column must be >= 0"; return; } QGridLayout *gridLayout = qobject_cast(layout); if (gridLayout) { d->addWidgetsFromGridLayout(gridLayout, column); return; } QFormLayout *formLayout = qobject_cast(layout); if (formLayout) { Q_ASSERT(column <= QFormLayout::SpanningRole); if (column > QFormLayout::SpanningRole) { qCWarning(KWidgetsAddonsLog) << "column should not be more than" << QFormLayout::SpanningRole << "for QFormLayout"; return; } QFormLayout::ItemRole role = static_cast(column); d->addWidgetsFromFormLayout(formLayout, role); } else { qCWarning(KWidgetsAddonsLog) << "Don't know how to handle layout" << layout; Q_ASSERT(0); } } #include "moc_kcolumnresizer.cpp" // vi: ts=4 sw=4 et