1 /*
2  * Copyright 2011 Aurélien Gâteau <agateau@kde.org>
3  * License: BSD-3-Clause
4  */
5 #include "ColumnResizer.h"
6 
7 #include <QDebug>
8 #include <QEvent>
9 #include <QGridLayout>
10 #include <QTimer>
11 #include <QWidget>
12 
13 class FormLayoutWidgetItem : public QWidgetItem
14 {
15 public:
FormLayoutWidgetItem(QWidget * widget,QFormLayout * formLayout,QFormLayout::ItemRole itemRole)16     FormLayoutWidgetItem(QWidget* widget, QFormLayout* formLayout, QFormLayout::ItemRole itemRole)
17     : QWidgetItem(widget)
18     , m_width(-1)
19     , m_formLayout(formLayout)
20     , m_itemRole(itemRole)
21     {}
22 
sizeHint() const23     QSize sizeHint() const
24     {
25         QSize size = QWidgetItem::sizeHint();
26         if (m_width != -1) {
27             size.setWidth(m_width);
28         }
29         return size;
30     }
31 
minimumSize() const32     QSize minimumSize() const
33     {
34         QSize size = QWidgetItem::minimumSize();
35         if (m_width != -1) {
36             size.setWidth(m_width);
37         }
38         return size;
39     }
40 
maximumSize() const41     QSize maximumSize() const
42     {
43         QSize size = QWidgetItem::maximumSize();
44         if (m_width != -1) {
45             size.setWidth(m_width);
46         }
47         return size;
48     }
49 
setWidth(int width)50     void setWidth(int width)
51     {
52         if (width != m_width) {
53             m_width = width;
54             invalidate();
55         }
56     }
57 
setGeometry(const QRect & _rect)58     void setGeometry(const QRect& _rect)
59     {
60         QRect rect = _rect;
61         int width = widget()->sizeHint().width();
62         if (m_itemRole == QFormLayout::LabelRole && m_formLayout->labelAlignment() & Qt::AlignRight) {
63             rect.setLeft(rect.right() - width);
64         }
65         QWidgetItem::setGeometry(rect);
66     }
67 
formLayout() const68     QFormLayout* formLayout() const
69     {
70         return m_formLayout;
71     }
72 
73 private:
74     int m_width;
75     QFormLayout* m_formLayout;
76     QFormLayout::ItemRole m_itemRole;
77 };
78 
79 typedef QPair<QGridLayout*, int> GridColumnInfo;
80 
81 class ColumnResizerPrivate
82 {
83 public:
ColumnResizerPrivate(ColumnResizer * q_ptr)84     ColumnResizerPrivate(ColumnResizer* q_ptr)
85     : q(q_ptr)
86     , m_updateTimer(new QTimer(q))
87     {
88         m_updateTimer->setSingleShot(true);
89         m_updateTimer->setInterval(0);
90         QObject::connect(m_updateTimer, SIGNAL(timeout()), q, SLOT(updateWidth()));
91     }
92 
scheduleWidthUpdate()93     void scheduleWidthUpdate()
94     {
95         m_updateTimer->start();
96     }
97 
98     ColumnResizer* q;
99     QTimer* m_updateTimer;
100     QList<QWidget*> m_widgets;
101     QList<FormLayoutWidgetItem*> m_wrWidgetItemList;
102     QList<GridColumnInfo> m_gridColumnInfoList;
103 };
104 
ColumnResizer(QObject * parent)105 ColumnResizer::ColumnResizer(QObject* parent)
106 : QObject(parent)
107 , d(new ColumnResizerPrivate(this))
108 {}
109 
~ColumnResizer()110 ColumnResizer::~ColumnResizer()
111 {
112     delete d;
113 }
114 
addWidget(QWidget * widget)115 void ColumnResizer::addWidget(QWidget* widget)
116 {
117     d->m_widgets.append(widget);
118     widget->installEventFilter(this);
119     d->scheduleWidthUpdate();
120 }
121 
updateWidth()122 void ColumnResizer::updateWidth()
123 {
124     int width = 0;
125     Q_FOREACH(QWidget* widget, d->m_widgets) {
126         width = qMax(widget->sizeHint().width(), width);
127     }
128     Q_FOREACH(FormLayoutWidgetItem* item, d->m_wrWidgetItemList) {
129         item->setWidth(width);
130         item->formLayout()->update();
131     }
132     Q_FOREACH(GridColumnInfo info, d->m_gridColumnInfoList) {
133         info.first->setColumnMinimumWidth(info.second, width);
134     }
135 }
136 
eventFilter(QObject *,QEvent * event)137 bool ColumnResizer::eventFilter(QObject*, QEvent* event)
138 {
139     if (event->type() == QEvent::Resize) {
140         d->scheduleWidthUpdate();
141     }
142     return false;
143 }
144 
addWidgetsFromLayout(QLayout * layout,int column)145 void ColumnResizer::addWidgetsFromLayout(QLayout* layout, int column)
146 {
147     Q_ASSERT(column >= 0);
148     QGridLayout* gridLayout = qobject_cast<QGridLayout*>(layout);
149     QFormLayout* formLayout = qobject_cast<QFormLayout*>(layout);
150     if (gridLayout) {
151         addWidgetsFromGridLayout(gridLayout, column);
152     } else if (formLayout) {
153         if (column > QFormLayout::SpanningRole) {
154             qCritical() << "column should not be more than" << QFormLayout::SpanningRole << "for QFormLayout";
155             return;
156         }
157         QFormLayout::ItemRole role = static_cast<QFormLayout::ItemRole>(column);
158         addWidgetsFromFormLayout(formLayout, role);
159     } else {
160         qCritical() << "Don't know how to handle layout" << layout;
161     }
162 }
163 
addWidgetsFromGridLayout(QGridLayout * layout,int column)164 void ColumnResizer::addWidgetsFromGridLayout(QGridLayout* layout, int column)
165 {
166     for (int row = 0; row < layout->rowCount(); ++row) {
167         QLayoutItem* item = layout->itemAtPosition(row, column);
168         if (!item) {
169             continue;
170         }
171         QWidget* widget = item->widget();
172         if (!widget) {
173             continue;
174         }
175         addWidget(widget);
176     }
177     d->m_gridColumnInfoList << GridColumnInfo(layout, column);
178 }
179 
addWidgetsFromFormLayout(QFormLayout * layout,QFormLayout::ItemRole role)180 void ColumnResizer::addWidgetsFromFormLayout(QFormLayout* layout, QFormLayout::ItemRole role)
181 {
182     for (int row = 0; row < layout->rowCount(); ++row) {
183         QLayoutItem* item = layout->itemAt(row, role);
184         if (!item) {
185             continue;
186         }
187         QWidget* widget = item->widget();
188         if (!widget) {
189             continue;
190         }
191         layout->removeItem(item);
192         delete item;
193         FormLayoutWidgetItem* newItem = new FormLayoutWidgetItem(widget, layout, role);
194         layout->setItem(row, role, newItem);
195         addWidget(widget);
196         d->m_wrWidgetItemList << newItem;
197     }
198 }
199 
200 // vi: ts=4 sw=4 et
201