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
MorphLayoutCommand(QDesignerFormWindowInterface * formWindow)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
~MorphLayoutCommand()55 MorphLayoutCommand::~MorphLayoutCommand()
56 {
57 delete m_layoutCommand;
58 delete m_breakLayoutCommand;
59 }
60
init(QWidget * w,int newType)61 bool MorphLayoutCommand::init(QWidget *w, int newType)
62 {
63 int oldType;
64 QDesignerFormWindowInterface *fw = formWindow();
65 if (!canMorph(fw, w, &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(fw->core(), w);
72 const int count = layout->count();
73 for (int i = 0; i < count ; i++) {
74 if (QWidget *w = layout->itemAt(i)->widget())
75 if (fw->isManaged(w))
76 m_widgets.push_back(w);
77 }
78 const bool reparentLayoutWidget = false; // leave QLayoutWidget intact
79 m_breakLayoutCommand->init(m_widgets, m_layoutBase, reparentLayoutWidget);
80 m_layoutCommand->init(m_layoutBase, m_widgets, static_cast<LayoutInfo::Type>(m_newType), m_layoutBase, reparentLayoutWidget);
81 setText(formatDescription(core(), m_layoutBase, oldType, newType));
82 return true;
83 }
84
canMorph(const QDesignerFormWindowInterface * formWindow,QWidget * w,int * ptrToCurrentType)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, 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
redo()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(), m_layoutBase);
123 const int newMask = LayoutProperties::visibleProperties(newLayout);
124 const int applicableMask = (oldMask & newMask) & ~LayoutProperties::ObjectNameProperty;
125 if (applicableMask)
126 properties->toPropertySheet(core(), newLayout, applicableMask);
127 }
128 }
129
undo()130 void MorphLayoutCommand::undo()
131 {
132 m_layoutCommand->undo();
133 m_breakLayoutCommand->undo();
134 }
135
formatDescription(QDesignerFormEditorInterface *,const QWidget * w,int oldType,int newType)136 QString MorphLayoutCommand::formatDescription(QDesignerFormEditorInterface * /* core*/, const QWidget *w, int oldType, int newType)
137 {
138 const QString oldName = LayoutInfo::layoutName(static_cast<LayoutInfo::Type>(oldType));
139 const QString newName = LayoutInfo::layoutName(static_cast<LayoutInfo::Type>(newType));
140 const QString widgetName = qobject_cast<const QLayoutWidget*>(w) ? w->layout()->objectName() : w->objectName();
141 return QApplication::translate("Command", "Change layout of '%1' from %2 to %3").arg(widgetName, oldName, newName);
142 }
143
LayoutAlignmentCommand(QDesignerFormWindowInterface * formWindow)144 LayoutAlignmentCommand::LayoutAlignmentCommand(QDesignerFormWindowInterface *formWindow) :
145 QDesignerFormWindowCommand(QApplication::translate("Command", "Change layout alignment"), formWindow),
146 m_widget(nullptr)
147 {
148 }
149
init(QWidget * w,Qt::Alignment alignment)150 bool LayoutAlignmentCommand::init(QWidget *w, Qt::Alignment alignment)
151 {
152 bool enabled;
153 m_newAlignment = alignment;
154 m_oldAlignment = LayoutAlignmentCommand::alignmentOf(core(), w, &enabled);
155 m_widget = w;
156 return enabled;
157 }
158
redo()159 void LayoutAlignmentCommand::redo()
160 {
161 LayoutAlignmentCommand::applyAlignment(core(), m_widget, m_newAlignment);
162 }
163
undo()164 void LayoutAlignmentCommand::undo()
165 {
166 LayoutAlignmentCommand::applyAlignment(core(), m_widget, m_oldAlignment);
167 }
168
169 // Find out alignment and return whether command is enabled.
alignmentOf(const QDesignerFormEditorInterface * core,QWidget * w,bool * enabledIn)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, w, &managed, &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
applyAlignment(const QDesignerFormEditorInterface * core,QWidget * w,Qt::Alignment a)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, w, nullptr, &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