source: trunk/tools/designer/src/lib/shared/qdesigner_widgetitem.cpp@ 5

Last change on this file since 5 was 2, checked in by Dmitry A. Kuminov, 16 years ago

Initially imported qt-all-opensource-src-4.5.1 from Trolltech.

File size: 12.0 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4** Contact: Qt Software Information ([email protected])
5**
6** This file is part of the Qt Designer of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial Usage
10** Licensees holding valid Qt Commercial licenses may use this file in
11** accordance with the Qt Commercial License Agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and Nokia.
14**
15** GNU Lesser General Public License Usage
16** Alternatively, this file may be used under the terms of the GNU Lesser
17** General Public License version 2.1 as published by the Free Software
18** Foundation and appearing in the file LICENSE.LGPL included in the
19** packaging of this file. Please review the following information to
20** ensure the GNU Lesser General Public License version 2.1 requirements
21** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
22**
23** In addition, as a special exception, Nokia gives you certain
24** additional rights. These rights are described in the Nokia Qt LGPL
25** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
26** package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you are unsure which license is appropriate for your use, please
37** contact the sales department at [email protected].
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include "qdesigner_widgetitem_p.h"
43#include "qdesigner_widget_p.h"
44#include "widgetfactory_p.h"
45
46#include <QtDesigner/QDesignerFormWindowInterface>
47#include <QtDesigner/QExtensionManager>
48#include <QtDesigner/QDesignerFormEditorInterface>
49#include <QtDesigner/QDesignerContainerExtension>
50#include <QtDesigner/QDesignerWidgetDataBaseInterface>
51
52#include <QtGui/QVBoxLayout>
53#include <QtGui/QHBoxLayout>
54#include <QtGui/QGridLayout>
55#include <QtGui/QFormLayout>
56#include <QtGui/QApplication>
57
58#include <QtCore/QTextStream>
59#include <QtCore/QDebug>
60#include <private/qlayout_p.h>
61
62QT_BEGIN_NAMESPACE
63
64enum { DebugWidgetItem = 0 };
65enum { MinimumLength = 10 };
66
67// Widget item creation function to be registered as factory method with
68// QLayoutPrivate
69static QWidgetItem *createDesignerWidgetItem(const QLayout *layout, QWidget *widget)
70{
71 Qt::Orientations orientations;
72 if (qdesigner_internal::QDesignerWidgetItem::check(layout, widget, &orientations)) {
73 if (DebugWidgetItem)
74 qDebug() << "QDesignerWidgetItem: Creating on " << layout << widget << orientations;
75 return new qdesigner_internal::QDesignerWidgetItem(layout, widget, orientations);
76 }
77 if (DebugWidgetItem)
78 qDebug() << "QDesignerWidgetItem: Noncontainer: " << layout << widget;
79
80 return 0;
81}
82
83static QString sizePolicyToString(const QSizePolicy &p)
84{
85 QString rc; {
86 QTextStream str(&rc);
87 str << "Control=" << p.controlType() << " expdirs=" << p.expandingDirections()
88 << " hasHeightForWidth=" << p.hasHeightForWidth()
89 << " H: Policy=" << p.horizontalPolicy()
90 << " stretch=" << p.horizontalStretch()
91 << " V: Policy=" << p.verticalPolicy()
92 << " stretch=" << p.verticalStretch();
93 }
94 return rc;
95}
96
97// Find the layout the item is contained in, recursing over
98// child layouts
99static const QLayout *findLayoutOfItem(const QLayout *haystack, const QLayoutItem *needle)
100{
101 const int count = haystack->count();
102 for (int i = 0; i < count; i++) {
103 QLayoutItem *item = haystack->itemAt(i);
104 if (item == needle)
105 return haystack;
106 if (QLayout *childLayout = item->layout())
107 if (const QLayout *containing = findLayoutOfItem(childLayout, needle))
108 return containing;
109 }
110 return 0;
111}
112
113
114namespace qdesigner_internal {
115
116// ------------------ QDesignerWidgetItem
117QDesignerWidgetItem::QDesignerWidgetItem(const QLayout *containingLayout, QWidget *w, Qt::Orientations o) :
118 QWidgetItemV2(w),
119 m_orientations(o),
120 m_nonLaidOutMinSize(w->minimumSizeHint()),
121 m_nonLaidOutSizeHint(w->sizeHint()),
122 m_cachedContainingLayout(containingLayout)
123{
124 // Initialize the minimum size to prevent nonlaid-out frames/widgets
125 // from being slammed to zero
126 const QSize minimumSize = w->minimumSize();
127 if (!minimumSize.isEmpty())
128 m_nonLaidOutMinSize = minimumSize;
129 expand(&m_nonLaidOutMinSize);
130 expand(&m_nonLaidOutSizeHint);
131 w->installEventFilter(this);
132 connect(containingLayout, SIGNAL(destroyed()), this, SLOT(layoutChanged()));
133 if (DebugWidgetItem )
134 qDebug() << "QDesignerWidgetItem" << w << sizePolicyToString(w->sizePolicy()) << m_nonLaidOutMinSize << m_nonLaidOutSizeHint;
135}
136
137void QDesignerWidgetItem::expand(QSize *s) const
138{
139 // Expand the size if its too small
140 if (m_orientations & Qt::Horizontal && s->width() <= 0)
141 s->setWidth(MinimumLength);
142 if (m_orientations & Qt::Vertical && s->height() <= 0)
143 s->setHeight(MinimumLength);
144}
145
146QSize QDesignerWidgetItem::minimumSize() const
147{
148 // Just track the size in case we are laid-out or stretched.
149 const QSize baseMinSize = QWidgetItemV2::minimumSize();
150 QWidget * w = constWidget();
151 if (w->layout() || subjectToStretch(containingLayout(), w)) {
152 m_nonLaidOutMinSize = baseMinSize;
153 return baseMinSize;
154 }
155 // Nonlaid out: Maintain last laid-out size
156 const QSize rc = baseMinSize.expandedTo(m_nonLaidOutMinSize);
157 if (DebugWidgetItem > 1)
158 qDebug() << "minimumSize" << constWidget() << baseMinSize << rc;
159 return rc;
160}
161
162QSize QDesignerWidgetItem::sizeHint() const
163{
164 // Just track the size in case we are laid-out or stretched.
165 const QSize baseSizeHint = QWidgetItemV2::sizeHint();
166 QWidget * w = constWidget();
167 if (w->layout() || subjectToStretch(containingLayout(), w)) {
168 m_nonLaidOutSizeHint = baseSizeHint;
169 return baseSizeHint;
170 }
171 // Nonlaid out: Maintain last laid-out size
172 const QSize rc = baseSizeHint.expandedTo(m_nonLaidOutSizeHint);
173 if (DebugWidgetItem > 1)
174 qDebug() << "sizeHint" << constWidget() << baseSizeHint << rc;
175 return rc;
176}
177
178bool QDesignerWidgetItem::subjectToStretch(const QLayout *layout, QWidget *w)
179{
180 if (!layout)
181 return false;
182 // Are we under some stretch factor?
183 if (const QBoxLayout *bl = qobject_cast<const QBoxLayout *>(layout)) {
184 const int index = bl->indexOf(w);
185 Q_ASSERT(index != -1);
186 return bl->stretch(index) != 0;
187 }
188 if (const QGridLayout *cgl = qobject_cast<const QGridLayout *>(layout)) {
189 QGridLayout *gl = const_cast<QGridLayout *>(cgl);
190 const int index = cgl->indexOf(w);
191 Q_ASSERT(index != -1);
192 int row, column, rowSpan, columnSpan;
193 gl->getItemPosition (index, &row, &column, &rowSpan, &columnSpan);
194 const int rend = row + rowSpan;
195 const int cend = column + columnSpan;
196 for (int r = row; r < rend; r++)
197 if (cgl->rowStretch(r) != 0)
198 return true;
199 for (int c = column; c < cend; c++)
200 if (cgl->columnStretch(c) != 0)
201 return true;
202 }
203 return false;
204}
205
206/* Return the orientations mask for a layout, specifying
207 * in which directions squeezing should be prevented. */
208static Qt::Orientations layoutOrientation(const QLayout *layout)
209{
210 if (const QBoxLayout *bl = qobject_cast<const QBoxLayout *>(layout)) {
211 const QBoxLayout::Direction direction = bl->direction();
212 return direction == QBoxLayout::LeftToRight || direction == QBoxLayout::RightToLeft ? Qt::Horizontal : Qt::Vertical;
213 }
214 if (qobject_cast<const QFormLayout*>(layout))
215 return Qt::Vertical;
216 return Qt::Horizontal|Qt::Vertical;
217}
218
219// Check for a non-container extension container
220bool QDesignerWidgetItem::isContainer(const QDesignerFormEditorInterface *core, QWidget *w)
221{
222 if (!WidgetFactory::isFormEditorObject(w))
223 return false;
224 const QDesignerWidgetDataBaseInterface *wdb = core->widgetDataBase();
225 const int widx = wdb->indexOfObject(w);
226 if (widx == -1 || !wdb->item(widx)->isContainer())
227 return false;
228 if (qt_extension<QDesignerContainerExtension*>(core->extensionManager(), w))
229 return false;
230 return true;
231}
232
233bool QDesignerWidgetItem::check(const QLayout *layout, QWidget *w, Qt::Orientations *ptrToOrientations)
234{
235 // Check for form-editor non-containerextension-containers (QFrame, etc)
236 // within laid-out form editor widgets. No check for managed() here as we
237 // want container pages and widgets in the process of being morphed as
238 // well. Avoid nested layouts (as the effective stretch cannot be easily
239 // computed and may mess things up). Won't work for Q3 Group boxes.
240 if (ptrToOrientations)
241 *ptrToOrientations = 0;
242
243 const QObject *layoutParent = layout->parent();
244 if (!layoutParent || !layoutParent->isWidgetType() || !WidgetFactory::isFormEditorObject(layoutParent))
245 return false;
246
247 QDesignerFormWindowInterface *fw = QDesignerFormWindowInterface::findFormWindow(w);
248 if (!fw || !isContainer(fw->core(), w))
249 return false;
250
251 // If it is a box, restrict to its orientation
252 if (ptrToOrientations)
253 *ptrToOrientations = layoutOrientation(layout);
254
255 return true;
256}
257
258QSize QDesignerWidgetItem::nonLaidOutMinSize() const
259{
260 return m_nonLaidOutMinSize;
261}
262
263void QDesignerWidgetItem::setNonLaidOutMinSize(const QSize &s)
264{
265 if (DebugWidgetItem > 1)
266 qDebug() << "setNonLaidOutMinSize" << constWidget() << s;
267 m_nonLaidOutMinSize = s;
268}
269
270QSize QDesignerWidgetItem::nonLaidOutSizeHint() const
271{
272 return m_nonLaidOutSizeHint;
273}
274
275void QDesignerWidgetItem::setNonLaidOutSizeHint(const QSize &s)
276{
277 if (DebugWidgetItem > 1)
278 qDebug() << "setNonLaidOutSizeHint" << constWidget() << s;
279 m_nonLaidOutSizeHint = s;
280}
281
282void QDesignerWidgetItem::install()
283{
284 QLayoutPrivate::widgetItemFactoryMethod = createDesignerWidgetItem;
285}
286
287void QDesignerWidgetItem::deinstall()
288{
289 QLayoutPrivate::widgetItemFactoryMethod = 0;
290}
291
292const QLayout *QDesignerWidgetItem::containingLayout() const
293{
294 if (!m_cachedContainingLayout) {
295 if (QWidget *parentWidget = constWidget()->parentWidget())
296 if (QLayout *parentLayout = parentWidget->layout()) {
297 m_cachedContainingLayout = findLayoutOfItem(parentLayout, this);
298 if (m_cachedContainingLayout)
299 connect(m_cachedContainingLayout, SIGNAL(destroyed()), this, SLOT(layoutChanged()));
300 }
301 if (DebugWidgetItem)
302 qDebug() << Q_FUNC_INFO << " found " << m_cachedContainingLayout << " after reparenting " << constWidget();
303 }
304 return m_cachedContainingLayout;
305}
306
307void QDesignerWidgetItem::layoutChanged()
308{
309 if (DebugWidgetItem)
310 qDebug() << Q_FUNC_INFO;
311 m_cachedContainingLayout = 0;
312}
313
314bool QDesignerWidgetItem::eventFilter(QObject * /* watched */, QEvent *event)
315{
316 if (event->type() == QEvent::ParentChange)
317 layoutChanged();
318 return false;
319}
320
321// ------------------ QDesignerWidgetItemInstaller
322
323int QDesignerWidgetItemInstaller::m_instanceCount = 0;
324
325QDesignerWidgetItemInstaller::QDesignerWidgetItemInstaller()
326{
327 if (m_instanceCount++ == 0) {
328 if (DebugWidgetItem)
329 qDebug() << "QDesignerWidgetItemInstaller: installing";
330 QDesignerWidgetItem::install();
331 }
332}
333
334QDesignerWidgetItemInstaller::~QDesignerWidgetItemInstaller()
335{
336 if (--m_instanceCount == 0) {
337 if (DebugWidgetItem)
338 qDebug() << "QDesignerWidgetItemInstaller: deinstalling";
339 QDesignerWidgetItem::deinstall();
340 }
341}
342
343}
344
345QT_END_NAMESPACE
Note: See TracBrowser for help on using the repository browser.