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