1 | /**************************************************************************** |
2 | ** |
3 | ** Copyright (C) 2016 The Qt Company Ltd. |
4 | ** Contact: https://www.qt.io/licensing/ |
5 | ** |
6 | ** This file is part of the Qt Designer of the Qt Toolkit. |
7 | ** |
8 | ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ |
9 | ** Commercial License Usage |
10 | ** Licensees holding valid commercial Qt licenses may use this file in |
11 | ** accordance with the commercial license agreement provided with the |
12 | ** Software or, alternatively, in accordance with the terms contained in |
13 | ** a written agreement between you and The Qt Company. For licensing terms |
14 | ** and conditions see https://www.qt.io/terms-conditions. For further |
15 | ** information use the contact form at https://www.qt.io/contact-us. |
16 | ** |
17 | ** GNU General Public License Usage |
18 | ** Alternatively, this file may be used under the terms of the GNU |
19 | ** General Public License version 3 as published by the Free Software |
20 | ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT |
21 | ** included in the packaging of this file. Please review the following |
22 | ** information to ensure the GNU General Public License requirements will |
23 | ** be met: https://www.gnu.org/licenses/gpl-3.0.html. |
24 | ** |
25 | ** $QT_END_LICENSE$ |
26 | ** |
27 | ****************************************************************************/ |
28 | |
29 | #include "qdesigner_command2_p.h" |
30 | #include "formwindowbase_p.h" |
31 | #include "layoutinfo_p.h" |
32 | #include "qdesigner_command_p.h" |
33 | #include "widgetfactory_p.h" |
34 | #include "qlayout_widget_p.h" |
35 | |
36 | #include <QtDesigner/abstractformeditor.h> |
37 | #include <QtDesigner/abstractmetadatabase.h> |
38 | |
39 | #include <QtWidgets/qapplication.h> |
40 | #include <QtWidgets/qlayout.h> |
41 | |
42 | QT_BEGIN_NAMESPACE |
43 | |
44 | namespace qdesigner_internal { |
45 | |
46 | MorphLayoutCommand::MorphLayoutCommand(QDesignerFormWindowInterface *formWindow) : |
47 | QDesignerFormWindowCommand(QString(), formWindow), |
48 | m_breakLayoutCommand(new BreakLayoutCommand(formWindow)), |
49 | m_layoutCommand(new LayoutCommand(formWindow)), |
50 | m_newType(LayoutInfo::VBox), |
51 | m_layoutBase(nullptr) |
52 | { |
53 | } |
54 | |
55 | MorphLayoutCommand::~MorphLayoutCommand() |
56 | { |
57 | delete m_layoutCommand; |
58 | delete m_breakLayoutCommand; |
59 | } |
60 | |
61 | bool MorphLayoutCommand::init(QWidget *w, int newType) |
62 | { |
63 | int oldType; |
64 | QDesignerFormWindowInterface *fw = formWindow(); |
65 | if (!canMorph(formWindow: fw, w, ptrToCurrentType: &oldType) || oldType == newType) |
66 | return false; |
67 | m_layoutBase = w; |
68 | m_newType = newType; |
69 | // Find all managed widgets |
70 | m_widgets.clear(); |
71 | const QLayout *layout = LayoutInfo::managedLayout(core: fw->core(), widget: w); |
72 | const int count = layout->count(); |
73 | for (int i = 0; i < count ; i++) { |
74 | if (QWidget *w = layout->itemAt(index: i)->widget()) |
75 | if (fw->isManaged(widget: w)) |
76 | m_widgets.push_back(t: w); |
77 | } |
78 | const bool reparentLayoutWidget = false; // leave QLayoutWidget intact |
79 | m_breakLayoutCommand->init(widgets: m_widgets, layoutBase: m_layoutBase, reparentLayoutWidget); |
80 | m_layoutCommand->init(parentWidget: m_layoutBase, widgets: m_widgets, layoutType: static_cast<LayoutInfo::Type>(m_newType), layoutBase: m_layoutBase, reparentLayoutWidget); |
81 | setText(formatDescription(core: core(), w: m_layoutBase, oldType, newType)); |
82 | return true; |
83 | } |
84 | |
85 | bool MorphLayoutCommand::canMorph(const QDesignerFormWindowInterface *formWindow, QWidget *w, int *ptrToCurrentType) |
86 | { |
87 | if (ptrToCurrentType) |
88 | *ptrToCurrentType = LayoutInfo::NoLayout; |
89 | // We want a managed widget or a container page |
90 | // with a level-0 managed layout |
91 | QDesignerFormEditorInterface *core = formWindow->core(); |
92 | QLayout *layout = LayoutInfo::managedLayout(core, widget: w); |
93 | if (!layout) |
94 | return false; |
95 | const LayoutInfo::Type type = LayoutInfo::layoutType(core, layout); |
96 | if (ptrToCurrentType) |
97 | *ptrToCurrentType = type; |
98 | switch (type) { |
99 | case LayoutInfo::HBox: |
100 | case LayoutInfo::VBox: |
101 | case LayoutInfo::Grid: |
102 | case LayoutInfo::Form: |
103 | return true; |
104 | break; |
105 | case LayoutInfo::NoLayout: |
106 | case LayoutInfo::HSplitter: // Nothing doing |
107 | case LayoutInfo::VSplitter: |
108 | case LayoutInfo::UnknownLayout: |
109 | break; |
110 | } |
111 | return false; |
112 | } |
113 | |
114 | void MorphLayoutCommand::redo() |
115 | { |
116 | m_breakLayoutCommand->redo(); |
117 | m_layoutCommand->redo(); |
118 | /* Transfer applicable properties which is a cross-section of the modified |
119 | * properties except object name. */ |
120 | if (const LayoutProperties *properties = m_breakLayoutCommand->layoutProperties()) { |
121 | const int oldMask = m_breakLayoutCommand->propertyMask(); |
122 | QLayout *newLayout = LayoutInfo::managedLayout(core: core(), widget: m_layoutBase); |
123 | const int newMask = LayoutProperties::visibleProperties(layout: newLayout); |
124 | const int applicableMask = (oldMask & newMask) & ~LayoutProperties::ObjectNameProperty; |
125 | if (applicableMask) |
126 | properties->toPropertySheet(core: core(), l: newLayout, mask: applicableMask); |
127 | } |
128 | } |
129 | |
130 | void MorphLayoutCommand::undo() |
131 | { |
132 | m_layoutCommand->undo(); |
133 | m_breakLayoutCommand->undo(); |
134 | } |
135 | |
136 | QString MorphLayoutCommand::formatDescription(QDesignerFormEditorInterface * /* core*/, const QWidget *w, int oldType, int newType) |
137 | { |
138 | const QString oldName = LayoutInfo::layoutName(t: static_cast<LayoutInfo::Type>(oldType)); |
139 | const QString newName = LayoutInfo::layoutName(t: static_cast<LayoutInfo::Type>(newType)); |
140 | const QString widgetName = qobject_cast<const QLayoutWidget*>(object: w) ? w->layout()->objectName() : w->objectName(); |
141 | return QApplication::translate(context: "Command" , key: "Change layout of '%1' from %2 to %3" ).arg(a1: widgetName, a2: oldName, a3: newName); |
142 | } |
143 | |
144 | LayoutAlignmentCommand::LayoutAlignmentCommand(QDesignerFormWindowInterface *formWindow) : |
145 | QDesignerFormWindowCommand(QApplication::translate(context: "Command" , key: "Change layout alignment" ), formWindow), |
146 | m_widget(nullptr) |
147 | { |
148 | } |
149 | |
150 | bool LayoutAlignmentCommand::init(QWidget *w, Qt::Alignment alignment) |
151 | { |
152 | bool enabled; |
153 | m_newAlignment = alignment; |
154 | m_oldAlignment = LayoutAlignmentCommand::alignmentOf(core: core(), w, enabled: &enabled); |
155 | m_widget = w; |
156 | return enabled; |
157 | } |
158 | |
159 | void LayoutAlignmentCommand::redo() |
160 | { |
161 | LayoutAlignmentCommand::applyAlignment(core: core(), w: m_widget, a: m_newAlignment); |
162 | } |
163 | |
164 | void LayoutAlignmentCommand::undo() |
165 | { |
166 | LayoutAlignmentCommand::applyAlignment(core: core(), w: m_widget, a: m_oldAlignment); |
167 | } |
168 | |
169 | // Find out alignment and return whether command is enabled. |
170 | Qt::Alignment LayoutAlignmentCommand::alignmentOf(const QDesignerFormEditorInterface *core, QWidget *w, bool *enabledIn) |
171 | { |
172 | bool managed; |
173 | QLayout *layout; |
174 | |
175 | if (enabledIn) |
176 | *enabledIn = false; |
177 | // Can only work on a managed layout |
178 | const LayoutInfo::Type type = LayoutInfo::laidoutWidgetType(core, widget: w, isManaged: &managed, layout: &layout); |
179 | const bool enabled = layout && managed && |
180 | (type == LayoutInfo::HBox || type == LayoutInfo::VBox |
181 | || type == LayoutInfo::Grid); |
182 | if (!enabled) |
183 | return {}; |
184 | // Get alignment |
185 | const int index = layout->indexOf(w); |
186 | Q_ASSERT(index >= 0); |
187 | if (enabledIn) |
188 | *enabledIn = true; |
189 | return layout->itemAt(index)->alignment(); |
190 | } |
191 | |
192 | void LayoutAlignmentCommand::applyAlignment(const QDesignerFormEditorInterface *core, QWidget *w, Qt::Alignment a) |
193 | { |
194 | // Find layout and apply to item |
195 | QLayout *layout; |
196 | LayoutInfo::laidoutWidgetType(core, widget: w, isManaged: nullptr, layout: &layout); |
197 | if (layout) { |
198 | const int index = layout->indexOf(w); |
199 | if (index >= 0) { |
200 | layout->itemAt(index)->setAlignment(a); |
201 | layout->update(); |
202 | } |
203 | } |
204 | } |
205 | |
206 | } // namespace qdesigner_internal |
207 | |
208 | QT_END_NAMESPACE |
209 | |