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 QtWidgets module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
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 Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 3 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL3 included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 3 requirements
23 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24 **
25 ** GNU General Public License Usage
26 ** Alternatively, this file may be used under the terms of the GNU
27 ** General Public License version 2.0 or (at your option) the GNU General
28 ** Public license version 3 or any later version approved by the KDE Free
29 ** Qt Foundation. The licenses are as published by the Free Software
30 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31 ** included in the packaging of this file. Please review the following
32 ** information to ensure the GNU General Public License requirements will
33 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34 ** https://www.gnu.org/licenses/gpl-3.0.html.
35 **
36 ** $QT_END_LICENSE$
37 **
38 ****************************************************************************/
39 
40 #ifndef QMDIAREA_P_H
41 #define QMDIAREA_P_H
42 
43 //
44 //  W A R N I N G
45 //  -------------
46 //
47 // This file is not part of the Qt API.  It exists purely as an
48 // implementation detail.  This header file may change from version to
49 // version without notice, or even be removed.
50 //
51 // We mean it.
52 //
53 
54 #include <QtWidgets/private/qtwidgetsglobal_p.h>
55 #include "qmdiarea.h"
56 #include "qmdisubwindow.h"
57 
58 QT_REQUIRE_CONFIG(mdiarea);
59 
60 #include <QList>
61 #include <QVector>
62 #include <QRect>
63 #include <QPoint>
64 #include <QtWidgets/qapplication.h>
65 #include <private/qmdisubwindow_p.h>
66 #include <private/qabstractscrollarea_p.h>
67 
68 QT_BEGIN_NAMESPACE
69 
70 namespace QMdi {
71 class Rearranger
72 {
73 public:
74     enum Type {
75         RegularTiler,
76         SimpleCascader,
77         IconTiler
78     };
79 
80     // Rearranges widgets relative to domain.
81     virtual void rearrange(QList<QWidget *> &widgets, const QRect &domain) const = 0;
82     virtual Type type() const = 0;
~Rearranger()83     virtual ~Rearranger() {}
84 };
85 
86 class RegularTiler : public Rearranger
87 {
88     // Rearranges widgets according to a regular tiling pattern
89     // covering the entire domain.
90     // Both positions and sizes may change.
91     void rearrange(QList<QWidget *> &widgets, const QRect &domain) const override;
type()92     Type type() const override { return Rearranger::RegularTiler; }
93 };
94 
95 class SimpleCascader : public Rearranger
96 {
97     // Rearranges widgets according to a simple, regular cascading pattern.
98     // Widgets are resized to minimumSize.
99     // Both positions and sizes may change.
100     void rearrange(QList<QWidget *> &widgets, const QRect &domain) const override;
type()101     Type type() const override { return Rearranger::SimpleCascader; }
102 };
103 
104 class IconTiler : public Rearranger
105 {
106     // Rearranges icons (assumed to be the same size) according to a regular
107     // tiling pattern filling up the domain from the bottom.
108     // Only positions may change.
109     void rearrange(QList<QWidget *> &widgets, const QRect &domain) const override;
type()110     Type type() const override { return Rearranger::IconTiler; }
111 };
112 
113 class Placer
114 {
115 public:
116     // Places the rectangle defined by 'size' relative to 'rects' and 'domain'.
117     // Returns the position of the resulting rectangle.
118     virtual QPoint place(
119         const QSize &size, const QVector<QRect> &rects, const QRect &domain) const = 0;
~Placer()120     virtual ~Placer() {}
121 };
122 
123 class MinOverlapPlacer : public Placer
124 {
125     QPoint place(const QSize &size, const QVector<QRect> &rects, const QRect &domain) const override;
126     static int accumulatedOverlap(const QRect &source, const QVector<QRect> &rects);
127     static QRect findMinOverlapRect(const QVector<QRect> &source, const QVector<QRect> &rects);
128     static QVector<QRect> getCandidatePlacements(const QSize &size, const QVector<QRect> &rects, const QRect &domain);
129     static QPoint findBestPlacement(const QRect &domain, const QVector<QRect> &rects, QVector<QRect> &source);
130     static QVector<QRect> findNonInsiders(const QRect &domain, QVector<QRect> &source);
131     static QVector<QRect> findMaxOverlappers(const QRect &domain, const QVector<QRect> &source);
132 };
133 } // namespace QMdi
134 
135 class QMdiAreaTabBar;
136 class QMdiAreaPrivate : public QAbstractScrollAreaPrivate
137 {
138     Q_DECLARE_PUBLIC(QMdiArea)
139 public:
140     QMdiAreaPrivate();
141 
142     // Variables.
143     QMdi::Rearranger *cascader;
144     QMdi::Rearranger *regularTiler;
145     QMdi::Rearranger *iconTiler;
146     QMdi::Placer *placer;
147 #if QT_CONFIG(rubberband)
148     QRubberBand *rubberBand;
149 #endif
150     QMdiAreaTabBar *tabBar;
151     QList<QMdi::Rearranger *> pendingRearrangements;
152     QVector< QPointer<QMdiSubWindow> > pendingPlacements;
153     QVector< QPointer<QMdiSubWindow> > childWindows;
154     QVector<int> indicesToActivatedChildren;
155     QPointer<QMdiSubWindow> active;
156     QPointer<QMdiSubWindow> aboutToBecomeActive;
157     QBrush background;
158     QMdiArea::WindowOrder activationOrder;
159     QMdiArea::AreaOptions options;
160     QMdiArea::ViewMode viewMode;
161 #if QT_CONFIG(tabbar)
162     bool documentMode;
163     bool tabsClosable;
164     bool tabsMovable;
165 #endif
166 #if QT_CONFIG(tabwidget)
167     QTabWidget::TabShape tabShape;
168     QTabWidget::TabPosition tabPosition;
169 #endif
170     bool ignoreGeometryChange;
171     bool ignoreWindowStateChange;
172     bool isActivated;
173     bool isSubWindowsTiled;
174     bool showActiveWindowMaximized;
175     bool tileCalledFromResizeEvent;
176     bool updatesDisabledByUs;
177     bool inViewModeChange;
178     int indexToNextWindow;
179     int indexToPreviousWindow;
180     int indexToHighlighted;
181     int indexToLastActiveTab;
182     int resizeTimerId;
183     int tabToPreviousTimerId;
184 
185     // Slots.
186     void _q_deactivateAllWindows(QMdiSubWindow *aboutToActivate = nullptr);
187     void _q_processWindowStateChanged(Qt::WindowStates oldState, Qt::WindowStates newState);
188     void _q_currentTabChanged(int index);
189     void _q_closeTab(int index);
190     void _q_moveTab(int from, int to);
191 
192     // Functions.
193     void appendChild(QMdiSubWindow *child);
194     void place(QMdi::Placer *placer, QMdiSubWindow *child);
195     void rearrange(QMdi::Rearranger *rearranger);
196     void arrangeMinimizedSubWindows();
197     void activateWindow(QMdiSubWindow *child);
198     void activateCurrentWindow();
199     void activateHighlightedWindow();
200     void emitWindowActivated(QMdiSubWindow *child);
201     void resetActiveWindow(QMdiSubWindow *child = nullptr);
202     void updateActiveWindow(int removedIndex, bool activeRemoved);
203     void updateScrollBars();
204     void internalRaise(QMdiSubWindow *child) const;
205     bool scrollBarsEnabled() const;
206     bool lastWindowAboutToBeDestroyed() const;
207     void setChildActivationEnabled(bool enable = true, bool onlyNextActivationEvent = false) const;
208     QRect resizeToMinimumTileSize(const QSize &minSubWindowSize, int subWindowCount);
209     void scrollBarPolicyChanged(Qt::Orientation, Qt::ScrollBarPolicy) override; // reimp
210     QMdiSubWindow *nextVisibleSubWindow(int increaseFactor, QMdiArea::WindowOrder,
211                                         int removed = -1, int fromIndex = -1) const;
212     void highlightNextSubWindow(int increaseFactor);
213     QList<QMdiSubWindow *> subWindowList(QMdiArea::WindowOrder, bool reversed = false) const;
214     void disconnectSubWindow(QObject *subWindow);
215     void setViewMode(QMdiArea::ViewMode mode);
216 #if QT_CONFIG(tabbar)
217     void updateTabBarGeometry();
218     void refreshTabBar();
219 #endif
220 
startResizeTimer()221     inline void startResizeTimer()
222     {
223         Q_Q(QMdiArea);
224         if (resizeTimerId > 0)
225             q->killTimer(resizeTimerId);
226         resizeTimerId = q->startTimer(200);
227     }
228 
startTabToPreviousTimer()229     inline void startTabToPreviousTimer()
230     {
231         Q_Q(QMdiArea);
232         if (tabToPreviousTimerId > 0)
233             q->killTimer(tabToPreviousTimerId);
234         tabToPreviousTimerId = q->startTimer(QApplication::keyboardInputInterval());
235     }
236 
windowStaysOnTop(QMdiSubWindow * subWindow)237     inline bool windowStaysOnTop(QMdiSubWindow *subWindow) const
238     {
239         if (!subWindow)
240             return false;
241         return subWindow->windowFlags() & Qt::WindowStaysOnTopHint;
242     }
243 
isExplicitlyDeactivated(QMdiSubWindow * subWindow)244     inline bool isExplicitlyDeactivated(QMdiSubWindow *subWindow) const
245     {
246         if (!subWindow)
247             return true;
248         return subWindow->d_func()->isExplicitlyDeactivated;
249     }
250 
251     inline void setActive(QMdiSubWindow *subWindow, bool active = true, bool changeFocus = true) const
252     {
253         if (subWindow)
254             subWindow->d_func()->setActive(active, changeFocus);
255     }
256 
257 #if QT_CONFIG(rubberband)
258     void showRubberBandFor(QMdiSubWindow *subWindow);
259 
hideRubberBand()260     inline void hideRubberBand()
261     {
262         if (rubberBand && rubberBand->isVisible())
263             rubberBand->hide();
264         indexToHighlighted = -1;
265     }
266 #endif // QT_CONFIG(rubberband)
267 };
268 
269 QT_END_NAMESPACE
270 
271 #endif // QMDIAREA_P_H
272