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 "qmdiarea_container.h" |
30 | |
31 | #include <QtDesigner/qextensionmanager.h> |
32 | #include <QtDesigner/abstractformeditor.h> |
33 | |
34 | #include <QtWidgets/qmdiarea.h> |
35 | #include <QtWidgets/qmdisubwindow.h> |
36 | #include <QtWidgets/qapplication.h> |
37 | #include <QtCore/qdebug.h> |
38 | #include <QtCore/qhash.h> |
39 | |
40 | QT_BEGIN_NAMESPACE |
41 | |
42 | namespace qdesigner_internal { |
43 | |
44 | QMdiAreaContainer::QMdiAreaContainer(QMdiArea *widget, QObject *parent) |
45 | : QObject(parent), |
46 | m_mdiArea(widget) |
47 | { |
48 | } |
49 | |
50 | int QMdiAreaContainer::count() const |
51 | { |
52 | return m_mdiArea->subWindowList(order: QMdiArea::CreationOrder).count(); |
53 | } |
54 | |
55 | QWidget *QMdiAreaContainer::widget(int index) const |
56 | { |
57 | if (index < 0) |
58 | return nullptr; |
59 | return m_mdiArea->subWindowList(order: QMdiArea::CreationOrder).at(i: index)->widget(); |
60 | } |
61 | |
62 | int QMdiAreaContainer::currentIndex() const |
63 | { |
64 | if (QMdiSubWindow *sub = m_mdiArea->activeSubWindow()) |
65 | return m_mdiArea->subWindowList(order: QMdiArea::CreationOrder).indexOf(t: sub); |
66 | return -1; |
67 | } |
68 | |
69 | void QMdiAreaContainer::setCurrentIndex(int index) |
70 | { |
71 | if (index < 0) { |
72 | qDebug() << "** WARNING Attempt to QMdiAreaContainer::setCurrentIndex(-1)" ; |
73 | return; |
74 | } |
75 | QMdiSubWindow *frame = m_mdiArea->subWindowList(order: QMdiArea::CreationOrder).at(i: index); |
76 | m_mdiArea->setActiveSubWindow(frame); |
77 | } |
78 | |
79 | void QMdiAreaContainer::addWidget(QWidget *widget) |
80 | { |
81 | QMdiSubWindow *frame = m_mdiArea->addSubWindow(widget, flags: Qt::Window); |
82 | frame->show(); |
83 | m_mdiArea->cascadeSubWindows(); |
84 | positionNewMdiChild(area: m_mdiArea, mdiChild: frame); |
85 | } |
86 | |
87 | // Semi-smart positioning of new windows: Make child fill the whole MDI window below |
88 | // cascaded other windows |
89 | void QMdiAreaContainer::positionNewMdiChild(const QWidget *area, QWidget *mdiChild) |
90 | { |
91 | enum { MinSize = 20 }; |
92 | const QPoint pos = mdiChild->pos(); |
93 | const QSize areaSize = area->size(); |
94 | switch (QApplication::layoutDirection()) { |
95 | case Qt::LayoutDirectionAuto: |
96 | case Qt::LeftToRight: { |
97 | const QSize fullSize = QSize(areaSize.width() - pos.x(), areaSize.height() - pos.y()); |
98 | if (fullSize.width() > MinSize && fullSize.height() > MinSize) |
99 | mdiChild->resize(fullSize); |
100 | } |
101 | break; |
102 | case Qt::RightToLeft: { |
103 | const QSize fullSize = QSize(pos.x() + mdiChild->width(), areaSize.height() - pos.y()); |
104 | if (fullSize.width() > MinSize && fullSize.height() > MinSize) { |
105 | mdiChild->move(ax: 0, ay: pos.y()); |
106 | mdiChild->resize(fullSize); |
107 | } |
108 | } |
109 | break; |
110 | } |
111 | } |
112 | |
113 | void QMdiAreaContainer::insertWidget(int, QWidget *widget) |
114 | { |
115 | addWidget(widget); |
116 | } |
117 | |
118 | void QMdiAreaContainer::remove(int index) |
119 | { |
120 | auto subWins = m_mdiArea->subWindowList(order: QMdiArea::CreationOrder); |
121 | if (index >= 0 && index < subWins.size()) { |
122 | QMdiSubWindow *f = subWins.at(i: index); |
123 | m_mdiArea->removeSubWindow(widget: f->widget()); |
124 | delete f; |
125 | } |
126 | } |
127 | |
128 | // ---------- MdiAreaPropertySheet, creates fake properties: |
129 | // 1) window name (object name of child) |
130 | // 2) title (windowTitle of child). |
131 | |
132 | static const char *subWindowTitleC = "activeSubWindowTitle" ; |
133 | static const char *subWindowNameC = "activeSubWindowName" ; |
134 | |
135 | QMdiAreaPropertySheet::QMdiAreaPropertySheet(QWidget *mdiArea, QObject *parent) : |
136 | QDesignerPropertySheet(mdiArea, parent), |
137 | m_windowTitleProperty(QStringLiteral("windowTitle" )) |
138 | { |
139 | createFakeProperty(propertyName: QLatin1String(subWindowNameC), value: QString()); |
140 | createFakeProperty(propertyName: QLatin1String(subWindowTitleC), value: QString()); |
141 | } |
142 | |
143 | QMdiAreaPropertySheet::MdiAreaProperty QMdiAreaPropertySheet::mdiAreaProperty(const QString &name) |
144 | { |
145 | using MdiAreaPropertyHash = QHash<QString, MdiAreaProperty>; |
146 | static MdiAreaPropertyHash mdiAreaPropertyHash; |
147 | if (mdiAreaPropertyHash.isEmpty()) { |
148 | mdiAreaPropertyHash.insert(akey: QLatin1String(subWindowNameC), avalue: MdiAreaSubWindowName); |
149 | mdiAreaPropertyHash.insert(akey: QLatin1String(subWindowTitleC), avalue: MdiAreaSubWindowTitle); |
150 | } |
151 | return mdiAreaPropertyHash.value(akey: name,adefaultValue: MdiAreaNone); |
152 | } |
153 | |
154 | void QMdiAreaPropertySheet::setProperty(int index, const QVariant &value) |
155 | { |
156 | switch (mdiAreaProperty(name: propertyName(index))) { |
157 | case MdiAreaSubWindowName: |
158 | if (QWidget *w = currentWindow()) |
159 | w->setObjectName(value.toString()); |
160 | break; |
161 | case MdiAreaSubWindowTitle: // Forward to window title of subwindow |
162 | if (QDesignerPropertySheetExtension *cws = currentWindowSheet()) { |
163 | const int index = cws->indexOf(name: m_windowTitleProperty); |
164 | cws->setProperty(index, value); |
165 | cws->setChanged(index, changed: true); |
166 | } |
167 | break; |
168 | default: |
169 | QDesignerPropertySheet::setProperty(index, value); |
170 | break; |
171 | } |
172 | } |
173 | |
174 | bool QMdiAreaPropertySheet::reset(int index) |
175 | { |
176 | bool rc = true; |
177 | switch (mdiAreaProperty(name: propertyName(index))) { |
178 | case MdiAreaSubWindowName: |
179 | setProperty(index, value: QVariant(QString())); |
180 | setChanged(index, changed: false); |
181 | break; |
182 | case MdiAreaSubWindowTitle: // Forward to window title of subwindow |
183 | if (QDesignerPropertySheetExtension *cws = currentWindowSheet()) { |
184 | const int index = cws->indexOf(name: m_windowTitleProperty); |
185 | rc = cws->reset(index); |
186 | } |
187 | break; |
188 | default: |
189 | rc = QDesignerPropertySheet::reset(index); |
190 | break; |
191 | } |
192 | return rc; |
193 | } |
194 | |
195 | QVariant QMdiAreaPropertySheet::property(int index) const |
196 | { |
197 | switch (mdiAreaProperty(name: propertyName(index))) { |
198 | case MdiAreaSubWindowName: |
199 | if (QWidget *w = currentWindow()) |
200 | return w->objectName(); |
201 | return QVariant(QString()); |
202 | case MdiAreaSubWindowTitle: |
203 | if (QWidget *w = currentWindow()) |
204 | return w->windowTitle(); |
205 | return QVariant(QString()); |
206 | case MdiAreaNone: |
207 | break; |
208 | } |
209 | return QDesignerPropertySheet::property(index); |
210 | } |
211 | |
212 | bool QMdiAreaPropertySheet::isEnabled(int index) const |
213 | { |
214 | switch (mdiAreaProperty(name: propertyName(index))) { |
215 | case MdiAreaSubWindowName: |
216 | case MdiAreaSubWindowTitle: |
217 | return currentWindow() != nullptr; |
218 | case MdiAreaNone: |
219 | break; |
220 | } |
221 | return QDesignerPropertySheet::isEnabled(index); |
222 | } |
223 | |
224 | bool QMdiAreaPropertySheet::isChanged(int index) const |
225 | { |
226 | bool rc = false; |
227 | switch (mdiAreaProperty(name: propertyName(index))) { |
228 | case MdiAreaSubWindowName: |
229 | rc = currentWindow() != nullptr; |
230 | break; |
231 | case MdiAreaSubWindowTitle: |
232 | if (QDesignerPropertySheetExtension *cws = currentWindowSheet()) { |
233 | const int index = cws->indexOf(name: m_windowTitleProperty); |
234 | rc = cws->isChanged(index); |
235 | } |
236 | break; |
237 | default: |
238 | rc = QDesignerPropertySheet::isChanged(index); |
239 | break; |
240 | } |
241 | return rc; |
242 | } |
243 | |
244 | QWidget *QMdiAreaPropertySheet::currentWindow() const |
245 | { |
246 | if (const QDesignerContainerExtension *c = qt_extension<QDesignerContainerExtension*>(manager: core()->extensionManager(), object: object())) { |
247 | const int ci = c->currentIndex(); |
248 | if (ci < 0) |
249 | return nullptr; |
250 | return c->widget(index: ci); |
251 | } |
252 | return nullptr; |
253 | } |
254 | |
255 | QDesignerPropertySheetExtension *QMdiAreaPropertySheet::currentWindowSheet() const |
256 | { |
257 | QWidget *cw = currentWindow(); |
258 | if (cw == nullptr) |
259 | return nullptr; |
260 | return qt_extension<QDesignerPropertySheetExtension*>(manager: core()->extensionManager(), object: cw); |
261 | } |
262 | |
263 | bool QMdiAreaPropertySheet::checkProperty(const QString &propertyName) |
264 | { |
265 | return mdiAreaProperty(name: propertyName) == MdiAreaNone; |
266 | } |
267 | } |
268 | QT_END_NAMESPACE |
269 | |