|
1 /**************************************************************************** |
|
2 ** |
|
3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). |
|
4 ** All rights reserved. |
|
5 ** Contact: Nokia Corporation (qt-info@nokia.com) |
|
6 ** |
|
7 ** This file is part of the Qt Designer of the Qt Toolkit. |
|
8 ** |
|
9 ** $QT_BEGIN_LICENSE:LGPL$ |
|
10 ** No Commercial Usage |
|
11 ** This file contains pre-release code and may not be distributed. |
|
12 ** You may use this file in accordance with the terms and conditions |
|
13 ** contained in the Technology Preview License Agreement accompanying |
|
14 ** this package. |
|
15 ** |
|
16 ** GNU Lesser General Public License Usage |
|
17 ** Alternatively, this file may be used under the terms of the GNU Lesser |
|
18 ** General Public License version 2.1 as published by the Free Software |
|
19 ** Foundation and appearing in the file LICENSE.LGPL included in the |
|
20 ** packaging of this file. Please review the following information to |
|
21 ** ensure the GNU Lesser General Public License version 2.1 requirements |
|
22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. |
|
23 ** |
|
24 ** In addition, as a special exception, Nokia gives you certain additional |
|
25 ** rights. These rights are described in the Nokia Qt LGPL Exception |
|
26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. |
|
27 ** |
|
28 ** If you have questions regarding the use of this file, please contact |
|
29 ** Nokia at qt-info@nokia.com. |
|
30 ** |
|
31 ** |
|
32 ** |
|
33 ** |
|
34 ** |
|
35 ** |
|
36 ** |
|
37 ** |
|
38 ** $QT_END_LICENSE$ |
|
39 ** |
|
40 ****************************************************************************/ |
|
41 |
|
42 #include "qlayout_widget_p.h" |
|
43 #include "qdesigner_utils_p.h" |
|
44 #include "layout_p.h" |
|
45 #include "layoutinfo_p.h" |
|
46 #include "invisible_widget_p.h" |
|
47 #include "qdesigner_widgetitem_p.h" |
|
48 |
|
49 #include <QtDesigner/QDesignerFormWindowInterface> |
|
50 #include <QtDesigner/QExtensionManager> |
|
51 #include <QtDesigner/QDesignerFormEditorInterface> |
|
52 #include <QtDesigner/QDesignerPropertySheetExtension> |
|
53 #include <QtDesigner/QDesignerWidgetFactoryInterface> |
|
54 |
|
55 #include <QtGui/QPainter> |
|
56 #include <QtGui/QHBoxLayout> |
|
57 #include <QtGui/QVBoxLayout> |
|
58 #include <QtGui/QGridLayout> |
|
59 #include <QtGui/QFormLayout> |
|
60 #include <QtGui/qevent.h> |
|
61 |
|
62 #include <QtCore/qdebug.h> |
|
63 #include <QtCore/QtAlgorithms> |
|
64 #include <QtCore/QMap> |
|
65 #include <QtCore/QStack> |
|
66 #include <QtCore/QPair> |
|
67 #include <QtCore/QSet> |
|
68 |
|
69 enum { ShiftValue = 1 }; |
|
70 enum { debugLayout = 0 }; |
|
71 enum { FormLayoutColumns = 2 }; |
|
72 enum { indicatorSize = 2 }; |
|
73 // Grid/form Helpers: get info (overloads to make templates work) |
|
74 |
|
75 namespace { // Do not use static, will break HP-UX due to templates |
|
76 |
|
77 QT_USE_NAMESPACE |
|
78 |
|
79 // overloads to make templates over QGridLayout/QFormLayout work |
|
80 inline int gridRowCount(const QGridLayout *gridLayout) |
|
81 { |
|
82 return gridLayout->rowCount(); |
|
83 } |
|
84 |
|
85 inline int gridColumnCount(const QGridLayout *gridLayout) |
|
86 { |
|
87 return gridLayout->columnCount(); |
|
88 } |
|
89 |
|
90 // QGridLayout/QFormLayout Helpers: get item position (overloads to make templates work) |
|
91 inline void getGridItemPosition(QGridLayout *gridLayout, int index, |
|
92 int *row, int *column, int *rowspan, int *colspan) |
|
93 { |
|
94 gridLayout->getItemPosition(index, row, column, rowspan, colspan); |
|
95 } |
|
96 |
|
97 QRect gridItemInfo(QGridLayout *grid, int index) |
|
98 { |
|
99 int row, column, rowSpan, columnSpan; |
|
100 // getItemPosition is not const, grmbl.. |
|
101 grid->getItemPosition(index, &row, &column, &rowSpan, &columnSpan); |
|
102 return QRect(column, row, columnSpan, rowSpan); |
|
103 } |
|
104 |
|
105 inline int gridRowCount(const QFormLayout *formLayout) { return formLayout->rowCount(); } |
|
106 inline int gridColumnCount(const QFormLayout *) { return FormLayoutColumns; } |
|
107 |
|
108 inline void getGridItemPosition(QFormLayout *formLayout, int index, int *row, int *column, int *rowspan, int *colspan) |
|
109 { |
|
110 qdesigner_internal::getFormLayoutItemPosition(formLayout, index, row, column, rowspan, colspan); |
|
111 } |
|
112 |
|
113 QRect gridItemInfo(const QFormLayout *form, int index) |
|
114 { |
|
115 int row; |
|
116 int column; |
|
117 int colspan; |
|
118 qdesigner_internal::getFormLayoutItemPosition(form, index, &row, &column, 0, &colspan); |
|
119 return QRect(column, row, colspan, 1); |
|
120 } |
|
121 } // namespace anonymous |
|
122 |
|
123 QT_BEGIN_NAMESPACE |
|
124 |
|
125 static const char *objectNameC = "objectName"; |
|
126 static const char *sizeConstraintC = "sizeConstraint"; |
|
127 |
|
128 /* A padding spacer element that is used to represent an empty form layout cell. It should grow with its cell. |
|
129 * Should not be used on a grid as it causes resizing inconsistencies */ |
|
130 namespace qdesigner_internal { |
|
131 class PaddingSpacerItem : public QSpacerItem { |
|
132 public: |
|
133 PaddingSpacerItem() : QSpacerItem(0, 0, QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding) {} |
|
134 virtual Qt::Orientations expandingDirections () const { return Qt::Vertical | Qt::Horizontal; } |
|
135 }; |
|
136 } |
|
137 |
|
138 static inline QSpacerItem *createGridSpacer() |
|
139 { |
|
140 return new QSpacerItem(0, 0); |
|
141 } |
|
142 |
|
143 static inline QSpacerItem *createFormSpacer() |
|
144 { |
|
145 return new qdesigner_internal::PaddingSpacerItem; |
|
146 } |
|
147 |
|
148 // QGridLayout/QFormLayout Helpers: Debug items of GridLikeLayout |
|
149 template <class GridLikeLayout> |
|
150 static QDebug debugGridLikeLayout(QDebug str, const GridLikeLayout &gl) |
|
151 { |
|
152 const int count = gl.count(); |
|
153 str << "Grid: " << gl.objectName() << gridRowCount(&gl) << " rows x " << gridColumnCount(&gl) |
|
154 << " cols " << count << " items\n"; |
|
155 for (int i = 0; i < count; i++) { |
|
156 QLayoutItem *item = gl.itemAt(i); |
|
157 str << "Item " << i << item << item->widget() << gridItemInfo(const_cast<GridLikeLayout *>(&gl), i) << " empty=" << qdesigner_internal::LayoutInfo::isEmptyItem(item) << "\n"; |
|
158 } |
|
159 return str; |
|
160 } |
|
161 |
|
162 static inline QDebug operator<<(QDebug str, const QGridLayout &gl) { return debugGridLikeLayout(str, gl); } |
|
163 static inline QDebug operator<<(QDebug str, const QFormLayout &fl) { return debugGridLikeLayout(str, fl); } |
|
164 |
|
165 static inline bool isEmptyFormLayoutRow(const QFormLayout *fl, int row) |
|
166 { |
|
167 // Spanning can never be empty |
|
168 if (fl->itemAt(row, QFormLayout::SpanningRole)) |
|
169 return false; |
|
170 return qdesigner_internal::LayoutInfo::isEmptyItem(fl->itemAt(row, QFormLayout::LabelRole)) && qdesigner_internal::LayoutInfo::isEmptyItem(fl->itemAt(row, QFormLayout::FieldRole)); |
|
171 } |
|
172 |
|
173 static inline bool canSimplifyFormLayout(const QFormLayout *formLayout, const QRect &restrictionArea) |
|
174 { |
|
175 if (restrictionArea.x() >= FormLayoutColumns) |
|
176 return false; |
|
177 // Try to find empty rows |
|
178 const int bottomCheckRow = qMin(formLayout->rowCount(), restrictionArea.top() + restrictionArea.height()); |
|
179 for (int r = restrictionArea.y(); r < bottomCheckRow; r++) |
|
180 if (isEmptyFormLayoutRow(formLayout, r)) |
|
181 return true; |
|
182 return false; |
|
183 } |
|
184 |
|
185 // recreate a managed layout (which does not automagically remove |
|
186 // empty rows/columns like grid or form layout) in case it needs to shrink |
|
187 |
|
188 static QLayout *recreateManagedLayout(const QDesignerFormEditorInterface *core, QWidget *w, QLayout *lt) |
|
189 { |
|
190 const qdesigner_internal::LayoutInfo::Type t = qdesigner_internal::LayoutInfo::layoutType(core, lt); |
|
191 qdesigner_internal::LayoutProperties properties; |
|
192 const int mask = properties.fromPropertySheet(core, lt, qdesigner_internal::LayoutProperties::AllProperties); |
|
193 qdesigner_internal::LayoutInfo::deleteLayout(core, w); |
|
194 QLayout *rc = core->widgetFactory()->createLayout(w, 0, t); |
|
195 properties.toPropertySheet(core, rc, mask, true); |
|
196 return rc; |
|
197 } |
|
198 |
|
199 // QGridLayout/QFormLayout Helpers: find an item on a form/grid. Return index |
|
200 template <class GridLikeLayout> |
|
201 int findGridItemAt(GridLikeLayout *gridLayout, int at_row, int at_column) |
|
202 { |
|
203 Q_ASSERT(gridLayout); |
|
204 const int count = gridLayout->count(); |
|
205 for (int index = 0; index < count; index++) { |
|
206 int row, column, rowspan, colspan; |
|
207 getGridItemPosition(gridLayout, index, &row, &column, &rowspan, &colspan); |
|
208 if (at_row >= row && at_row < (row + rowspan) |
|
209 && at_column >= column && at_column < (column + colspan)) { |
|
210 return index; |
|
211 } |
|
212 } |
|
213 return -1; |
|
214 } |
|
215 // QGridLayout/QFormLayout Helpers: remove dummy spacers on form/grid |
|
216 template <class GridLikeLayout> |
|
217 static bool removeEmptyCellsOnGrid(GridLikeLayout *grid, const QRect &area) |
|
218 { |
|
219 // check if there are any items in the way. Should be only spacers |
|
220 // Unique out items that span rows/columns. |
|
221 QVector<int> indexesToBeRemoved; |
|
222 indexesToBeRemoved.reserve(grid->count()); |
|
223 const int rightColumn = area.x() + area.width(); |
|
224 const int bottomRow = area.y() + area.height(); |
|
225 for (int c = area.x(); c < rightColumn; c++) |
|
226 for (int r = area.y(); r < bottomRow; r++) { |
|
227 const int index = findGridItemAt(grid, r ,c); |
|
228 if (index != -1) |
|
229 if (QLayoutItem *item = grid->itemAt(index)) { |
|
230 if (qdesigner_internal::LayoutInfo::isEmptyItem(item)) { |
|
231 if (indexesToBeRemoved.indexOf(index) == -1) |
|
232 indexesToBeRemoved.push_back(index); |
|
233 } else { |
|
234 return false; |
|
235 } |
|
236 } |
|
237 } |
|
238 // remove, starting from last |
|
239 if (!indexesToBeRemoved.empty()) { |
|
240 qStableSort(indexesToBeRemoved.begin(), indexesToBeRemoved.end()); |
|
241 for (int i = indexesToBeRemoved.size() - 1; i >= 0; i--) |
|
242 delete grid->takeAt(indexesToBeRemoved[i]); |
|
243 } |
|
244 return true; |
|
245 } |
|
246 |
|
247 namespace qdesigner_internal { |
|
248 // --------- LayoutProperties |
|
249 |
|
250 LayoutProperties::LayoutProperties() |
|
251 { |
|
252 clear(); |
|
253 } |
|
254 |
|
255 void LayoutProperties::clear() |
|
256 { |
|
257 qFill(m_margins, m_margins + MarginCount, 0); |
|
258 qFill(m_marginsChanged, m_marginsChanged + MarginCount, false); |
|
259 qFill(m_spacings, m_spacings + SpacingsCount, 0); |
|
260 qFill(m_spacingsChanged, m_spacingsChanged + SpacingsCount, false); |
|
261 |
|
262 m_objectName = QVariant(); |
|
263 m_objectNameChanged = false; |
|
264 m_sizeConstraint = QVariant(QLayout::SetDefaultConstraint); |
|
265 m_sizeConstraintChanged = false; |
|
266 |
|
267 m_fieldGrowthPolicyChanged = m_rowWrapPolicyChanged = m_labelAlignmentChanged = m_formAlignmentChanged = false; |
|
268 m_fieldGrowthPolicy = m_rowWrapPolicy = m_formAlignment = QVariant(); |
|
269 |
|
270 m_boxStretchChanged = m_gridRowStretchChanged = m_gridColumnStretchChanged = m_gridRowMinimumHeightChanged = false; |
|
271 m_boxStretch = m_gridRowStretch = m_gridColumnStretch = m_gridRowMinimumHeight = QVariant(); |
|
272 } |
|
273 |
|
274 int LayoutProperties::visibleProperties(const QLayout *layout) |
|
275 { |
|
276 // Grid like layout have 2 spacings. |
|
277 const bool isFormLayout = qobject_cast<const QFormLayout*>(layout); |
|
278 const bool isGridLike = qobject_cast<const QGridLayout*>(layout) || isFormLayout; |
|
279 int rc = ObjectNameProperty|LeftMarginProperty|TopMarginProperty|RightMarginProperty|BottomMarginProperty| |
|
280 SizeConstraintProperty; |
|
281 |
|
282 rc |= isGridLike ? (HorizSpacingProperty|VertSpacingProperty) : SpacingProperty; |
|
283 if (isFormLayout) { |
|
284 rc |= FieldGrowthPolicyProperty|RowWrapPolicyProperty|LabelAlignmentProperty|FormAlignmentProperty; |
|
285 } else { |
|
286 if (isGridLike) { |
|
287 rc |= GridRowStretchProperty|GridColumnStretchProperty|GridRowMinimumHeightProperty|GridColumnMinimumWidthProperty; |
|
288 } else { |
|
289 rc |= BoxStretchProperty; |
|
290 } |
|
291 } |
|
292 return rc; |
|
293 } |
|
294 |
|
295 static const char *marginPropertyNamesC[] = {"leftMargin", "topMargin", "rightMargin", "bottomMargin"}; |
|
296 static const char *spacingPropertyNamesC[] = {"spacing", "horizontalSpacing", "verticalSpacing" }; |
|
297 static const char *fieldGrowthPolicyPropertyC = "fieldGrowthPolicy"; |
|
298 static const char *rowWrapPolicyPropertyC = "rowWrapPolicy"; |
|
299 static const char *labelAlignmentPropertyC = "labelAlignment"; |
|
300 static const char *formAlignmentPropertyC = "formAlignment"; |
|
301 static const char *boxStretchPropertyC = "stretch"; |
|
302 static const char *gridRowStretchPropertyC = "rowStretch"; |
|
303 static const char *gridColumnStretchPropertyC = "columnStretch"; |
|
304 static const char *gridRowMinimumHeightPropertyC = "rowMinimumHeight"; |
|
305 static const char *gridColumnMinimumWidthPropertyC = "columnMinimumWidth"; |
|
306 |
|
307 static bool intValueFromSheet(const QDesignerPropertySheetExtension *sheet, const QString &name, int *value, bool *changed) |
|
308 { |
|
309 const int sheetIndex = sheet->indexOf(name); |
|
310 if (sheetIndex == -1) |
|
311 return false; |
|
312 *value = sheet->property(sheetIndex).toInt(); |
|
313 *changed = sheet->isChanged(sheetIndex); |
|
314 return true; |
|
315 } |
|
316 |
|
317 static void variantPropertyFromSheet(int mask, int flag, const QDesignerPropertySheetExtension *sheet, const QString &name, |
|
318 QVariant *value, bool *changed, int *returnMask) |
|
319 { |
|
320 if (mask & flag) { |
|
321 const int sIndex = sheet->indexOf(name); |
|
322 if (sIndex != -1) { |
|
323 *value = sheet->property(sIndex); |
|
324 *changed = sheet->isChanged(sIndex); |
|
325 *returnMask |= flag; |
|
326 } |
|
327 } |
|
328 } |
|
329 |
|
330 int LayoutProperties::fromPropertySheet(const QDesignerFormEditorInterface *core, QLayout *l, int mask) |
|
331 { |
|
332 int rc = 0; |
|
333 const QDesignerPropertySheetExtension *sheet = qt_extension<QDesignerPropertySheetExtension*>(core->extensionManager(), l); |
|
334 Q_ASSERT(sheet); |
|
335 // name |
|
336 if (mask & ObjectNameProperty) { |
|
337 const int nameIndex = sheet->indexOf(QLatin1String(objectNameC)); |
|
338 Q_ASSERT(nameIndex != -1); |
|
339 m_objectName = sheet->property(nameIndex); |
|
340 m_objectNameChanged = sheet->isChanged(nameIndex); |
|
341 rc |= ObjectNameProperty; |
|
342 } |
|
343 // -- Margins |
|
344 const int marginFlags[MarginCount] = { LeftMarginProperty, TopMarginProperty, RightMarginProperty, BottomMarginProperty}; |
|
345 for (int i = 0; i < MarginCount; i++) |
|
346 if (mask & marginFlags[i]) |
|
347 if (intValueFromSheet(sheet, QLatin1String(marginPropertyNamesC[i]), m_margins + i, m_marginsChanged + i)) |
|
348 rc |= marginFlags[i]; |
|
349 |
|
350 const int spacingFlags[] = { SpacingProperty, HorizSpacingProperty, VertSpacingProperty}; |
|
351 for (int i = 0; i < SpacingsCount; i++) |
|
352 if (mask & spacingFlags[i]) |
|
353 if (intValueFromSheet(sheet, QLatin1String(spacingPropertyNamesC[i]), m_spacings + i, m_spacingsChanged + i)) |
|
354 rc |= spacingFlags[i]; |
|
355 // sizeConstraint, flags |
|
356 variantPropertyFromSheet(mask, SizeConstraintProperty, sheet, QLatin1String(sizeConstraintC), &m_sizeConstraint, &m_sizeConstraintChanged, &rc); |
|
357 variantPropertyFromSheet(mask, FieldGrowthPolicyProperty, sheet, QLatin1String(fieldGrowthPolicyPropertyC), &m_fieldGrowthPolicy, &m_fieldGrowthPolicyChanged, &rc); |
|
358 variantPropertyFromSheet(mask, RowWrapPolicyProperty, sheet, QLatin1String(rowWrapPolicyPropertyC), &m_rowWrapPolicy, &m_rowWrapPolicyChanged, &rc); |
|
359 variantPropertyFromSheet(mask, LabelAlignmentProperty, sheet, QLatin1String(labelAlignmentPropertyC), &m_labelAlignment, &m_labelAlignmentChanged, &rc); |
|
360 variantPropertyFromSheet(mask, FormAlignmentProperty, sheet, QLatin1String(formAlignmentPropertyC), &m_formAlignment, &m_formAlignmentChanged, &rc); |
|
361 variantPropertyFromSheet(mask, BoxStretchProperty, sheet, QLatin1String(boxStretchPropertyC), &m_boxStretch, & m_boxStretchChanged, &rc); |
|
362 variantPropertyFromSheet(mask, GridRowStretchProperty, sheet, QLatin1String(gridRowStretchPropertyC), &m_gridRowStretch, &m_gridRowStretchChanged, &rc); |
|
363 variantPropertyFromSheet(mask, GridColumnStretchProperty, sheet, QLatin1String(gridColumnStretchPropertyC), &m_gridColumnStretch, &m_gridColumnStretchChanged, &rc); |
|
364 variantPropertyFromSheet(mask, GridRowMinimumHeightProperty, sheet, QLatin1String(gridRowMinimumHeightPropertyC), &m_gridRowMinimumHeight, &m_gridRowMinimumHeightChanged, &rc); |
|
365 variantPropertyFromSheet(mask, GridColumnMinimumWidthProperty, sheet, QLatin1String(gridColumnMinimumWidthPropertyC), &m_gridColumnMinimumWidth, &m_gridColumnMinimumWidthChanged, &rc); |
|
366 return rc; |
|
367 } |
|
368 |
|
369 static bool intValueToSheet(QDesignerPropertySheetExtension *sheet, const QString &name, int value, bool changed, bool applyChanged) |
|
370 |
|
371 { |
|
372 |
|
373 const int sheetIndex = sheet->indexOf(name); |
|
374 if (sheetIndex == -1) { |
|
375 qWarning() << " LayoutProperties: Attempt to set property " << name << " that does not exist for the layout."; |
|
376 return false; |
|
377 } |
|
378 sheet->setProperty(sheetIndex, QVariant(value)); |
|
379 if (applyChanged) |
|
380 sheet->setChanged(sheetIndex, changed); |
|
381 return true; |
|
382 } |
|
383 |
|
384 static void variantPropertyToSheet(int mask, int flag, bool applyChanged, QDesignerPropertySheetExtension *sheet, const QString &name, |
|
385 const QVariant &value, bool changed, int *returnMask) |
|
386 { |
|
387 if (mask & flag) { |
|
388 const int sIndex = sheet->indexOf(name); |
|
389 if (sIndex != -1) { |
|
390 sheet->setProperty(sIndex, value); |
|
391 if (applyChanged) |
|
392 sheet->setChanged(sIndex, changed); |
|
393 *returnMask |= flag; |
|
394 } |
|
395 } |
|
396 } |
|
397 |
|
398 int LayoutProperties::toPropertySheet(const QDesignerFormEditorInterface *core, QLayout *l, int mask, bool applyChanged) const |
|
399 { |
|
400 int rc = 0; |
|
401 QDesignerPropertySheetExtension *sheet = qt_extension<QDesignerPropertySheetExtension*>(core->extensionManager(), l); |
|
402 Q_ASSERT(sheet); |
|
403 // name |
|
404 if (mask & ObjectNameProperty) { |
|
405 const int nameIndex = sheet->indexOf(QLatin1String(objectNameC)); |
|
406 Q_ASSERT(nameIndex != -1); |
|
407 sheet->setProperty(nameIndex, m_objectName); |
|
408 if (applyChanged) |
|
409 sheet->setChanged(nameIndex, m_objectNameChanged); |
|
410 rc |= ObjectNameProperty; |
|
411 } |
|
412 // margins |
|
413 const int marginFlags[MarginCount] = { LeftMarginProperty, TopMarginProperty, RightMarginProperty, BottomMarginProperty}; |
|
414 for (int i = 0; i < MarginCount; i++) |
|
415 if (mask & marginFlags[i]) |
|
416 if (intValueToSheet(sheet, QLatin1String(marginPropertyNamesC[i]), m_margins[i], m_marginsChanged[i], applyChanged)) |
|
417 rc |= marginFlags[i]; |
|
418 |
|
419 const int spacingFlags[] = { SpacingProperty, HorizSpacingProperty, VertSpacingProperty}; |
|
420 for (int i = 0; i < SpacingsCount; i++) |
|
421 if (mask & spacingFlags[i]) |
|
422 if (intValueToSheet(sheet, QLatin1String(spacingPropertyNamesC[i]), m_spacings[i], m_spacingsChanged[i], applyChanged)) |
|
423 rc |= spacingFlags[i]; |
|
424 // sizeConstraint |
|
425 variantPropertyToSheet(mask, SizeConstraintProperty, applyChanged, sheet, QLatin1String(sizeConstraintC), m_sizeConstraint, m_sizeConstraintChanged, &rc); |
|
426 variantPropertyToSheet(mask, FieldGrowthPolicyProperty, applyChanged, sheet, QLatin1String(fieldGrowthPolicyPropertyC), m_fieldGrowthPolicy, &m_fieldGrowthPolicyChanged, &rc); |
|
427 variantPropertyToSheet(mask, RowWrapPolicyProperty, applyChanged, sheet, QLatin1String(rowWrapPolicyPropertyC), m_rowWrapPolicy, m_rowWrapPolicyChanged, &rc); |
|
428 variantPropertyToSheet(mask, LabelAlignmentProperty, applyChanged, sheet, QLatin1String(labelAlignmentPropertyC), m_labelAlignment, m_labelAlignmentChanged, &rc); |
|
429 variantPropertyToSheet(mask, FormAlignmentProperty, applyChanged, sheet, QLatin1String(formAlignmentPropertyC), m_formAlignment, m_formAlignmentChanged, &rc); |
|
430 variantPropertyToSheet(mask, BoxStretchProperty, applyChanged, sheet, QLatin1String(boxStretchPropertyC), m_boxStretch, m_boxStretchChanged, &rc); |
|
431 variantPropertyToSheet(mask, GridRowStretchProperty, applyChanged, sheet, QLatin1String(gridRowStretchPropertyC), m_gridRowStretch, m_gridRowStretchChanged, &rc); |
|
432 variantPropertyToSheet(mask, GridColumnStretchProperty, applyChanged, sheet, QLatin1String(gridColumnStretchPropertyC), m_gridColumnStretch, m_gridColumnStretchChanged, &rc); |
|
433 variantPropertyToSheet(mask, GridRowMinimumHeightProperty, applyChanged, sheet, QLatin1String(gridRowMinimumHeightPropertyC), m_gridRowMinimumHeight, m_gridRowMinimumHeightChanged, &rc); |
|
434 variantPropertyToSheet(mask, GridColumnMinimumWidthProperty, applyChanged, sheet, QLatin1String(gridColumnMinimumWidthPropertyC), m_gridColumnMinimumWidth, m_gridColumnMinimumWidthChanged, &rc); |
|
435 return rc; |
|
436 } |
|
437 |
|
438 // ---------------- LayoutHelper |
|
439 LayoutHelper::LayoutHelper() |
|
440 { |
|
441 } |
|
442 |
|
443 LayoutHelper::~LayoutHelper() |
|
444 { |
|
445 } |
|
446 |
|
447 int LayoutHelper::indexOf(const QLayout *lt, const QWidget *widget) |
|
448 { |
|
449 if (!lt) |
|
450 return -1; |
|
451 |
|
452 const int itemCount = lt->count(); |
|
453 for (int i = 0; i < itemCount; i++) |
|
454 if (lt->itemAt(i)->widget() == widget) |
|
455 return i; |
|
456 return -1; |
|
457 } |
|
458 |
|
459 QRect LayoutHelper::itemInfo(QLayout *lt, const QWidget *widget) const |
|
460 { |
|
461 const int index = indexOf(lt, widget); |
|
462 if (index == -1) { |
|
463 qWarning() << "LayoutHelper::itemInfo: " << widget << " not in layout " << lt; |
|
464 return QRect(0, 0, 1, 1); |
|
465 } |
|
466 return itemInfo(lt, index); |
|
467 } |
|
468 |
|
469 // ---------------- BoxLayoutHelper |
|
470 class BoxLayoutHelper : public LayoutHelper { |
|
471 public: |
|
472 BoxLayoutHelper(const Qt::Orientation orientation) : m_orientation(orientation) {} |
|
473 |
|
474 virtual QRect itemInfo(QLayout *lt, int index) const; |
|
475 virtual void insertWidget(QLayout *lt, const QRect &info, QWidget *w); |
|
476 virtual void removeWidget(QLayout *lt, QWidget *widget); |
|
477 virtual void replaceWidget(QLayout *lt, QWidget *before, QWidget *after); |
|
478 |
|
479 virtual void pushState(const QDesignerFormEditorInterface *, const QWidget *); |
|
480 virtual void popState(const QDesignerFormEditorInterface *, QWidget *); |
|
481 |
|
482 virtual bool canSimplify(const QDesignerFormEditorInterface *, const QWidget *, const QRect &) const { return false; } |
|
483 virtual void simplify(const QDesignerFormEditorInterface *, QWidget *, const QRect &) {} |
|
484 |
|
485 // Helper for restoring layout states |
|
486 typedef QVector <QLayoutItem *> LayoutItemVector; |
|
487 static LayoutItemVector disassembleLayout(QLayout *lt); |
|
488 static QLayoutItem *findItemOfWidget(const LayoutItemVector &lv, QWidget *w); |
|
489 |
|
490 private: |
|
491 typedef QVector<QWidget *> BoxLayoutState; |
|
492 |
|
493 static BoxLayoutState state(const QBoxLayout*lt); |
|
494 |
|
495 QStack<BoxLayoutState> m_states; |
|
496 const Qt::Orientation m_orientation; |
|
497 }; |
|
498 |
|
499 QRect BoxLayoutHelper::itemInfo(QLayout * /*lt*/, int index) const |
|
500 { |
|
501 return m_orientation == Qt::Horizontal ? QRect(index, 0, 1, 1) : QRect(0, index, 1, 1); |
|
502 } |
|
503 |
|
504 void BoxLayoutHelper::insertWidget(QLayout *lt, const QRect &info, QWidget *w) |
|
505 { |
|
506 QDesignerWidgetItemInstaller wii; // Make sure we use QDesignerWidgetItem. |
|
507 QBoxLayout *boxLayout = qobject_cast<QBoxLayout *>(lt); |
|
508 Q_ASSERT(boxLayout); |
|
509 boxLayout->insertWidget(m_orientation == Qt::Horizontal ? info.x() : info.y(), w); |
|
510 } |
|
511 |
|
512 void BoxLayoutHelper::removeWidget(QLayout *lt, QWidget *widget) |
|
513 { |
|
514 QBoxLayout *boxLayout = qobject_cast<QBoxLayout *>(lt); |
|
515 Q_ASSERT(boxLayout); |
|
516 boxLayout->removeWidget(widget); |
|
517 } |
|
518 |
|
519 void BoxLayoutHelper::replaceWidget(QLayout *lt, QWidget *before, QWidget *after) |
|
520 { |
|
521 bool ok = false; |
|
522 QDesignerWidgetItemInstaller wii; // Make sure we use QDesignerWidgetItem. |
|
523 if (QBoxLayout *boxLayout = qobject_cast<QBoxLayout *>(lt)) { |
|
524 const int index = boxLayout->indexOf(before); |
|
525 if (index != -1) { |
|
526 const bool visible = before->isVisible(); |
|
527 delete boxLayout->takeAt(index); |
|
528 if (visible) |
|
529 before->hide(); |
|
530 before->setParent(0); |
|
531 boxLayout->insertWidget(index, after); |
|
532 ok = true; |
|
533 } |
|
534 } |
|
535 if (!ok) |
|
536 qWarning() << "BoxLayoutHelper::replaceWidget : Unable to replace " << before << " by " << after << " in " << lt; |
|
537 } |
|
538 |
|
539 BoxLayoutHelper::BoxLayoutState BoxLayoutHelper::state(const QBoxLayout*lt) |
|
540 { |
|
541 BoxLayoutState rc; |
|
542 if (const int count = lt->count()) { |
|
543 rc.reserve(count); |
|
544 for (int i = 0; i < count; i++) |
|
545 if (QWidget *w = lt->itemAt(i)->widget()) |
|
546 rc.push_back(w); |
|
547 } |
|
548 return rc; |
|
549 } |
|
550 |
|
551 void BoxLayoutHelper::pushState(const QDesignerFormEditorInterface *core, const QWidget *w) |
|
552 { |
|
553 const QBoxLayout *boxLayout = qobject_cast<const QBoxLayout *>(LayoutInfo::managedLayout(core, w)); |
|
554 Q_ASSERT(boxLayout); |
|
555 m_states.push(state(boxLayout)); |
|
556 } |
|
557 |
|
558 QLayoutItem *BoxLayoutHelper::findItemOfWidget(const LayoutItemVector &lv, QWidget *w) |
|
559 { |
|
560 const LayoutItemVector::const_iterator cend = lv.constEnd(); |
|
561 for (LayoutItemVector::const_iterator it = lv.constBegin(); it != cend; ++it) |
|
562 if ( (*it)->widget() == w) |
|
563 return *it; |
|
564 |
|
565 return 0; |
|
566 } |
|
567 |
|
568 BoxLayoutHelper::LayoutItemVector BoxLayoutHelper::disassembleLayout(QLayout *lt) |
|
569 { |
|
570 // Take items |
|
571 const int count = lt->count(); |
|
572 if (count == 0) |
|
573 return LayoutItemVector(); |
|
574 LayoutItemVector rc; |
|
575 rc.reserve(count); |
|
576 for (int i = count - 1; i >= 0; i--) |
|
577 rc.push_back(lt->takeAt(i)); |
|
578 return rc; |
|
579 } |
|
580 |
|
581 void BoxLayoutHelper::popState(const QDesignerFormEditorInterface *core, QWidget *w) |
|
582 { |
|
583 QBoxLayout *boxLayout = qobject_cast<QBoxLayout *>(LayoutInfo::managedLayout(core, w)); |
|
584 Q_ASSERT(boxLayout); |
|
585 const BoxLayoutState savedState = m_states.pop(); |
|
586 const BoxLayoutState currentState = state(boxLayout); |
|
587 // Check for equality/empty. Note that this will currently |
|
588 // always trigger as box layouts do not have a state apart from |
|
589 // the order and there is no layout order editor yet. |
|
590 if (savedState == state(boxLayout)) |
|
591 return; |
|
592 |
|
593 const int count = savedState.size(); |
|
594 Q_ASSERT(count == currentState.size()); |
|
595 // Take items and reassemble in saved order |
|
596 const LayoutItemVector items = disassembleLayout(boxLayout); |
|
597 for (int i = 0; i < count; i++) { |
|
598 QLayoutItem *item = findItemOfWidget(items, savedState[i]); |
|
599 Q_ASSERT(item); |
|
600 boxLayout->addItem(item); |
|
601 } |
|
602 } |
|
603 |
|
604 // Grid Layout state. Datatypically store the state of a GridLayout as a map of |
|
605 // widgets to QRect(columns, rows) and size. Used to store the state for undo operations |
|
606 // that do not change the widgets within the layout; also provides some manipulation |
|
607 // functions and ability to apply the state to a layout provided its widgets haven't changed. |
|
608 struct GridLayoutState { |
|
609 GridLayoutState(); |
|
610 |
|
611 void fromLayout(QGridLayout *l); |
|
612 void applyToLayout(const QDesignerFormEditorInterface *core, QWidget *w) const; |
|
613 |
|
614 void insertRow(int row); |
|
615 void insertColumn(int column); |
|
616 |
|
617 bool simplify(const QRect &r, bool testOnly); |
|
618 void removeFreeRow(int row); |
|
619 void removeFreeColumn(int column); |
|
620 |
|
621 |
|
622 // State of a cell in one dimension |
|
623 enum DimensionCellState { |
|
624 Free, |
|
625 Spanned, // Item spans it |
|
626 Occupied // Item bordering on it |
|
627 }; |
|
628 // Horiontal, Vertical pair of state |
|
629 typedef QPair<DimensionCellState, DimensionCellState> CellState; |
|
630 typedef QVector<CellState> CellStates; |
|
631 |
|
632 // Figure out states of a cell and return as a flat vector of |
|
633 // [column1, column2,...] (address as row * columnCount + col) |
|
634 static CellStates cellStates(const QList<QRect> &rects, int numRows, int numColumns); |
|
635 |
|
636 typedef QMap<QWidget *, QRect> WidgetItemMap; |
|
637 WidgetItemMap widgetItemMap; |
|
638 int rowCount; |
|
639 int colCount; |
|
640 }; |
|
641 |
|
642 static inline bool needsSpacerItem(const GridLayoutState::CellState &cs) { |
|
643 return cs.first == GridLayoutState::Free && cs.second == GridLayoutState::Free; |
|
644 } |
|
645 |
|
646 static inline QDebug operator<<(QDebug str, const GridLayoutState &gs) |
|
647 { |
|
648 str << "GridLayoutState: " << gs.rowCount << " rows x " << gs.colCount |
|
649 << " cols " << gs.widgetItemMap.size() << " items\n"; |
|
650 |
|
651 const GridLayoutState::WidgetItemMap::const_iterator wcend = gs.widgetItemMap.constEnd(); |
|
652 for (GridLayoutState::WidgetItemMap::const_iterator it = gs.widgetItemMap.constBegin(); it != wcend; ++it) |
|
653 str << "Item " << it.key() << it.value() << '\n'; |
|
654 return str; |
|
655 } |
|
656 |
|
657 GridLayoutState::GridLayoutState() : |
|
658 rowCount(0), |
|
659 colCount(0) |
|
660 { |
|
661 } |
|
662 |
|
663 GridLayoutState::CellStates GridLayoutState::cellStates(const QList<QRect> &rects, int numRows, int numColumns) |
|
664 { |
|
665 CellStates rc = CellStates(numRows * numColumns, CellState(Free, Free)); |
|
666 const QList<QRect>::const_iterator rcend = rects.constEnd(); |
|
667 for (QList<QRect>::const_iterator it = rects.constBegin(); it != rcend; ++it) { |
|
668 const int leftColumn = it->x(); |
|
669 const int topRow = it->y(); |
|
670 const int rightColumn = leftColumn + it->width() - 1; |
|
671 const int bottomRow = topRow + it->height() - 1; |
|
672 for (int r = topRow; r <= bottomRow; r++) |
|
673 for (int c = leftColumn; c <= rightColumn; c++) { |
|
674 const int flatIndex = r * numColumns + c; |
|
675 // Bordering horizontally? |
|
676 DimensionCellState &horizState = rc[flatIndex].first; |
|
677 if (c == leftColumn || c == rightColumn) { |
|
678 horizState = Occupied; |
|
679 } else { |
|
680 if (horizState < Spanned) |
|
681 horizState = Spanned; |
|
682 } |
|
683 // Bordering vertically? |
|
684 DimensionCellState &vertState = rc[flatIndex].second; |
|
685 if (r == topRow || r == bottomRow) { |
|
686 vertState = Occupied; |
|
687 } else { |
|
688 if (vertState < Spanned) |
|
689 vertState = Spanned; |
|
690 } |
|
691 } |
|
692 } |
|
693 if (debugLayout) { |
|
694 qDebug() << "GridLayoutState::cellStates: " << numRows << " x " << numColumns; |
|
695 for (int r = 0; r < numRows; r++) |
|
696 for (int c = 0; c < numColumns; c++) |
|
697 qDebug() << " Row: " << r << " column: " << c << rc[r * numColumns + c]; |
|
698 } |
|
699 return rc; |
|
700 } |
|
701 |
|
702 void GridLayoutState::fromLayout(QGridLayout *l) |
|
703 { |
|
704 rowCount = l->rowCount(); |
|
705 colCount = l->columnCount(); |
|
706 const int count = l->count(); |
|
707 for (int i = 0; i < count; i++) { |
|
708 QLayoutItem *item = l->itemAt(i); |
|
709 if (!LayoutInfo::isEmptyItem(item)) |
|
710 widgetItemMap.insert(item->widget(), gridItemInfo(l, i)); |
|
711 } |
|
712 } |
|
713 |
|
714 void GridLayoutState::applyToLayout(const QDesignerFormEditorInterface *core, QWidget *w) const |
|
715 { |
|
716 typedef QMap<QLayoutItem *, QRect> LayoutItemRectMap; |
|
717 QGridLayout *grid = qobject_cast<QGridLayout *>(LayoutInfo::managedLayout(core, w)); |
|
718 Q_ASSERT(grid); |
|
719 if (debugLayout) |
|
720 qDebug() << ">GridLayoutState::applyToLayout" << *this << *grid; |
|
721 const bool shrink = grid->rowCount() > rowCount || grid->columnCount() > colCount; |
|
722 // Build a map of existing items to rectangles via widget map, delete spacers |
|
723 LayoutItemRectMap itemMap; |
|
724 while (grid->count()) { |
|
725 QLayoutItem *item = grid->takeAt(0); |
|
726 if (!LayoutInfo::isEmptyItem(item)) { |
|
727 QWidget *itemWidget = item->widget(); |
|
728 const WidgetItemMap::const_iterator it = widgetItemMap.constFind(itemWidget); |
|
729 if (it == widgetItemMap.constEnd()) |
|
730 qFatal("GridLayoutState::applyToLayout: Attempt to apply to a layout that has a widget '%s'/'%s' added after saving the state.", |
|
731 itemWidget->metaObject()->className(), itemWidget->objectName().toUtf8().constData()); |
|
732 itemMap.insert(item, it.value()); |
|
733 } else { |
|
734 delete item; |
|
735 } |
|
736 } |
|
737 Q_ASSERT(itemMap.size() == widgetItemMap.size()); |
|
738 // recreate if shrink |
|
739 if (shrink) |
|
740 grid = static_cast<QGridLayout*>(recreateManagedLayout(core, w, grid)); |
|
741 |
|
742 // Add widgets items |
|
743 const LayoutItemRectMap::const_iterator icend = itemMap.constEnd(); |
|
744 for (LayoutItemRectMap::const_iterator it = itemMap.constBegin(); it != icend; ++it) { |
|
745 const QRect info = it.value(); |
|
746 grid->addItem(it.key(), info.y(), info.x(), info.height(), info.width()); |
|
747 } |
|
748 // create spacers |
|
749 const CellStates cs = cellStates(itemMap.values(), rowCount, colCount); |
|
750 for (int r = 0; r < rowCount; r++) |
|
751 for (int c = 0; c < colCount; c++) |
|
752 if (needsSpacerItem(cs[r * colCount + c])) |
|
753 grid->addItem(createGridSpacer(), r, c); |
|
754 grid->activate(); |
|
755 if (debugLayout) |
|
756 qDebug() << "<GridLayoutState::applyToLayout" << *grid; |
|
757 } |
|
758 |
|
759 void GridLayoutState::insertRow(int row) |
|
760 { |
|
761 rowCount++; |
|
762 const WidgetItemMap::iterator iend = widgetItemMap.end(); |
|
763 for (WidgetItemMap::iterator it = widgetItemMap.begin(); it != iend; ++it) { |
|
764 const int topRow = it.value().y(); |
|
765 if (topRow >= row) { |
|
766 it.value().translate(0, 1); |
|
767 } else { //Over it: Does it span it -> widen? |
|
768 const int rowSpan = it.value().height(); |
|
769 if (rowSpan > 1 && topRow + rowSpan > row) |
|
770 it.value().setHeight(rowSpan + 1); |
|
771 } |
|
772 } |
|
773 } |
|
774 |
|
775 void GridLayoutState::insertColumn(int column) |
|
776 { |
|
777 colCount++; |
|
778 const WidgetItemMap::iterator iend = widgetItemMap.end(); |
|
779 for (WidgetItemMap::iterator it = widgetItemMap.begin(); it != iend; ++it) { |
|
780 const int leftColumn = it.value().x(); |
|
781 if (leftColumn >= column) { |
|
782 it.value().translate(1, 0); |
|
783 } else { // Left of it: Does it span it -> widen? |
|
784 const int colSpan = it.value().width(); |
|
785 if (colSpan > 1 && leftColumn + colSpan > column) |
|
786 it.value().setWidth(colSpan + 1); |
|
787 } |
|
788 } |
|
789 } |
|
790 |
|
791 // Simplify: Remove empty columns/rows and such ones that are only spanned (shrink |
|
792 // spanning items). |
|
793 // 'AB.C.' 'ABC' |
|
794 // 'DDDD.' ==> 'DDD' |
|
795 // 'EF.G.' 'EFG' |
|
796 bool GridLayoutState::simplify(const QRect &r, bool testOnly) |
|
797 { |
|
798 // figure out free rows/columns. |
|
799 QVector<bool> occupiedRows(rowCount, false); |
|
800 QVector<bool> occupiedColumns(colCount, false); |
|
801 // Mark everything outside restriction rectangle as occupied |
|
802 const int restrictionLeftColumn = r.x(); |
|
803 const int restrictionRightColumn = restrictionLeftColumn + r.width(); |
|
804 const int restrictionTopRow = r.y(); |
|
805 const int restrictionBottomRow = restrictionTopRow + r.height(); |
|
806 if (restrictionLeftColumn > 0 || restrictionRightColumn < colCount || |
|
807 restrictionTopRow > 0 || restrictionBottomRow < rowCount) { |
|
808 for (int r = 0; r < rowCount; r++) |
|
809 if (r < restrictionTopRow || r >= restrictionBottomRow) |
|
810 occupiedRows[r] = true; |
|
811 for (int c = 0; c < colCount; c++) |
|
812 if (c < restrictionLeftColumn || c >= restrictionRightColumn) |
|
813 occupiedColumns[c] = true; |
|
814 } |
|
815 // figure out free fields and tick off occupied rows and columns |
|
816 const CellStates cs = cellStates(widgetItemMap.values(), rowCount, colCount); |
|
817 for (int r = 0; r < rowCount; r++) |
|
818 for (int c = 0; c < colCount; c++) { |
|
819 const CellState &state = cs[r * colCount + c]; |
|
820 if (state.first == Occupied) |
|
821 occupiedColumns[c] = true; |
|
822 if (state.second == Occupied) |
|
823 occupiedRows[r] = true; |
|
824 } |
|
825 // Any free rows/columns? |
|
826 if (occupiedRows.indexOf(false) == -1 && occupiedColumns.indexOf(false) == -1) |
|
827 return false; |
|
828 if (testOnly) |
|
829 return true; |
|
830 // remove rows |
|
831 for (int r = rowCount - 1; r >= 0; r--) |
|
832 if (!occupiedRows[r]) |
|
833 removeFreeRow(r); |
|
834 // remove columns |
|
835 for (int c = colCount - 1; c >= 0; c--) |
|
836 if (!occupiedColumns[c]) |
|
837 removeFreeColumn(c); |
|
838 return true; |
|
839 } |
|
840 |
|
841 void GridLayoutState::removeFreeRow(int removeRow) |
|
842 { |
|
843 const WidgetItemMap::iterator iend = widgetItemMap.end(); |
|
844 for (WidgetItemMap::iterator it = widgetItemMap.begin(); it != iend; ++it) { |
|
845 const int r = it.value().y(); |
|
846 Q_ASSERT(r != removeRow); // Free rows only |
|
847 if (r < removeRow) { // Does the item span it? - shrink it |
|
848 const int rowSpan = it.value().height(); |
|
849 if (rowSpan > 1) { |
|
850 const int bottomRow = r + rowSpan; |
|
851 if (bottomRow > removeRow) |
|
852 it.value().setHeight(rowSpan - 1); |
|
853 } |
|
854 } else |
|
855 if (r > removeRow) // Item below it? - move. |
|
856 it.value().translate(0, -1); |
|
857 } |
|
858 rowCount--; |
|
859 } |
|
860 |
|
861 void GridLayoutState::removeFreeColumn(int removeColumn) |
|
862 { |
|
863 const WidgetItemMap::iterator iend = widgetItemMap.end(); |
|
864 for (WidgetItemMap::iterator it = widgetItemMap.begin(); it != iend; ++it) { |
|
865 const int c = it.value().x(); |
|
866 Q_ASSERT(c != removeColumn); // Free columns only |
|
867 if (c < removeColumn) { // Does the item span it? - shrink it |
|
868 const int colSpan = it.value().width(); |
|
869 if (colSpan > 1) { |
|
870 const int rightColumn = c + colSpan; |
|
871 if (rightColumn > removeColumn) |
|
872 it.value().setWidth(colSpan - 1); |
|
873 } |
|
874 } else |
|
875 if (c > removeColumn) // Item to the right of it? - move. |
|
876 it.value().translate(-1, 0); |
|
877 } |
|
878 colCount--; |
|
879 } |
|
880 |
|
881 // ---------------- GridLayoutHelper |
|
882 class GridLayoutHelper : public LayoutHelper { |
|
883 public: |
|
884 GridLayoutHelper() {} |
|
885 |
|
886 virtual QRect itemInfo(QLayout *lt, int index) const; |
|
887 virtual void insertWidget(QLayout *lt, const QRect &info, QWidget *w); |
|
888 virtual void removeWidget(QLayout *lt, QWidget *widget); |
|
889 virtual void replaceWidget(QLayout *lt, QWidget *before, QWidget *after); |
|
890 |
|
891 virtual void pushState(const QDesignerFormEditorInterface *core, const QWidget *widgetWithManagedLayout); |
|
892 virtual void popState(const QDesignerFormEditorInterface *core, QWidget *widgetWithManagedLayout); |
|
893 |
|
894 virtual bool canSimplify(const QDesignerFormEditorInterface *core, const QWidget *widgetWithManagedLayout, const QRect &restrictionArea) const; |
|
895 virtual void simplify(const QDesignerFormEditorInterface *core, QWidget *widgetWithManagedLayout, const QRect &restrictionArea); |
|
896 |
|
897 static void insertRow(QGridLayout *grid, int row); |
|
898 |
|
899 private: |
|
900 QStack<GridLayoutState> m_states; |
|
901 }; |
|
902 |
|
903 void GridLayoutHelper::insertRow(QGridLayout *grid, int row) |
|
904 { |
|
905 GridLayoutState state; |
|
906 state.fromLayout(grid); |
|
907 state.insertRow(row); |
|
908 QDesignerFormWindowInterface *fw = QDesignerFormWindowInterface::findFormWindow(grid); |
|
909 state.applyToLayout(fw->core(), grid->parentWidget()); |
|
910 } |
|
911 |
|
912 QRect GridLayoutHelper::itemInfo(QLayout * lt, int index) const |
|
913 { |
|
914 QGridLayout *grid = qobject_cast<QGridLayout *>(lt); |
|
915 Q_ASSERT(grid); |
|
916 return gridItemInfo(grid, index); |
|
917 } |
|
918 |
|
919 void GridLayoutHelper::insertWidget(QLayout *lt, const QRect &info, QWidget *w) |
|
920 { |
|
921 QDesignerWidgetItemInstaller wii; // Make sure we use QDesignerWidgetItem. |
|
922 QGridLayout *gridLayout = qobject_cast<QGridLayout *>(lt); |
|
923 Q_ASSERT(gridLayout); |
|
924 // check if there are any items. Should be only spacers, else something is wrong |
|
925 const int row = info.y(); |
|
926 int column = info.x(); |
|
927 int colSpan = info.width(); |
|
928 int rowSpan = info.height(); |
|
929 // If not empty: A multiselection was dropped on an empty item, insert row |
|
930 // and spread items along new row |
|
931 if (!removeEmptyCellsOnGrid(gridLayout, info)) { |
|
932 int freeColumn = -1; |
|
933 colSpan = rowSpan = 1; |
|
934 // First look to the right for a free column |
|
935 const int columnCount = gridLayout->columnCount(); |
|
936 for (int c = column; c < columnCount; c++) { |
|
937 const int idx = findGridItemAt(gridLayout, row, c); |
|
938 if (idx != -1 && LayoutInfo::isEmptyItem(gridLayout->itemAt(idx))) { |
|
939 freeColumn = c; |
|
940 break; |
|
941 } |
|
942 } |
|
943 if (freeColumn != -1) { |
|
944 removeEmptyCellsOnGrid(gridLayout, QRect(freeColumn, row, 1, 1)); |
|
945 column = freeColumn; |
|
946 } else { |
|
947 GridLayoutHelper::insertRow(gridLayout, row); |
|
948 column = 0; |
|
949 } |
|
950 } |
|
951 gridLayout->addWidget(w, row , column, rowSpan, colSpan); |
|
952 } |
|
953 |
|
954 void GridLayoutHelper::removeWidget(QLayout *lt, QWidget *widget) |
|
955 { |
|
956 QGridLayout *gridLayout = qobject_cast<QGridLayout *>(lt); |
|
957 Q_ASSERT(gridLayout); |
|
958 const int index = gridLayout->indexOf(widget); |
|
959 if (index == -1) { |
|
960 qWarning() << "GridLayoutHelper::removeWidget : Attempt to remove " << widget << " which is not in the layout."; |
|
961 return; |
|
962 } |
|
963 // delete old item and pad with by spacer items |
|
964 int row, column, rowspan, colspan; |
|
965 gridLayout->getItemPosition(index, &row, &column, &rowspan, &colspan); |
|
966 delete gridLayout->takeAt(index); |
|
967 const int rightColumn = column + colspan; |
|
968 const int bottomRow = row + rowspan; |
|
969 for (int c = column; c < rightColumn; c++) |
|
970 for (int r = row; r < bottomRow; r++) |
|
971 gridLayout->addItem(createGridSpacer(), r, c); |
|
972 } |
|
973 |
|
974 void GridLayoutHelper::replaceWidget(QLayout *lt, QWidget *before, QWidget *after) |
|
975 { |
|
976 bool ok = false; |
|
977 QDesignerWidgetItemInstaller wii; // Make sure we use QDesignerWidgetItem. |
|
978 if (QGridLayout *gridLayout = qobject_cast<QGridLayout *>(lt)) { |
|
979 const int index = gridLayout->indexOf(before); |
|
980 if (index != -1) { |
|
981 int row, column, rowSpan, columnSpan; |
|
982 gridLayout->getItemPosition (index, &row, &column, &rowSpan, &columnSpan); |
|
983 const bool visible = before->isVisible(); |
|
984 delete gridLayout->takeAt(index); |
|
985 if (visible) |
|
986 before->hide(); |
|
987 before->setParent(0); |
|
988 gridLayout->addWidget(after, row, column, rowSpan, columnSpan); |
|
989 ok = true; |
|
990 } |
|
991 } |
|
992 if (!ok) |
|
993 qWarning() << "GridLayoutHelper::replaceWidget : Unable to replace " << before << " by " << after << " in " << lt; |
|
994 } |
|
995 |
|
996 void GridLayoutHelper::pushState(const QDesignerFormEditorInterface *core, const QWidget *widgetWithManagedLayout) |
|
997 { |
|
998 QGridLayout *gridLayout = qobject_cast<QGridLayout *>(LayoutInfo::managedLayout(core, widgetWithManagedLayout)); |
|
999 Q_ASSERT(gridLayout); |
|
1000 GridLayoutState gs; |
|
1001 gs.fromLayout(gridLayout); |
|
1002 m_states.push(gs); |
|
1003 } |
|
1004 |
|
1005 void GridLayoutHelper::popState(const QDesignerFormEditorInterface *core, QWidget *widgetWithManagedLayout) |
|
1006 { |
|
1007 Q_ASSERT(!m_states.empty()); |
|
1008 const GridLayoutState state = m_states.pop(); |
|
1009 state.applyToLayout(core, widgetWithManagedLayout); |
|
1010 } |
|
1011 |
|
1012 bool GridLayoutHelper::canSimplify(const QDesignerFormEditorInterface *core, const QWidget *widgetWithManagedLayout, const QRect &restrictionArea) const |
|
1013 { |
|
1014 QGridLayout *gridLayout = qobject_cast<QGridLayout *>(LayoutInfo::managedLayout(core, widgetWithManagedLayout)); |
|
1015 Q_ASSERT(gridLayout); |
|
1016 GridLayoutState gs; |
|
1017 gs.fromLayout(gridLayout); |
|
1018 return gs.simplify(restrictionArea, true); |
|
1019 } |
|
1020 |
|
1021 void GridLayoutHelper::simplify(const QDesignerFormEditorInterface *core, QWidget *widgetWithManagedLayout, const QRect &restrictionArea) |
|
1022 { |
|
1023 QGridLayout *gridLayout = qobject_cast<QGridLayout *>(LayoutInfo::managedLayout(core, widgetWithManagedLayout)); |
|
1024 Q_ASSERT(gridLayout); |
|
1025 if (debugLayout) |
|
1026 qDebug() << ">GridLayoutHelper::simplify" << *gridLayout; |
|
1027 GridLayoutState gs; |
|
1028 gs.fromLayout(gridLayout); |
|
1029 if (gs.simplify(restrictionArea, false)) |
|
1030 gs.applyToLayout(core, widgetWithManagedLayout); |
|
1031 if (debugLayout) |
|
1032 qDebug() << "<GridLayoutHelper::simplify" << *gridLayout; |
|
1033 } |
|
1034 |
|
1035 // ---------------- FormLayoutHelper |
|
1036 class FormLayoutHelper : public LayoutHelper { |
|
1037 public: |
|
1038 typedef QPair<QWidget *, QWidget *> WidgetPair; |
|
1039 typedef QVector<WidgetPair> FormLayoutState; |
|
1040 |
|
1041 FormLayoutHelper() {} |
|
1042 |
|
1043 virtual QRect itemInfo(QLayout *lt, int index) const; |
|
1044 virtual void insertWidget(QLayout *lt, const QRect &info, QWidget *w); |
|
1045 virtual void removeWidget(QLayout *lt, QWidget *widget); |
|
1046 virtual void replaceWidget(QLayout *lt, QWidget *before, QWidget *after); |
|
1047 |
|
1048 virtual void pushState(const QDesignerFormEditorInterface *core, const QWidget *widgetWithManagedLayout); |
|
1049 virtual void popState(const QDesignerFormEditorInterface *core, QWidget *widgetWithManagedLayout); |
|
1050 |
|
1051 virtual bool canSimplify(const QDesignerFormEditorInterface *core, const QWidget *, const QRect &) const; |
|
1052 virtual void simplify(const QDesignerFormEditorInterface *, QWidget *, const QRect &); |
|
1053 |
|
1054 private: |
|
1055 static FormLayoutState state(const QFormLayout *lt); |
|
1056 |
|
1057 QStack<FormLayoutState> m_states; |
|
1058 }; |
|
1059 |
|
1060 QRect FormLayoutHelper::itemInfo(QLayout * lt, int index) const |
|
1061 { |
|
1062 QFormLayout *form = qobject_cast<QFormLayout *>(lt); |
|
1063 Q_ASSERT(form); |
|
1064 int row, column, colspan; |
|
1065 getFormLayoutItemPosition(form, index, &row, &column, 0, &colspan); |
|
1066 return QRect(column, row, colspan, 1); |
|
1067 } |
|
1068 |
|
1069 void FormLayoutHelper::insertWidget(QLayout *lt, const QRect &info, QWidget *w) |
|
1070 { |
|
1071 if (debugLayout) |
|
1072 qDebug() << "FormLayoutHelper::insertWidget:" << w << info; |
|
1073 QDesignerWidgetItemInstaller wii; // Make sure we use QDesignerWidgetItem. |
|
1074 QFormLayout *formLayout = qobject_cast<QFormLayout *>(lt); |
|
1075 Q_ASSERT(formLayout); |
|
1076 // check if there are any nonspacer items? (Drop on 3rd column or drop of a multiselection |
|
1077 // on an empty item. As the Form layout does not have insert semantics; we need to manually insert a row |
|
1078 const bool insert = !removeEmptyCellsOnGrid(formLayout, info); |
|
1079 formLayoutAddWidget(formLayout, w, info, insert); |
|
1080 QLayoutSupport::createEmptyCells(formLayout); |
|
1081 } |
|
1082 |
|
1083 void FormLayoutHelper::removeWidget(QLayout *lt, QWidget *widget) |
|
1084 { |
|
1085 QFormLayout *formLayout = qobject_cast<QFormLayout *>(lt); |
|
1086 Q_ASSERT(formLayout); |
|
1087 const int index = formLayout->indexOf(widget); |
|
1088 if (index == -1) { |
|
1089 qWarning() << "FormLayoutHelper::removeWidget : Attempt to remove " << widget << " which is not in the layout."; |
|
1090 return; |
|
1091 } |
|
1092 // delete old item and pad with by spacer items |
|
1093 int row, column, colspan; |
|
1094 getFormLayoutItemPosition(formLayout, index, &row, &column, 0, &colspan); |
|
1095 if (debugLayout) |
|
1096 qDebug() << "FormLayoutHelper::removeWidget: #" << index << widget << " at " << row << column << colspan; |
|
1097 delete formLayout->takeAt(index); |
|
1098 if (colspan > 1 || column == 0) |
|
1099 formLayout->setItem(row, QFormLayout::LabelRole, createFormSpacer()); |
|
1100 if (colspan > 1 || column == 1) |
|
1101 formLayout->setItem(row, QFormLayout::FieldRole, createFormSpacer()); |
|
1102 } |
|
1103 |
|
1104 void FormLayoutHelper::replaceWidget(QLayout *lt, QWidget *before, QWidget *after) |
|
1105 { |
|
1106 bool ok = false; |
|
1107 QDesignerWidgetItemInstaller wii; // Make sure we use QDesignerWidgetItem. |
|
1108 if (QFormLayout *formLayout = qobject_cast<QFormLayout *>(lt)) { |
|
1109 const int index = formLayout->indexOf(before); |
|
1110 if (index != -1) { |
|
1111 int row; |
|
1112 QFormLayout::ItemRole role; |
|
1113 formLayout->getItemPosition (index, &row, &role); |
|
1114 const bool visible = before->isVisible(); |
|
1115 delete formLayout->takeAt(index); |
|
1116 if (visible) |
|
1117 before->hide(); |
|
1118 before->setParent(0); |
|
1119 formLayout->setWidget(row, role, after); |
|
1120 ok = true; |
|
1121 } |
|
1122 } |
|
1123 if (!ok) |
|
1124 qWarning() << "FormLayoutHelper::replaceWidget : Unable to replace " << before << " by " << after << " in " << lt; |
|
1125 } |
|
1126 |
|
1127 FormLayoutHelper::FormLayoutState FormLayoutHelper::state(const QFormLayout *lt) |
|
1128 { |
|
1129 const int rowCount = lt->rowCount(); |
|
1130 if (rowCount == 0) |
|
1131 return FormLayoutState(); |
|
1132 FormLayoutState rc(rowCount, WidgetPair(0, 0)); |
|
1133 const int count = lt->count(); |
|
1134 int row, column, colspan; |
|
1135 for (int i = 0; i < count; i++) { |
|
1136 QLayoutItem *item = lt->itemAt(i); |
|
1137 if (!LayoutInfo::isEmptyItem(item)) { |
|
1138 QWidget *w = item->widget(); |
|
1139 Q_ASSERT(w); |
|
1140 getFormLayoutItemPosition(lt, i, &row, &column, 0, &colspan); |
|
1141 if (colspan > 1 || column == 0) |
|
1142 rc[row].first = w; |
|
1143 if (colspan > 1 || column == 1) |
|
1144 rc[row].second = w; |
|
1145 } |
|
1146 } |
|
1147 if (debugLayout) { |
|
1148 qDebug() << "FormLayoutHelper::state: " << rowCount; |
|
1149 for (int r = 0; r < rowCount; r++) |
|
1150 qDebug() << " Row: " << r << rc[r].first << rc[r].second; |
|
1151 } |
|
1152 return rc; |
|
1153 } |
|
1154 |
|
1155 void FormLayoutHelper::pushState(const QDesignerFormEditorInterface *core, const QWidget *widgetWithManagedLayout) |
|
1156 { |
|
1157 QFormLayout *formLayout = qobject_cast<QFormLayout *>(LayoutInfo::managedLayout(core, widgetWithManagedLayout)); |
|
1158 Q_ASSERT(formLayout); |
|
1159 m_states.push(state(formLayout)); |
|
1160 } |
|
1161 |
|
1162 void FormLayoutHelper::popState(const QDesignerFormEditorInterface *core, QWidget *widgetWithManagedLayout) |
|
1163 { |
|
1164 QFormLayout *formLayout = qobject_cast<QFormLayout *>(LayoutInfo::managedLayout(core, widgetWithManagedLayout)); |
|
1165 Q_ASSERT(!m_states.empty() && formLayout); |
|
1166 |
|
1167 const FormLayoutState storedState = m_states.pop(); |
|
1168 const FormLayoutState currentState = state(formLayout); |
|
1169 if (currentState == storedState) |
|
1170 return; |
|
1171 const int rowCount = storedState.size(); |
|
1172 // clear out, shrink if required, but maintain items via map, pad spacers |
|
1173 const BoxLayoutHelper::LayoutItemVector items = BoxLayoutHelper::disassembleLayout(formLayout); |
|
1174 if (rowCount < formLayout->rowCount()) |
|
1175 formLayout = static_cast<QFormLayout*>(recreateManagedLayout(core, widgetWithManagedLayout, formLayout )); |
|
1176 for (int r = 0; r < rowCount; r++) { |
|
1177 QWidget *widgets[FormLayoutColumns] = { storedState[r].first, storedState[r].second }; |
|
1178 const bool spanning = widgets[0] != 0 && widgets[0] == widgets[1]; |
|
1179 if (spanning) { |
|
1180 formLayout->setWidget(r, QFormLayout::SpanningRole, widgets[0]); |
|
1181 } else { |
|
1182 for (int c = 0; c < FormLayoutColumns; c++) { |
|
1183 const QFormLayout::ItemRole role = c == 0 ? QFormLayout::LabelRole : QFormLayout::FieldRole; |
|
1184 if (widgets[c]) { |
|
1185 Q_ASSERT(BoxLayoutHelper::findItemOfWidget(items, widgets[c])); |
|
1186 formLayout->setWidget(r, role, widgets[c]); |
|
1187 } else { |
|
1188 formLayout->setItem(r, role, createFormSpacer()); |
|
1189 } |
|
1190 } |
|
1191 } |
|
1192 } |
|
1193 } |
|
1194 |
|
1195 bool FormLayoutHelper::canSimplify(const QDesignerFormEditorInterface *core, const QWidget *widgetWithManagedLayout, const QRect &restrictionArea) const |
|
1196 { |
|
1197 const QFormLayout *formLayout = qobject_cast<QFormLayout *>(LayoutInfo::managedLayout(core, widgetWithManagedLayout)); |
|
1198 Q_ASSERT(formLayout); |
|
1199 return canSimplifyFormLayout(formLayout, restrictionArea); |
|
1200 } |
|
1201 |
|
1202 void FormLayoutHelper::simplify(const QDesignerFormEditorInterface *core, QWidget *widgetWithManagedLayout, const QRect &restrictionArea) |
|
1203 { |
|
1204 typedef QPair<QLayoutItem*, QLayoutItem*> LayoutItemPair; |
|
1205 typedef QVector<LayoutItemPair> LayoutItemPairs; |
|
1206 |
|
1207 QFormLayout *formLayout = qobject_cast<QFormLayout *>(LayoutInfo::managedLayout(core, widgetWithManagedLayout)); |
|
1208 Q_ASSERT(formLayout); |
|
1209 if (debugLayout) |
|
1210 qDebug() << "FormLayoutHelper::simplify"; |
|
1211 // Transform into vector of item pairs |
|
1212 const int rowCount = formLayout->rowCount(); |
|
1213 LayoutItemPairs pairs(rowCount, LayoutItemPair(0, 0)); |
|
1214 for (int i = formLayout->count() - 1; i >= 0; i--) { |
|
1215 int row, col,colspan; |
|
1216 getFormLayoutItemPosition(formLayout, i, &row, &col, 0, &colspan); |
|
1217 if (colspan > 1) { |
|
1218 pairs[row].first = pairs[row].second = formLayout->takeAt(i); |
|
1219 } else { |
|
1220 if (col == 0) |
|
1221 pairs[row].first = formLayout->takeAt(i); |
|
1222 else |
|
1223 pairs[row].second = formLayout->takeAt(i); |
|
1224 } |
|
1225 } |
|
1226 // Weed out empty ones |
|
1227 const int bottomCheckRow = qMin(rowCount, restrictionArea.y() + restrictionArea.height()); |
|
1228 for (int r = bottomCheckRow - 1; r >= restrictionArea.y(); r--) |
|
1229 if (LayoutInfo::isEmptyItem(pairs[r].first) && LayoutInfo::isEmptyItem(pairs[r].second)) { |
|
1230 delete pairs[r].first; |
|
1231 delete pairs[r].second; |
|
1232 pairs.remove(r); |
|
1233 } |
|
1234 const int simpleRowCount = pairs.size(); |
|
1235 if (simpleRowCount < rowCount) |
|
1236 formLayout = static_cast<QFormLayout *>(recreateManagedLayout(core, widgetWithManagedLayout, formLayout)); |
|
1237 // repopulate |
|
1238 for (int r = 0; r < simpleRowCount; r++) { |
|
1239 const bool spanning = pairs[r].first == pairs[r].second; |
|
1240 if (spanning) { |
|
1241 formLayout->setItem(r, QFormLayout::SpanningRole, pairs[r].first); |
|
1242 } else { |
|
1243 formLayout->setItem(r, QFormLayout::LabelRole, pairs[r].first); |
|
1244 formLayout->setItem(r, QFormLayout::FieldRole, pairs[r].second); |
|
1245 } |
|
1246 } |
|
1247 } |
|
1248 |
|
1249 LayoutHelper *LayoutHelper::createLayoutHelper(int type) |
|
1250 { |
|
1251 LayoutHelper *rc = 0; |
|
1252 switch (type) { |
|
1253 case LayoutInfo::HBox: |
|
1254 rc = new BoxLayoutHelper(Qt::Horizontal); |
|
1255 break; |
|
1256 case LayoutInfo::VBox: |
|
1257 rc = new BoxLayoutHelper(Qt::Vertical); |
|
1258 break; |
|
1259 case LayoutInfo::Grid: |
|
1260 rc = new GridLayoutHelper; |
|
1261 break; |
|
1262 case LayoutInfo::Form: |
|
1263 return new FormLayoutHelper; |
|
1264 default: |
|
1265 break; |
|
1266 } |
|
1267 Q_ASSERT(rc); |
|
1268 return rc; |
|
1269 } |
|
1270 |
|
1271 // ---- QLayoutSupport (LayoutDecorationExtension) |
|
1272 QLayoutSupport::QLayoutSupport(QDesignerFormWindowInterface *formWindow, QWidget *widget, LayoutHelper *helper, QObject *parent) : |
|
1273 QObject(parent), |
|
1274 m_formWindow(formWindow), |
|
1275 m_helper(helper), |
|
1276 m_widget(widget), |
|
1277 m_currentIndex(-1), |
|
1278 m_currentInsertMode(QDesignerLayoutDecorationExtension::InsertWidgetMode) |
|
1279 { |
|
1280 } |
|
1281 |
|
1282 QLayout * QLayoutSupport::layout() const |
|
1283 { |
|
1284 return LayoutInfo::managedLayout(m_formWindow->core(), m_widget); |
|
1285 } |
|
1286 |
|
1287 void QLayoutSupport::hideIndicator(Indicator i) |
|
1288 { |
|
1289 if (m_indicators[i]) |
|
1290 m_indicators[i]->hide(); |
|
1291 } |
|
1292 |
|
1293 void QLayoutSupport::showIndicator(Indicator i, const QRect &geometry, const QPalette &p) |
|
1294 { |
|
1295 if (!m_indicators[i]) |
|
1296 m_indicators[i] = new qdesigner_internal::InvisibleWidget(m_widget); |
|
1297 QWidget *indicator = m_indicators[i]; |
|
1298 indicator->setAutoFillBackground(true); |
|
1299 indicator->setPalette(p); |
|
1300 indicator->setGeometry(geometry); |
|
1301 indicator->show(); |
|
1302 indicator->raise(); |
|
1303 } |
|
1304 |
|
1305 QLayoutSupport::~QLayoutSupport() |
|
1306 { |
|
1307 delete m_helper; |
|
1308 for (int i = 0; i < NumIndicators; i++) |
|
1309 if (m_indicators[i]) |
|
1310 m_indicators[i]->deleteLater(); |
|
1311 } |
|
1312 |
|
1313 QGridLayout * QLayoutSupport::gridLayout() const |
|
1314 { |
|
1315 return qobject_cast<QGridLayout*>(LayoutInfo::managedLayout(m_formWindow->core(), m_widget)); |
|
1316 } |
|
1317 |
|
1318 QRect QLayoutSupport::itemInfo(int index) const |
|
1319 { |
|
1320 return m_helper->itemInfo(LayoutInfo::managedLayout(m_formWindow->core(), m_widget), index); |
|
1321 } |
|
1322 |
|
1323 void QLayoutSupport::setInsertMode(InsertMode im) |
|
1324 { |
|
1325 m_currentInsertMode = im; |
|
1326 } |
|
1327 |
|
1328 void QLayoutSupport::setCurrentCell(const QPair<int, int> &cell) |
|
1329 { |
|
1330 m_currentCell = cell; |
|
1331 } |
|
1332 |
|
1333 void QLayoutSupport::adjustIndicator(const QPoint &pos, int index) |
|
1334 { |
|
1335 if (index == -1) { // first item goes anywhere |
|
1336 hideIndicator(LeftIndicator); |
|
1337 hideIndicator(TopIndicator); |
|
1338 hideIndicator(RightIndicator); |
|
1339 hideIndicator(BottomIndicator); |
|
1340 return; |
|
1341 } |
|
1342 m_currentIndex = index; |
|
1343 m_currentInsertMode = QDesignerLayoutDecorationExtension::InsertWidgetMode; |
|
1344 |
|
1345 QLayoutItem *item = layout()->itemAt(index); |
|
1346 const QRect g = extendedGeometry(index); |
|
1347 // ### cleanup |
|
1348 if (LayoutInfo::isEmptyItem(item)) { |
|
1349 // Empty grid/form cell. Draw a rectangle |
|
1350 QPalette redPalette; |
|
1351 redPalette.setColor(QPalette::Window, Qt::red); |
|
1352 |
|
1353 showIndicator(LeftIndicator, QRect(g.x(), g.y(), indicatorSize, g.height()), redPalette); |
|
1354 showIndicator(TopIndicator, QRect(g.x(), g.y(), g.width(), indicatorSize), redPalette); |
|
1355 showIndicator(RightIndicator, QRect(g.right(), g.y(), indicatorSize, g.height()), redPalette); |
|
1356 showIndicator(BottomIndicator, QRect(g.x(), g.bottom(), g.width(), indicatorSize), redPalette); |
|
1357 setCurrentCellFromIndicatorOnEmptyCell(m_currentIndex); |
|
1358 } else { |
|
1359 // Append/Insert. Draw a bar left/right or above/below |
|
1360 QPalette bluePalette; |
|
1361 bluePalette.setColor(QPalette::Window, Qt::blue); |
|
1362 hideIndicator(LeftIndicator); |
|
1363 hideIndicator(TopIndicator); |
|
1364 |
|
1365 const int fromRight = g.right() - pos.x(); |
|
1366 const int fromBottom = g.bottom() - pos.y(); |
|
1367 |
|
1368 const int fromLeft = pos.x() - g.x(); |
|
1369 const int fromTop = pos.y() - g.y(); |
|
1370 |
|
1371 const int fromLeftRight = qMin(fromRight, fromLeft ); |
|
1372 const int fromBottomTop = qMin(fromBottom, fromTop); |
|
1373 |
|
1374 const Qt::Orientation indicatorOrientation = fromLeftRight < fromBottomTop ? Qt::Vertical : Qt::Horizontal; |
|
1375 |
|
1376 if (supportsIndicatorOrientation(indicatorOrientation)) { |
|
1377 const QRect r(layout()->geometry().topLeft(), layout()->parentWidget()->size()); |
|
1378 switch (indicatorOrientation) { |
|
1379 case Qt::Vertical: { |
|
1380 hideIndicator(BottomIndicator); |
|
1381 const bool closeToLeft = fromLeftRight == fromLeft; |
|
1382 showIndicator(RightIndicator, QRect(closeToLeft ? g.x() : g.right() + 1 - indicatorSize, 0, indicatorSize, r.height()), bluePalette); |
|
1383 |
|
1384 const int incr = closeToLeft ? 0 : +1; |
|
1385 setCurrentCellFromIndicator(indicatorOrientation, m_currentIndex, incr); |
|
1386 } |
|
1387 break; |
|
1388 case Qt::Horizontal: { |
|
1389 hideIndicator(RightIndicator); |
|
1390 const bool closeToTop = fromBottomTop == fromTop; |
|
1391 showIndicator(BottomIndicator, QRect(r.x(), closeToTop ? g.y() : g.bottom() + 1 - indicatorSize, r.width(), indicatorSize), bluePalette); |
|
1392 |
|
1393 const int incr = closeToTop ? 0 : +1; |
|
1394 setCurrentCellFromIndicator(indicatorOrientation, m_currentIndex, incr); |
|
1395 } |
|
1396 break; |
|
1397 } |
|
1398 } else { |
|
1399 hideIndicator(RightIndicator); |
|
1400 hideIndicator(BottomIndicator); |
|
1401 } // can handle indicatorOrientation |
|
1402 } |
|
1403 } |
|
1404 |
|
1405 int QLayoutSupport::indexOf(QLayoutItem *i) const |
|
1406 { |
|
1407 const QLayout *lt = layout(); |
|
1408 if (!lt) |
|
1409 return -1; |
|
1410 |
|
1411 int index = 0; |
|
1412 |
|
1413 while (QLayoutItem *item = lt->itemAt(index)) { |
|
1414 if (item == i) |
|
1415 return index; |
|
1416 |
|
1417 ++index; |
|
1418 } |
|
1419 |
|
1420 return -1; |
|
1421 } |
|
1422 |
|
1423 int QLayoutSupport::indexOf(QWidget *widget) const |
|
1424 { |
|
1425 const QLayout *lt = layout(); |
|
1426 if (!lt) |
|
1427 return -1; |
|
1428 |
|
1429 int index = 0; |
|
1430 while (QLayoutItem *item = lt->itemAt(index)) { |
|
1431 if (item->widget() == widget) |
|
1432 return index; |
|
1433 |
|
1434 ++index; |
|
1435 } |
|
1436 |
|
1437 return -1; |
|
1438 } |
|
1439 |
|
1440 QList<QWidget*> QLayoutSupport::widgets(QLayout *layout) const |
|
1441 { |
|
1442 if (!layout) |
|
1443 return QList<QWidget*>(); |
|
1444 |
|
1445 QList<QWidget*> lst; |
|
1446 int index = 0; |
|
1447 while (QLayoutItem *item = layout->itemAt(index)) { |
|
1448 ++index; |
|
1449 |
|
1450 QWidget *widget = item->widget(); |
|
1451 if (widget && formWindow()->isManaged(widget)) |
|
1452 lst.append(widget); |
|
1453 } |
|
1454 |
|
1455 return lst; |
|
1456 } |
|
1457 |
|
1458 int QLayoutSupport::findItemAt(QGridLayout *gridLayout, int at_row, int at_column) |
|
1459 { |
|
1460 return findGridItemAt(gridLayout, at_row, at_column); |
|
1461 } |
|
1462 |
|
1463 // Quick check whether simplify should be enabled for grids. May return false positives. |
|
1464 // Note: Calculating the occupied area does not work as spanning items may also be simplified. |
|
1465 |
|
1466 bool QLayoutSupport::canSimplifyQuickCheck(const QGridLayout *gl) |
|
1467 { |
|
1468 if (!gl) |
|
1469 return false; |
|
1470 const int colCount = gl->columnCount(); |
|
1471 const int rowCount = gl->rowCount(); |
|
1472 if (colCount < 2 || rowCount < 2) |
|
1473 return false; |
|
1474 // try to find a spacer. |
|
1475 const int count = gl->count(); |
|
1476 for (int index = 0; index < count; index++) |
|
1477 if (LayoutInfo::isEmptyItem(gl->itemAt(index))) |
|
1478 return true; |
|
1479 return false; |
|
1480 } |
|
1481 |
|
1482 bool QLayoutSupport::canSimplifyQuickCheck(const QFormLayout *fl) |
|
1483 { |
|
1484 return canSimplifyFormLayout(fl, QRect(QPoint(0, 0), QSize(32767, 32767))); |
|
1485 } |
|
1486 |
|
1487 // remove dummy spacers |
|
1488 bool QLayoutSupport::removeEmptyCells(QGridLayout *grid, const QRect &area) |
|
1489 { |
|
1490 return removeEmptyCellsOnGrid(grid, area); |
|
1491 } |
|
1492 |
|
1493 void QLayoutSupport::createEmptyCells(QGridLayout *gridLayout) |
|
1494 { |
|
1495 Q_ASSERT(gridLayout); |
|
1496 GridLayoutState gs; |
|
1497 gs.fromLayout(gridLayout); |
|
1498 |
|
1499 const GridLayoutState::CellStates cs = GridLayoutState::cellStates(gs.widgetItemMap.values(), gs.rowCount, gs.colCount); |
|
1500 for (int c = 0; c < gs.colCount; c++) |
|
1501 for (int r = 0; r < gs.rowCount; r++) |
|
1502 if (needsSpacerItem(cs[r * gs.colCount + c])) { |
|
1503 const int existingItemIndex = findItemAt(gridLayout, r, c); |
|
1504 if (existingItemIndex == -1) |
|
1505 gridLayout->addItem(createGridSpacer(), r, c); |
|
1506 } |
|
1507 } |
|
1508 |
|
1509 bool QLayoutSupport::removeEmptyCells(QFormLayout *formLayout, const QRect &area) |
|
1510 { |
|
1511 return removeEmptyCellsOnGrid(formLayout, area); |
|
1512 } |
|
1513 |
|
1514 void QLayoutSupport::createEmptyCells(QFormLayout *formLayout) |
|
1515 { |
|
1516 // No spanning items here.. |
|
1517 if (const int rowCount = formLayout->rowCount()) |
|
1518 for (int c = 0; c < FormLayoutColumns; c++) |
|
1519 for (int r = 0; r < rowCount; r++) |
|
1520 if (findGridItemAt(formLayout, r, c) == -1) |
|
1521 formLayout->setItem(r, c == 0 ? QFormLayout::LabelRole : QFormLayout::FieldRole, createFormSpacer()); |
|
1522 } |
|
1523 |
|
1524 int QLayoutSupport::findItemAt(const QPoint &pos) const |
|
1525 { |
|
1526 if (!layout()) |
|
1527 return -1; |
|
1528 |
|
1529 const QLayout *lt = layout(); |
|
1530 const int count = lt->count(); |
|
1531 |
|
1532 if (count == 0) |
|
1533 return -1; |
|
1534 |
|
1535 int best = -1; |
|
1536 int bestIndex = -1; |
|
1537 |
|
1538 for (int index = 0; index < count; index++) { |
|
1539 QLayoutItem *item = lt->itemAt(index); |
|
1540 bool visible = true; |
|
1541 // When dragging widgets within layout, the source widget is invisible and must not be hit |
|
1542 if (const QWidget *w = item->widget()) |
|
1543 visible = w->isVisible(); |
|
1544 if (visible) { |
|
1545 const QRect g = item->geometry(); |
|
1546 |
|
1547 const int dist = (g.center() - pos).manhattanLength(); |
|
1548 if (best == -1 || dist < best) { |
|
1549 best = dist; |
|
1550 bestIndex = index; |
|
1551 } |
|
1552 } |
|
1553 } |
|
1554 return bestIndex; |
|
1555 } |
|
1556 |
|
1557 // ------------ QBoxLayoutSupport (LayoutDecorationExtension) |
|
1558 namespace { |
|
1559 class QBoxLayoutSupport: public QLayoutSupport |
|
1560 { |
|
1561 public: |
|
1562 QBoxLayoutSupport(QDesignerFormWindowInterface *formWindow, QWidget *widget, Qt::Orientation orientation, QObject *parent = 0); |
|
1563 |
|
1564 virtual void insertWidget(QWidget *widget, const QPair<int, int> &cell); |
|
1565 virtual void removeWidget(QWidget *widget); |
|
1566 virtual void simplify() {} |
|
1567 virtual void insertRow(int /*row*/) {} |
|
1568 virtual void insertColumn(int /*column*/) {} |
|
1569 |
|
1570 virtual int findItemAt(int /*at_row*/, int /*at_column*/) const { return -1; } |
|
1571 |
|
1572 private: |
|
1573 virtual void setCurrentCellFromIndicatorOnEmptyCell(int index); |
|
1574 virtual void setCurrentCellFromIndicator(Qt::Orientation indicatorOrientation, int index, int increment); |
|
1575 virtual bool supportsIndicatorOrientation(Qt::Orientation indicatorOrientation) const; |
|
1576 virtual QRect extendedGeometry(int index) const; |
|
1577 |
|
1578 const Qt::Orientation m_orientation; |
|
1579 }; |
|
1580 |
|
1581 void QBoxLayoutSupport::removeWidget(QWidget *widget) |
|
1582 { |
|
1583 QLayout *lt = layout(); |
|
1584 const int index = lt->indexOf(widget); |
|
1585 // Adjust the current cell in case a widget was dragged within the same layout to a position |
|
1586 // of higher index, which happens as follows: |
|
1587 // Drag start: The widget is hidden |
|
1588 // Drop: Current cell is stored, widget is removed and re-added, causing an index offset that needs to be compensated |
|
1589 QPair<int, int> currCell = currentCell(); |
|
1590 switch (m_orientation) { |
|
1591 case Qt::Horizontal: |
|
1592 if (currCell.second > 0 && index < currCell.second ) { |
|
1593 currCell.second--; |
|
1594 setCurrentCell(currCell); |
|
1595 } |
|
1596 break; |
|
1597 case Qt::Vertical: |
|
1598 if (currCell.first > 0 && index < currCell.first) { |
|
1599 currCell.first--; |
|
1600 setCurrentCell(currCell); |
|
1601 } |
|
1602 break; |
|
1603 } |
|
1604 helper()->removeWidget(lt, widget); |
|
1605 } |
|
1606 |
|
1607 QBoxLayoutSupport::QBoxLayoutSupport(QDesignerFormWindowInterface *formWindow, QWidget *widget, Qt::Orientation orientation, QObject *parent) : |
|
1608 QLayoutSupport(formWindow, widget, new BoxLayoutHelper(orientation), parent), |
|
1609 m_orientation(orientation) |
|
1610 { |
|
1611 } |
|
1612 |
|
1613 void QBoxLayoutSupport::setCurrentCellFromIndicatorOnEmptyCell(int index) |
|
1614 { |
|
1615 qDebug() << "QBoxLayoutSupport::setCurrentCellFromIndicatorOnEmptyCell(): Warning: found a fake spacer inside a vbox layout at " << index; |
|
1616 setCurrentCell(qMakePair(0, 0)); |
|
1617 } |
|
1618 |
|
1619 void QBoxLayoutSupport::insertWidget(QWidget *widget, const QPair<int, int> &cell) |
|
1620 { |
|
1621 switch (m_orientation) { |
|
1622 case Qt::Horizontal: |
|
1623 helper()->insertWidget(layout(), QRect(cell.second, 0, 1, 1), widget); |
|
1624 break; |
|
1625 case Qt::Vertical: |
|
1626 helper()->insertWidget(layout(), QRect(0, cell.first, 1, 1), widget); |
|
1627 break; |
|
1628 } |
|
1629 } |
|
1630 |
|
1631 void QBoxLayoutSupport::setCurrentCellFromIndicator(Qt::Orientation indicatorOrientation, int index, int increment) |
|
1632 { |
|
1633 if (m_orientation == Qt::Horizontal && indicatorOrientation == Qt::Vertical) { |
|
1634 setCurrentCell(qMakePair(0, index + increment)); |
|
1635 } else if (m_orientation == Qt::Vertical && indicatorOrientation == Qt::Horizontal) { |
|
1636 setCurrentCell(qMakePair(index + increment, 0)); |
|
1637 } |
|
1638 } |
|
1639 |
|
1640 bool QBoxLayoutSupport::supportsIndicatorOrientation(Qt::Orientation indicatorOrientation) const |
|
1641 { |
|
1642 return m_orientation != indicatorOrientation; |
|
1643 } |
|
1644 |
|
1645 QRect QBoxLayoutSupport::extendedGeometry(int index) const |
|
1646 { |
|
1647 QLayoutItem *item = layout()->itemAt(index); |
|
1648 // start off with item geometry |
|
1649 QRect g = item->geometry(); |
|
1650 |
|
1651 const QRect info = itemInfo(index); |
|
1652 |
|
1653 // On left border: extend to widget border |
|
1654 if (info.x() == 0) { |
|
1655 QPoint topLeft = g.topLeft(); |
|
1656 topLeft.rx() = layout()->geometry().left(); |
|
1657 g.setTopLeft(topLeft); |
|
1658 } |
|
1659 |
|
1660 // On top border: extend to widget border |
|
1661 if (info.y() == 0) { |
|
1662 QPoint topLeft = g.topLeft(); |
|
1663 topLeft.ry() = layout()->geometry().top(); |
|
1664 g.setTopLeft(topLeft); |
|
1665 } |
|
1666 |
|
1667 // is this the last item? |
|
1668 const QBoxLayout *box = static_cast<const QBoxLayout*>(layout()); |
|
1669 if (index < box->count() -1) |
|
1670 return g; // Nope. |
|
1671 |
|
1672 // extend to widget border |
|
1673 QPoint bottomRight = g.bottomRight(); |
|
1674 switch (m_orientation) { |
|
1675 case Qt::Vertical: |
|
1676 bottomRight.ry() = layout()->geometry().bottom(); |
|
1677 break; |
|
1678 case Qt::Horizontal: |
|
1679 bottomRight.rx() = layout()->geometry().right(); |
|
1680 break; |
|
1681 } |
|
1682 g.setBottomRight(bottomRight); |
|
1683 return g; |
|
1684 } |
|
1685 |
|
1686 // -------------- Base class for QGridLayout-like support classes (LayoutDecorationExtension) |
|
1687 template <class GridLikeLayout> |
|
1688 class GridLikeLayoutSupportBase: public QLayoutSupport |
|
1689 { |
|
1690 public: |
|
1691 |
|
1692 GridLikeLayoutSupportBase(QDesignerFormWindowInterface *formWindow, QWidget *widget, LayoutHelper *helper, QObject *parent = 0) : |
|
1693 QLayoutSupport(formWindow, widget, helper, parent) {} |
|
1694 |
|
1695 void insertWidget(QWidget *widget, const QPair<int, int> &cell); |
|
1696 virtual void removeWidget(QWidget *widget) { helper()->removeWidget(layout(), widget); } |
|
1697 virtual int findItemAt(int row, int column) const; |
|
1698 |
|
1699 protected: |
|
1700 GridLikeLayout *gridLikeLayout() const { |
|
1701 return qobject_cast<GridLikeLayout*>(LayoutInfo::managedLayout(formWindow()->core(), widget())); |
|
1702 } |
|
1703 |
|
1704 private: |
|
1705 |
|
1706 virtual void setCurrentCellFromIndicatorOnEmptyCell(int index); |
|
1707 virtual void setCurrentCellFromIndicator(Qt::Orientation indicatorOrientation, int index, int increment); |
|
1708 virtual bool supportsIndicatorOrientation(Qt::Orientation) const { return true; } |
|
1709 |
|
1710 virtual QRect extendedGeometry(int index) const; |
|
1711 |
|
1712 // Overwrite to check the insertion position (if there are limits) |
|
1713 virtual void checkCellForInsertion(int * /*row*/, int * /*col*/) const {} |
|
1714 }; |
|
1715 |
|
1716 template <class GridLikeLayout> |
|
1717 void GridLikeLayoutSupportBase<GridLikeLayout>::setCurrentCellFromIndicatorOnEmptyCell(int index) |
|
1718 { |
|
1719 GridLikeLayout *grid = gridLikeLayout(); |
|
1720 Q_ASSERT(grid); |
|
1721 |
|
1722 setInsertMode(InsertWidgetMode); |
|
1723 int row, column, rowspan, colspan; |
|
1724 |
|
1725 getGridItemPosition(grid, index, &row, &column, &rowspan, &colspan); |
|
1726 setCurrentCell(qMakePair(row, column)); |
|
1727 } |
|
1728 |
|
1729 template <class GridLikeLayout> |
|
1730 void GridLikeLayoutSupportBase<GridLikeLayout>::setCurrentCellFromIndicator(Qt::Orientation indicatorOrientation, int index, int increment) { |
|
1731 const QRect info = itemInfo(index); |
|
1732 switch (indicatorOrientation) { |
|
1733 case Qt::Vertical: { |
|
1734 setInsertMode(InsertColumnMode); |
|
1735 int row = info.top(); |
|
1736 int column = increment ? info.right() + 1 : info.left(); |
|
1737 checkCellForInsertion(&row, &column); |
|
1738 setCurrentCell(qMakePair(row , column)); |
|
1739 } |
|
1740 break; |
|
1741 case Qt::Horizontal: { |
|
1742 setInsertMode(InsertRowMode); |
|
1743 int row = increment ? info.bottom() + 1 : info.top(); |
|
1744 int column = info.left(); |
|
1745 checkCellForInsertion(&row, &column); |
|
1746 setCurrentCell(qMakePair(row, column)); |
|
1747 } |
|
1748 break; |
|
1749 } |
|
1750 } |
|
1751 |
|
1752 template <class GridLikeLayout> |
|
1753 void GridLikeLayoutSupportBase<GridLikeLayout>::insertWidget(QWidget *widget, const QPair<int, int> &cell) |
|
1754 { |
|
1755 helper()->insertWidget(layout(), QRect(cell.second, cell.first, 1, 1), widget); |
|
1756 } |
|
1757 |
|
1758 template <class GridLikeLayout> |
|
1759 int GridLikeLayoutSupportBase<GridLikeLayout>::findItemAt(int at_row, int at_column) const |
|
1760 { |
|
1761 GridLikeLayout *grid = gridLikeLayout(); |
|
1762 Q_ASSERT(grid); |
|
1763 return findGridItemAt(grid, at_row, at_column); |
|
1764 } |
|
1765 |
|
1766 template <class GridLikeLayout> |
|
1767 QRect GridLikeLayoutSupportBase<GridLikeLayout>::extendedGeometry(int index) const |
|
1768 { |
|
1769 QLayoutItem *item = layout()->itemAt(index); |
|
1770 // start off with item geometry |
|
1771 QRect g = item->geometry(); |
|
1772 |
|
1773 const QRect info = itemInfo(index); |
|
1774 |
|
1775 // On left border: extend to widget border |
|
1776 if (info.x() == 0) { |
|
1777 QPoint topLeft = g.topLeft(); |
|
1778 topLeft.rx() = layout()->geometry().left(); |
|
1779 g.setTopLeft(topLeft); |
|
1780 } |
|
1781 |
|
1782 // On top border: extend to widget border |
|
1783 if (info.y() == 0) { |
|
1784 QPoint topLeft = g.topLeft(); |
|
1785 topLeft.ry() = layout()->geometry().top(); |
|
1786 g.setTopLeft(topLeft); |
|
1787 } |
|
1788 const GridLikeLayout *grid = gridLikeLayout(); |
|
1789 Q_ASSERT(grid); |
|
1790 |
|
1791 // extend to widget border |
|
1792 QPoint bottomRight = g.bottomRight(); |
|
1793 if (gridRowCount(grid) == info.y()) |
|
1794 bottomRight.ry() = layout()->geometry().bottom(); |
|
1795 if (gridColumnCount(grid) == info.x()) |
|
1796 bottomRight.rx() = layout()->geometry().right(); |
|
1797 g.setBottomRight(bottomRight); |
|
1798 return g; |
|
1799 } |
|
1800 |
|
1801 // -------------- QGridLayoutSupport (LayoutDecorationExtension) |
|
1802 class QGridLayoutSupport: public GridLikeLayoutSupportBase<QGridLayout> |
|
1803 { |
|
1804 public: |
|
1805 |
|
1806 QGridLayoutSupport(QDesignerFormWindowInterface *formWindow, QWidget *widget, QObject *parent = 0); |
|
1807 |
|
1808 virtual void simplify(); |
|
1809 virtual void insertRow(int row); |
|
1810 virtual void insertColumn(int column); |
|
1811 |
|
1812 private: |
|
1813 }; |
|
1814 |
|
1815 QGridLayoutSupport::QGridLayoutSupport(QDesignerFormWindowInterface *formWindow, QWidget *widget, QObject *parent) : |
|
1816 GridLikeLayoutSupportBase<QGridLayout>(formWindow, widget, new GridLayoutHelper, parent) |
|
1817 { |
|
1818 } |
|
1819 |
|
1820 void QGridLayoutSupport::insertRow(int row) |
|
1821 { |
|
1822 QGridLayout *grid = gridLayout(); |
|
1823 Q_ASSERT(grid); |
|
1824 GridLayoutHelper::insertRow(grid, row); |
|
1825 } |
|
1826 |
|
1827 void QGridLayoutSupport::insertColumn(int column) |
|
1828 { |
|
1829 QGridLayout *grid = gridLayout(); |
|
1830 Q_ASSERT(grid); |
|
1831 GridLayoutState state; |
|
1832 state.fromLayout(grid); |
|
1833 state.insertColumn(column); |
|
1834 state.applyToLayout(formWindow()->core(), widget()); |
|
1835 } |
|
1836 |
|
1837 void QGridLayoutSupport::simplify() |
|
1838 { |
|
1839 QGridLayout *grid = gridLayout(); |
|
1840 Q_ASSERT(grid); |
|
1841 GridLayoutState state; |
|
1842 state.fromLayout(grid); |
|
1843 |
|
1844 const QRect fullArea = QRect(0, 0, state.colCount, state.rowCount); |
|
1845 if (state.simplify(fullArea, false)) |
|
1846 state.applyToLayout(formWindow()->core(), widget()); |
|
1847 } |
|
1848 |
|
1849 // -------------- QFormLayoutSupport (LayoutDecorationExtension) |
|
1850 class QFormLayoutSupport: public GridLikeLayoutSupportBase<QFormLayout> |
|
1851 { |
|
1852 public: |
|
1853 QFormLayoutSupport(QDesignerFormWindowInterface *formWindow, QWidget *widget, QObject *parent = 0); |
|
1854 |
|
1855 virtual void simplify() {} |
|
1856 virtual void insertRow(int /*row*/) {} |
|
1857 virtual void insertColumn(int /*column*/) {} |
|
1858 |
|
1859 private: |
|
1860 virtual void checkCellForInsertion(int * row, int *col) const; |
|
1861 }; |
|
1862 |
|
1863 QFormLayoutSupport::QFormLayoutSupport(QDesignerFormWindowInterface *formWindow, QWidget *widget, QObject *parent) : |
|
1864 GridLikeLayoutSupportBase<QFormLayout>(formWindow, widget, new FormLayoutHelper, parent) |
|
1865 { |
|
1866 } |
|
1867 |
|
1868 void QFormLayoutSupport::checkCellForInsertion(int *row, int *col) const |
|
1869 { |
|
1870 if (*col >= FormLayoutColumns) { // Clamp to 2 columns |
|
1871 *col = 1; |
|
1872 (*row)++; |
|
1873 } |
|
1874 } |
|
1875 } // anonymous namespace |
|
1876 |
|
1877 QLayoutSupport *QLayoutSupport::createLayoutSupport(QDesignerFormWindowInterface *formWindow, QWidget *widget, QObject *parent) |
|
1878 { |
|
1879 const QLayout *layout = LayoutInfo::managedLayout(formWindow->core(), widget); |
|
1880 Q_ASSERT(layout); |
|
1881 QLayoutSupport *rc = 0; |
|
1882 switch (LayoutInfo::layoutType(formWindow->core(), layout)) { |
|
1883 case LayoutInfo::HBox: |
|
1884 rc = new QBoxLayoutSupport(formWindow, widget, Qt::Horizontal, parent); |
|
1885 break; |
|
1886 case LayoutInfo::VBox: |
|
1887 rc = new QBoxLayoutSupport(formWindow, widget, Qt::Vertical, parent); |
|
1888 break; |
|
1889 case LayoutInfo::Grid: |
|
1890 rc = new QGridLayoutSupport(formWindow, widget, parent); |
|
1891 break; |
|
1892 case LayoutInfo::Form: |
|
1893 rc = new QFormLayoutSupport(formWindow, widget, parent); |
|
1894 break; |
|
1895 default: |
|
1896 break; |
|
1897 } |
|
1898 Q_ASSERT(rc); |
|
1899 return rc; |
|
1900 } |
|
1901 } // namespace qdesigner_internal |
|
1902 |
|
1903 // -------------- QLayoutWidget |
|
1904 QLayoutWidget::QLayoutWidget(QDesignerFormWindowInterface *formWindow, QWidget *parent) |
|
1905 : QWidget(parent), m_formWindow(formWindow), |
|
1906 m_leftMargin(0), m_topMargin(0), m_rightMargin(0), m_bottomMargin(0) |
|
1907 { |
|
1908 } |
|
1909 |
|
1910 void QLayoutWidget::paintEvent(QPaintEvent*) |
|
1911 { |
|
1912 if (m_formWindow->currentTool() != 0) |
|
1913 return; |
|
1914 |
|
1915 // only draw red borders if we're editting widgets |
|
1916 |
|
1917 QPainter p(this); |
|
1918 |
|
1919 QMap<int, QMap<int, bool> > excludedRowsForColumn; |
|
1920 QMap<int, QMap<int, bool> > excludedColumnsForRow; |
|
1921 |
|
1922 QLayout *lt = layout(); |
|
1923 QGridLayout *grid = qobject_cast<QGridLayout *>(lt); |
|
1924 if (lt) { |
|
1925 if (const int count = lt->count()) { |
|
1926 p.setPen(QPen(QColor(255, 0, 0, 35), 1)); |
|
1927 for (int i = 0; i < count; i++) { |
|
1928 QLayoutItem *item = lt->itemAt(i); |
|
1929 if (grid) { |
|
1930 int row, column, rowSpan, columnSpan; |
|
1931 grid->getItemPosition(i, &row, &column, &rowSpan, &columnSpan); |
|
1932 QMap<int, bool> rows; |
|
1933 QMap<int, bool> columns; |
|
1934 for (int i = rowSpan; i > 1; i--) |
|
1935 rows[row + i - 2] = true; |
|
1936 for (int i = columnSpan; i > 1; i--) |
|
1937 columns[column + i - 2] = true; |
|
1938 |
|
1939 while (rowSpan > 0) { |
|
1940 excludedColumnsForRow[row + rowSpan - 1].unite(columns); |
|
1941 rowSpan--; |
|
1942 } |
|
1943 while (columnSpan > 0) { |
|
1944 excludedRowsForColumn[column + columnSpan - 1].unite(rows); |
|
1945 columnSpan--; |
|
1946 } |
|
1947 } |
|
1948 if (item->spacerItem()) { |
|
1949 const QRect geometry = item->geometry(); |
|
1950 if (!geometry.isNull()) |
|
1951 p.drawRect(geometry.adjusted(1, 1, -2, -2)); |
|
1952 } |
|
1953 } |
|
1954 } |
|
1955 } |
|
1956 if (grid) { |
|
1957 p.setPen(QPen(QColor(0, 0x80, 0, 0x80), 1)); |
|
1958 const int rowCount = grid->rowCount(); |
|
1959 const int columnCount = grid->columnCount(); |
|
1960 for (int i = 0; i < rowCount; i++) { |
|
1961 for (int j = 0; j < columnCount; j++) { |
|
1962 const QRect cellRect = grid->cellRect(i, j); |
|
1963 if (j < columnCount - 1 && excludedColumnsForRow.value(i).value(j, false) == false) { |
|
1964 const double y0 = (i == 0) |
|
1965 ? 0 : (grid->cellRect(i - 1, j).bottom() + cellRect.top()) / 2.0; |
|
1966 const double y1 = (i == rowCount - 1) |
|
1967 ? height() - 1 : (cellRect.bottom() + grid->cellRect(i + 1, j).top()) / 2.0; |
|
1968 const double x = (cellRect.right() + grid->cellRect(i, j + 1).left()) / 2.0; |
|
1969 p.drawLine(QPointF(x, y0), QPointF(x, y1)); |
|
1970 } |
|
1971 if (i < rowCount - 1 && excludedRowsForColumn.value(j).value(i, false) == false) { |
|
1972 const double x0 = (j == 0) |
|
1973 ? 0 : (grid->cellRect(i, j - 1).right() + cellRect.left()) / 2.0; |
|
1974 const double x1 = (j == columnCount - 1) |
|
1975 ? width() - 1 : (cellRect.right() + grid->cellRect(i, j + 1).left()) / 2.0; |
|
1976 const double y = (cellRect.bottom() + grid->cellRect(i + 1, j).top()) / 2.0; |
|
1977 p.drawLine(QPointF(x0, y), QPointF(x1, y)); |
|
1978 } |
|
1979 } |
|
1980 } |
|
1981 } |
|
1982 p.setPen(QPen(QColor(255, 0, 0, 128), 1)); |
|
1983 p.drawRect(0, 0, width() - 1, height() - 1); |
|
1984 } |
|
1985 |
|
1986 bool QLayoutWidget::event(QEvent *e) |
|
1987 { |
|
1988 switch (e->type()) { |
|
1989 case QEvent::LayoutRequest: { |
|
1990 (void) QWidget::event(e); |
|
1991 // Magic: We are layouted, but the parent is not.. |
|
1992 if (layout() && qdesigner_internal::LayoutInfo::layoutType(formWindow()->core(), parentWidget()) == qdesigner_internal::LayoutInfo::NoLayout) { |
|
1993 resize(layout()->totalMinimumSize().expandedTo(size())); |
|
1994 } |
|
1995 |
|
1996 update(); |
|
1997 |
|
1998 return true; |
|
1999 } |
|
2000 |
|
2001 default: |
|
2002 break; |
|
2003 } |
|
2004 |
|
2005 return QWidget::event(e); |
|
2006 } |
|
2007 |
|
2008 int QLayoutWidget::layoutLeftMargin() const |
|
2009 { |
|
2010 if (m_leftMargin < 0 && layout()) { |
|
2011 int margin; |
|
2012 layout()->getContentsMargins(&margin, 0, 0, 0); |
|
2013 return margin; |
|
2014 } |
|
2015 return m_leftMargin; |
|
2016 } |
|
2017 |
|
2018 void QLayoutWidget::setLayoutLeftMargin(int layoutMargin) |
|
2019 { |
|
2020 m_leftMargin = layoutMargin; |
|
2021 if (layout()) { |
|
2022 int newMargin = m_leftMargin; |
|
2023 if (newMargin >= 0 && newMargin < ShiftValue) |
|
2024 newMargin = ShiftValue; |
|
2025 int left, top, right, bottom; |
|
2026 layout()->getContentsMargins(&left, &top, &right, &bottom); |
|
2027 layout()->setContentsMargins(newMargin, top, right, bottom); |
|
2028 } |
|
2029 } |
|
2030 |
|
2031 int QLayoutWidget::layoutTopMargin() const |
|
2032 { |
|
2033 if (m_topMargin < 0 && layout()) { |
|
2034 int margin; |
|
2035 layout()->getContentsMargins(0, &margin, 0, 0); |
|
2036 return margin; |
|
2037 } |
|
2038 return m_topMargin; |
|
2039 } |
|
2040 |
|
2041 void QLayoutWidget::setLayoutTopMargin(int layoutMargin) |
|
2042 { |
|
2043 m_topMargin = layoutMargin; |
|
2044 if (layout()) { |
|
2045 int newMargin = m_topMargin; |
|
2046 if (newMargin >= 0 && newMargin < ShiftValue) |
|
2047 newMargin = ShiftValue; |
|
2048 int left, top, right, bottom; |
|
2049 layout()->getContentsMargins(&left, &top, &right, &bottom); |
|
2050 layout()->setContentsMargins(left, newMargin, right, bottom); |
|
2051 } |
|
2052 } |
|
2053 |
|
2054 int QLayoutWidget::layoutRightMargin() const |
|
2055 { |
|
2056 if (m_rightMargin < 0 && layout()) { |
|
2057 int margin; |
|
2058 layout()->getContentsMargins(0, 0, &margin, 0); |
|
2059 return margin; |
|
2060 } |
|
2061 return m_rightMargin; |
|
2062 } |
|
2063 |
|
2064 void QLayoutWidget::setLayoutRightMargin(int layoutMargin) |
|
2065 { |
|
2066 m_rightMargin = layoutMargin; |
|
2067 if (layout()) { |
|
2068 int newMargin = m_rightMargin; |
|
2069 if (newMargin >= 0 && newMargin < ShiftValue) |
|
2070 newMargin = ShiftValue; |
|
2071 int left, top, right, bottom; |
|
2072 layout()->getContentsMargins(&left, &top, &right, &bottom); |
|
2073 layout()->setContentsMargins(left, top, newMargin, bottom); |
|
2074 } |
|
2075 } |
|
2076 |
|
2077 int QLayoutWidget::layoutBottomMargin() const |
|
2078 { |
|
2079 if (m_bottomMargin < 0 && layout()) { |
|
2080 int margin; |
|
2081 layout()->getContentsMargins(0, 0, 0, &margin); |
|
2082 return margin; |
|
2083 } |
|
2084 return m_bottomMargin; |
|
2085 } |
|
2086 |
|
2087 void QLayoutWidget::setLayoutBottomMargin(int layoutMargin) |
|
2088 { |
|
2089 m_bottomMargin = layoutMargin; |
|
2090 if (layout()) { |
|
2091 int newMargin = m_bottomMargin; |
|
2092 if (newMargin >= 0 && newMargin < ShiftValue) |
|
2093 newMargin = ShiftValue; |
|
2094 int left, top, right, bottom; |
|
2095 layout()->getContentsMargins(&left, &top, &right, &bottom); |
|
2096 layout()->setContentsMargins(left, top, right, newMargin); |
|
2097 } |
|
2098 } |
|
2099 |
|
2100 QT_END_NAMESPACE |