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 
QMdiAreaContainer(QMdiArea * widget,QObject * parent)44 QMdiAreaContainer::QMdiAreaContainer(QMdiArea *widget, QObject *parent)
45     : QObject(parent),
46       m_mdiArea(widget)
47 {
48 }
49 
count() const50 int QMdiAreaContainer::count() const
51 {
52     return m_mdiArea->subWindowList(QMdiArea::CreationOrder).count();
53 }
54 
widget(int index) const55 QWidget *QMdiAreaContainer::widget(int index) const
56 {
57     if (index < 0)
58         return nullptr;
59     return m_mdiArea->subWindowList(QMdiArea::CreationOrder).at(index)->widget();
60 }
61 
currentIndex() const62 int QMdiAreaContainer::currentIndex() const
63 {
64     if (QMdiSubWindow *sub = m_mdiArea->activeSubWindow())
65         return m_mdiArea->subWindowList(QMdiArea::CreationOrder).indexOf(sub);
66     return -1;
67 }
68 
setCurrentIndex(int index)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(QMdiArea::CreationOrder).at(index);
76     m_mdiArea->setActiveSubWindow(frame);
77 }
78 
addWidget(QWidget * widget)79 void QMdiAreaContainer::addWidget(QWidget *widget)
80 {
81     QMdiSubWindow *frame = m_mdiArea->addSubWindow(widget, Qt::Window);
82     frame->show();
83     m_mdiArea->cascadeSubWindows();
84     positionNewMdiChild(m_mdiArea, frame);
85 }
86 
87 // Semi-smart positioning of new windows: Make child fill the whole MDI window below
88 // cascaded other windows
positionNewMdiChild(const QWidget * area,QWidget * mdiChild)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(0, pos.y());
106             mdiChild->resize(fullSize);
107         }
108     }
109         break;
110     }
111 }
112 
insertWidget(int,QWidget * widget)113 void QMdiAreaContainer::insertWidget(int, QWidget *widget)
114 {
115     addWidget(widget);
116 }
117 
remove(int index)118 void QMdiAreaContainer::remove(int index)
119 {
120     auto subWins = m_mdiArea->subWindowList(QMdiArea::CreationOrder);
121     if (index >= 0 && index < subWins.size()) {
122         QMdiSubWindow *f = subWins.at(index);
123         m_mdiArea->removeSubWindow(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 
QMdiAreaPropertySheet(QWidget * mdiArea,QObject * parent)135 QMdiAreaPropertySheet::QMdiAreaPropertySheet(QWidget *mdiArea, QObject *parent) :
136     QDesignerPropertySheet(mdiArea, parent),
137     m_windowTitleProperty(QStringLiteral("windowTitle"))
138 {
139     createFakeProperty(QLatin1String(subWindowNameC), QString());
140     createFakeProperty(QLatin1String(subWindowTitleC), QString());
141 }
142 
mdiAreaProperty(const QString & name)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(QLatin1String(subWindowNameC), MdiAreaSubWindowName);
149         mdiAreaPropertyHash.insert(QLatin1String(subWindowTitleC), MdiAreaSubWindowTitle);
150     }
151     return mdiAreaPropertyHash.value(name,MdiAreaNone);
152 }
153 
setProperty(int index,const QVariant & value)154 void QMdiAreaPropertySheet::setProperty(int index, const QVariant &value)
155 {
156     switch (mdiAreaProperty(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(m_windowTitleProperty);
164             cws->setProperty(index, value);
165             cws->setChanged(index, true);
166         }
167         break;
168     default:
169         QDesignerPropertySheet::setProperty(index, value);
170         break;
171     }
172 }
173 
reset(int index)174 bool QMdiAreaPropertySheet::reset(int index)
175 {
176     bool rc = true;
177     switch (mdiAreaProperty(propertyName(index))) {
178     case MdiAreaSubWindowName:
179         setProperty(index, QVariant(QString()));
180         setChanged(index, false);
181         break;
182     case MdiAreaSubWindowTitle:        // Forward to window title of subwindow
183         if (QDesignerPropertySheetExtension *cws = currentWindowSheet()) {
184             const int index = cws->indexOf(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 
property(int index) const195 QVariant QMdiAreaPropertySheet::property(int index) const
196 {
197     switch (mdiAreaProperty(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 
isEnabled(int index) const212 bool QMdiAreaPropertySheet::isEnabled(int index) const
213 {
214     switch (mdiAreaProperty(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 
isChanged(int index) const224 bool QMdiAreaPropertySheet::isChanged(int index) const
225 {
226     bool rc = false;
227     switch (mdiAreaProperty(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(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 
currentWindow() const244 QWidget *QMdiAreaPropertySheet::currentWindow() const
245 {
246     if (const QDesignerContainerExtension *c = qt_extension<QDesignerContainerExtension*>(core()->extensionManager(), object())) {
247         const int ci = c->currentIndex();
248         if (ci < 0)
249             return nullptr;
250         return c->widget(ci);
251     }
252     return nullptr;
253 }
254 
currentWindowSheet() const255 QDesignerPropertySheetExtension *QMdiAreaPropertySheet::currentWindowSheet() const
256 {
257     QWidget *cw = currentWindow();
258     if (cw == nullptr)
259         return nullptr;
260     return qt_extension<QDesignerPropertySheetExtension*>(core()->extensionManager(), cw);
261 }
262 
checkProperty(const QString & propertyName)263 bool QMdiAreaPropertySheet::checkProperty(const QString &propertyName)
264 {
265     return mdiAreaProperty(propertyName) == MdiAreaNone;
266 }
267 }
268 QT_END_NAMESPACE
269