source: trunk/src/gui/widgets/qmdisubwindow.cpp@ 5

Last change on this file since 5 was 2, checked in by Dmitry A. Kuminov, 16 years ago

Initially imported qt-all-opensource-src-4.5.1 from Trolltech.

File size: 107.3 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4** Contact: Qt Software Information (qt-info@nokia.com)
5**
6** This file is part of the QtGui module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial Usage
10** Licensees holding valid Qt Commercial licenses may use this file in
11** accordance with the Qt Commercial License Agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and Nokia.
14**
15** GNU Lesser General Public License Usage
16** Alternatively, this file may be used under the terms of the GNU Lesser
17** General Public License version 2.1 as published by the Free Software
18** Foundation and appearing in the file LICENSE.LGPL included in the
19** packaging of this file. Please review the following information to
20** ensure the GNU Lesser General Public License version 2.1 requirements
21** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
22**
23** In addition, as a special exception, Nokia gives you certain
24** additional rights. These rights are described in the Nokia Qt LGPL
25** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
26** package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you are unsure which license is appropriate for your use, please
37** contact the sales department at qt-sales@nokia.com.
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42/*!
43 \class QMdiSubWindow
44 \brief The QMdiSubWindow class provides a subwindow class for
45 QMdiArea.
46 \since 4.3
47 \ingroup application
48 \mainclass
49
50 QMdiSubWindow represents a top-level window in a QMdiArea, and consists
51 of a title bar with window decorations, an internal widget, and
52 (depending on the current style) a window frame and a size
53 grip. QMdiSubWindow has its own layout, which consists of the
54 title bar and a center area for the internal widget.
55
56 \image qmdisubwindowlayout.png
57
58 The most common way to construct a QMdiSubWindow is to call
59 QMdiArea::addSubWindow() with the internal widget as the argument.
60 You can also create a subwindow yourself, and set an internal
61 widget by calling setWidget().
62
63 You use the same API when programming with subwindows as with
64 regular top-level windows (e.g., you can call functions such as
65 show(), hide(), showMaximized(), and setWindowTitle()).
66
67 \section1 Subwindow Handling
68
69 QMdiSubWindow also supports behavior specific to subwindows in
70 an MDI area.
71
72 By default, each QMdiSubWindow is visible inside the MDI area
73 viewport when moved around, but it is also possible to specify
74 transparent window movement and resizing behavior, where only
75 the outline of a subwindow is updated during these operations.
76 The setOption() function is used to enable this behavior.
77
78 The isShaded() function detects whether the subwindow is
79 currently shaded (i.e., the window is collapsed so that only the
80 title bar is visible). To enter shaded mode, call showShaded().
81 QMdiSubWindow emits the windowStateChanged() signal whenever the
82 window state has changed (e.g., when the window becomes minimized,
83 or is restored). It also emits aboutToActivate() before it is
84 activated.
85
86 In keyboard-interactive mode, the windows are moved and resized
87 with the keyboard. You can enter this mode through the system menu
88 of the window. The keyboardSingleStep and keyboardPageStep
89 properties control the distance the widget is moved or resized for
90 each keypress event. When shift is pressed down page step is used;
91 otherwise single step is used.
92
93 You can also change the active window with the keyboard. By
94 pressing the control and tab keys at the same time, the next
95 (using the current \l{QMdiArea::}{WindowOrder}) subwindow will be
96 activated. By pressing control, shift, and tab, you will activate
97 the previous window. This is equivalent to calling
98 \l{QMdiArea::}{activateNextSubWindow()} and
99 \l{QMdiArea::}{activatePreviousSubWindow()}. Note that these
100 shortcuts overrides global shortcuts, but not the \l{QMdiArea}s
101 shortcuts.
102
103 \sa QMdiArea
104*/
105
106/*!
107 \enum QMdiSubWindow::SubWindowOption
108
109 This enum describes options that customize the behavior
110 of QMdiSubWindow.
111
112 \omitvalue AllowOutsideAreaHorizontally
113 \omitvalue AllowOutsideAreaVertically
114
115 \value RubberBandResize If you enable this option, a rubber band
116 control is used to represent the subwindow's outline, and the user
117 resizes this instead of the subwindow itself.
118 As a result, the subwindow maintains its original position and size
119 until the resize operation has been completed, at which time it will
120 receive a single QResizeEvent.
121 By default, this option is disabled.
122
123 \value RubberBandMove If you enable this option, a rubber band
124 control is used to represent the subwindow's outline, and the user
125 moves this instead of the subwindow itself.
126 As a result, the subwindow remains in its original position until
127 the move operation has completed, at which time a QMoveEvent is
128 sent to the window. By default, this option is disabled.
129*/
130
131/*!
132 \fn QMdiSubWindow::windowStateChanged(Qt::WindowStates oldState, Qt::WindowStates newState)
133
134 QMdiSubWindow emits this signal after the window state changes. \a
135 oldState is the window state before it changed, and \a newState is the
136 new, current state.
137*/
138
139/*!
140 \fn QMdiSubWindow::aboutToActivate()
141
142 QMdiSubWindow emits this signal immediately before it is
143 activated. After the subwindow has been activated, the QMdiArea that
144 manages the subwindow will also emit the
145 \l{QMdiArea::}{subWindowActivated()} signal.
146
147 \sa QMdiArea::subWindowActivated()
148*/
149
150#include "qmdisubwindow_p.h"
151
152#ifndef QT_NO_MDIAREA
153
154#include <QApplication>
155#include <QStylePainter>
156#include <QVBoxLayout>
157#include <QMouseEvent>
158#include <QWhatsThis>
159#include <QToolTip>
160#include <QMainWindow>
161#include <QScrollBar>
162#include <QDebug>
163#if defined(Q_WS_MAC) && !defined(QT_NO_STYLE_MAC)
164#include <QMacStyle>
165#endif
166#include <QMdiArea>
167
168QT_BEGIN_NAMESPACE
169
170using namespace QMdi;
171
172static const QStyle::SubControl SubControls[] =
173{
174 QStyle::SC_TitleBarLabel, // 1
175 QStyle::SC_TitleBarSysMenu, // 2
176 QStyle::SC_TitleBarMinButton, // 3
177 QStyle::SC_TitleBarMaxButton, // 4
178 QStyle::SC_TitleBarShadeButton, // 5
179 QStyle::SC_TitleBarCloseButton, // 6
180 QStyle::SC_TitleBarNormalButton, // 7
181 QStyle::SC_TitleBarUnshadeButton, // 8
182 QStyle::SC_TitleBarContextHelpButton // 9
183};
184static const int NumSubControls = sizeof(SubControls) / sizeof(SubControls[0]);
185
186static const QStyle::StandardPixmap ButtonPixmaps[] =
187{
188 QStyle::SP_TitleBarMinButton,
189 QStyle::SP_TitleBarNormalButton,
190 QStyle::SP_TitleBarCloseButton
191};
192static const int NumButtonPixmaps = sizeof(ButtonPixmaps) / sizeof(ButtonPixmaps[0]);
193
194static const Qt::WindowFlags CustomizeWindowFlags =
195 Qt::FramelessWindowHint
196 | Qt::CustomizeWindowHint
197 | Qt::WindowTitleHint
198 | Qt::WindowSystemMenuHint
199 | Qt::WindowMinimizeButtonHint
200 | Qt::WindowMaximizeButtonHint
201 | Qt::WindowMinMaxButtonsHint;
202
203
204static const int BoundaryMargin = 5;
205
206static inline int getMoveDeltaComponent(uint cflags, uint moveFlag, uint resizeFlag,
207 int delta, int maxDelta, int minDelta)
208{
209 if (cflags & moveFlag) {
210 if (delta > 0)
211 return (cflags & resizeFlag) ? qMin(delta, maxDelta) : delta;
212 return (cflags & resizeFlag) ? qMax(delta, minDelta) : delta;
213 }
214 return 0;
215}
216
217static inline int getResizeDeltaComponent(uint cflags, uint resizeFlag,
218 uint resizeReverseFlag, int delta)
219{
220 if (cflags & resizeFlag) {
221 if (cflags & resizeReverseFlag)
222 return -delta;
223 return delta;
224 }
225 return 0;
226}
227
228static inline bool isChildOfQMdiSubWindow(const QWidget *child)
229{
230 Q_ASSERT(child);
231 QWidget *parent = child->parentWidget();
232 while (parent) {
233 if (qobject_cast<QMdiSubWindow *>(parent))
234 return true;
235 parent = parent->parentWidget();
236 }
237 return false;
238}
239
240static inline bool isChildOfTabbedQMdiArea(const QMdiSubWindow *child)
241{
242 Q_ASSERT(child);
243 if (QMdiArea *mdiArea = child->mdiArea()) {
244 if (mdiArea->viewMode() == QMdiArea::TabbedView)
245 return true;
246 }
247 return false;
248}
249
250template<typename T>
251static inline ControlElement<T> *ptr(QWidget *widget)
252{
253 if (widget && widget->qt_metacast("ControlElement")
254 && strcmp(widget->metaObject()->className(), T::staticMetaObject.className()) == 0) {
255 return static_cast<ControlElement<T> *>(widget);
256 }
257 return 0;
258}
259
260QString QMdiSubWindowPrivate::originalWindowTitle()
261{
262 Q_Q(QMdiSubWindow);
263 if (originalTitle.isNull()) {
264 originalTitle = q->window()->windowTitle();
265 if (originalTitle.isNull())
266 originalTitle = QLatin1String("");
267 }
268 return originalTitle;
269}
270
271void QMdiSubWindowPrivate::setNewWindowTitle()
272{
273 Q_Q(QMdiSubWindow);
274 QString childTitle = q->windowTitle();
275 if (childTitle.isEmpty())
276 return;
277 QString original = originalWindowTitle();
278 if (!original.isEmpty()) {
279 if (!original.contains(QMdiSubWindow::tr("- [%1]").arg(childTitle)))
280 q->window()->setWindowTitle(QMdiSubWindow::tr("%1 - [%2]").arg(original, childTitle));
281
282 } else {
283 q->window()->setWindowTitle(childTitle);
284 }
285}
286
287static inline bool isHoverControl(QStyle::SubControl control)
288{
289 return control != QStyle::SC_None && control != QStyle::SC_TitleBarLabel;
290}
291
292#if defined(Q_WS_WIN)
293static inline QRgb colorref2qrgb(COLORREF col)
294{
295 return qRgb(GetRValue(col),GetGValue(col),GetBValue(col));
296}
297#endif
298
299#ifndef QT_NO_TOOLTIP
300static void showToolTip(QHelpEvent *helpEvent, QWidget *widget, const QStyleOptionComplex &opt,
301 QStyle::ComplexControl complexControl, QStyle::SubControl subControl)
302{
303 Q_ASSERT(helpEvent);
304 Q_ASSERT(helpEvent->type() == QEvent::ToolTip);
305 Q_ASSERT(widget);
306
307#if defined(Q_WS_MAC) && !defined(QT_NO_STYLE_MAC)
308 // Native Mac windows don't show tool tip.
309 if (qobject_cast<QMacStyle *>(widget->style()))
310 return;
311#endif
312
313 // Convert CC_MdiControls to CC_TitleBar. Sub controls of different complex
314 // controls cannot be in the same switch as they might have the same value.
315 if (complexControl == QStyle::CC_MdiControls) {
316 if (subControl == QStyle::SC_MdiMinButton)
317 subControl = QStyle::SC_TitleBarMinButton;
318 else if (subControl == QStyle::SC_MdiCloseButton)
319 subControl = QStyle::SC_TitleBarCloseButton;
320 else if (subControl == QStyle::SC_MdiNormalButton)
321 subControl = QStyle::SC_TitleBarNormalButton;
322 else
323 subControl = QStyle::SC_None;
324 }
325
326 // Don't change the tooltip for the base widget itself.
327 if (subControl == QStyle::SC_None)
328 return;
329
330 QString toolTip;
331
332 switch (subControl) {
333 case QStyle::SC_TitleBarMinButton:
334 toolTip = QMdiSubWindow::tr("Minimize");
335 break;
336 case QStyle::SC_TitleBarMaxButton:
337 toolTip = QMdiSubWindow::tr("Maximize");
338 break;
339 case QStyle::SC_TitleBarUnshadeButton:
340 toolTip = QMdiSubWindow::tr("Unshade");
341 break;
342 case QStyle::SC_TitleBarShadeButton:
343 toolTip = QMdiSubWindow::tr("Shade");
344 break;
345 case QStyle::SC_TitleBarNormalButton:
346 if (widget->isMaximized() || !qobject_cast<QMdiSubWindow *>(widget))
347 toolTip = QMdiSubWindow::tr("Restore Down");
348 else
349 toolTip = QMdiSubWindow::tr("Restore");
350 break;
351 case QStyle::SC_TitleBarCloseButton:
352 toolTip = QMdiSubWindow::tr("Close");
353 break;
354 case QStyle::SC_TitleBarContextHelpButton:
355 toolTip = QMdiSubWindow::tr("Help");
356 break;
357 case QStyle::SC_TitleBarSysMenu:
358 toolTip = QMdiSubWindow::tr("Menu");
359 break;
360 default:
361 break;
362 }
363
364 const QRect rect = widget->style()->subControlRect(complexControl, &opt, subControl, widget);
365 QToolTip::showText(helpEvent->globalPos(), toolTip, widget, rect);
366}
367#endif // QT_NO_TOOLTIP
368
369namespace QMdi {
370/*
371 \class ControlLabel
372 \internal
373*/
374class ControlLabel : public QWidget
375{
376 Q_OBJECT
377public:
378 ControlLabel(QMdiSubWindow *subWindow, QWidget *parent = 0);
379
380 QSize sizeHint() const;
381
382signals:
383 void _q_clicked();
384 void _q_doubleClicked();
385
386protected:
387 bool event(QEvent *event);
388 void paintEvent(QPaintEvent *paintEvent);
389 void mousePressEvent(QMouseEvent *mouseEvent);
390 void mouseDoubleClickEvent(QMouseEvent *mouseEvent);
391 void mouseReleaseEvent(QMouseEvent *mouseEvent);
392
393private:
394 QPixmap label;
395 bool isPressed;
396 void updateWindowIcon();
397};
398} // namespace QMdi
399
400ControlLabel::ControlLabel(QMdiSubWindow *subWindow, QWidget *parent)
401 : QWidget(parent), isPressed(false)
402{
403 Q_UNUSED(subWindow);
404 setFocusPolicy(Qt::NoFocus);
405 updateWindowIcon();
406 setFixedSize(label.size());
407}
408
409/*
410 \internal
411*/
412QSize ControlLabel::sizeHint() const
413{
414 return label.size();
415}
416
417/*
418 \internal
419*/
420bool ControlLabel::event(QEvent *event)
421{
422 if (event->type() == QEvent::WindowIconChange)
423 updateWindowIcon();
424#ifndef QT_NO_TOOLTIP
425 else if (event->type() == QEvent::ToolTip) {
426 QStyleOptionTitleBar options;
427 options.initFrom(this);
428 showToolTip(static_cast<QHelpEvent *>(event), this, options,
429 QStyle::CC_TitleBar, QStyle::SC_TitleBarSysMenu);
430 }
431#endif
432 return QWidget::event(event);
433}
434
435/*
436 \internal
437*/
438void ControlLabel::paintEvent(QPaintEvent * /*paintEvent*/)
439{
440 QPainter painter(this);
441 painter.drawPixmap(0, 0, label);
442}
443
444/*
445 \internal
446*/
447void ControlLabel::mousePressEvent(QMouseEvent *mouseEvent)
448{
449 if (mouseEvent->button() != Qt::LeftButton) {
450 mouseEvent->ignore();
451 return;
452 }
453 isPressed = true;
454}
455
456/*
457 \internal
458*/
459void ControlLabel::mouseDoubleClickEvent(QMouseEvent *mouseEvent)
460{
461 if (mouseEvent->button() != Qt::LeftButton) {
462 mouseEvent->ignore();
463 return;
464 }
465 isPressed = false;
466 emit _q_doubleClicked();
467}
468
469/*
470 \internal
471*/
472void ControlLabel::mouseReleaseEvent(QMouseEvent *mouseEvent)
473{
474 if (mouseEvent->button() != Qt::LeftButton) {
475 mouseEvent->ignore();
476 return;
477 }
478 if (isPressed) {
479 isPressed = false;
480 emit _q_clicked();
481 }
482}
483
484/*
485 \internal
486*/
487void ControlLabel::updateWindowIcon()
488{
489 QIcon menuIcon = windowIcon();
490 if (menuIcon.isNull())
491 menuIcon = style()->standardIcon(QStyle::SP_TitleBarMenuButton, 0, parentWidget());
492 label = menuIcon.pixmap(16, 16);
493 update();
494}
495
496namespace QMdi {
497/*
498 \class ControllerWidget
499 \internal
500*/
501class ControllerWidget : public QWidget
502{
503 Q_OBJECT
504public:
505 ControllerWidget(QMdiSubWindow *subWindow, QWidget *parent = 0);
506 QSize sizeHint() const;
507 void setControlVisible(QMdiSubWindowPrivate::WindowStateAction action, bool visible);
508 inline bool hasVisibleControls() const
509 {
510 return (visibleControls & QStyle::SC_MdiMinButton)
511 || (visibleControls & QStyle::SC_MdiNormalButton)
512 || (visibleControls & QStyle::SC_MdiCloseButton);
513 }
514
515signals:
516 void _q_minimize();
517 void _q_restore();
518 void _q_close();
519
520protected:
521 void paintEvent(QPaintEvent *event);
522 void mousePressEvent(QMouseEvent *event);
523 void mouseReleaseEvent(QMouseEvent *event);
524 void mouseMoveEvent(QMouseEvent *event);
525 void leaveEvent(QEvent *event);
526 bool event(QEvent *event);
527
528private:
529 QStyle::SubControl activeControl;
530 QStyle::SubControl hoverControl;
531 QStyle::SubControls visibleControls;
532 void initStyleOption(QStyleOptionComplex *option) const;
533 QMdiArea *mdiArea;
534 inline QStyle::SubControl getSubControl(const QPoint &pos) const
535 {
536 QStyleOptionComplex opt;
537 initStyleOption(&opt);
538 return style()->hitTestComplexControl(QStyle::CC_MdiControls, &opt, pos, mdiArea);
539 }
540};
541} // namespace QMdi
542
543/*
544 \internal
545*/
546ControllerWidget::ControllerWidget(QMdiSubWindow *subWindow, QWidget *parent)
547 : QWidget(parent),
548 activeControl(QStyle::SC_None),
549 hoverControl(QStyle::SC_None),
550 visibleControls(QStyle::SC_None),
551 mdiArea(0)
552{
553 if (subWindow->parentWidget())
554 mdiArea = qobject_cast<QMdiArea *>(subWindow->parentWidget()->parentWidget());
555 setFocusPolicy(Qt::NoFocus);
556 setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
557 setMouseTracking(true);
558}
559
560/*
561 \internal
562*/
563QSize ControllerWidget::sizeHint() const
564{
565 ensurePolished();
566 QStyleOptionComplex opt;
567 initStyleOption(&opt);
568 QSize size(48, 16);
569 return style()->sizeFromContents(QStyle::CT_MdiControls, &opt, size, mdiArea);
570}
571
572void ControllerWidget::setControlVisible(QMdiSubWindowPrivate::WindowStateAction action, bool visible)
573{
574 QStyle::SubControl subControl = QStyle::SC_None;
575
576 // Map action from QMdiSubWindowPrivate::WindowStateAction to QStyle::SubControl.
577 if (action == QMdiSubWindowPrivate::MaximizeAction)
578 subControl = QStyle::SC_MdiNormalButton;
579 else if (action == QMdiSubWindowPrivate::CloseAction)
580 subControl = QStyle::SC_MdiCloseButton;
581 else if (action == QMdiSubWindowPrivate::MinimizeAction)
582 subControl = QStyle::SC_MdiMinButton;
583
584 if (subControl == QStyle::SC_None)
585 return;
586
587 if (visible && !(visibleControls & subControl))
588 visibleControls |= subControl;
589 else if (!visible && (visibleControls & subControl))
590 visibleControls &= ~subControl;
591}
592
593/*
594 \internal
595*/
596void ControllerWidget::paintEvent(QPaintEvent * /*paintEvent*/)
597{
598 QStyleOptionComplex opt;
599 initStyleOption(&opt);
600 if (activeControl == hoverControl) {
601 opt.activeSubControls = activeControl;
602 opt.state |= QStyle::State_Sunken;
603 } else if (hoverControl != QStyle::SC_None && (activeControl == QStyle::SC_None)) {
604 opt.activeSubControls = hoverControl;
605 opt.state |= QStyle::State_MouseOver;
606 }
607 QPainter painter(this);
608 style()->drawComplexControl(QStyle::CC_MdiControls, &opt, &painter, mdiArea);
609}
610
611/*
612 \internal
613*/
614void ControllerWidget::mousePressEvent(QMouseEvent *event)
615{
616 if (event->button() != Qt::LeftButton) {
617 event->ignore();
618 return;
619 }
620 activeControl = getSubControl(event->pos());
621 update();
622}
623
624/*
625 \internal
626*/
627void ControllerWidget::mouseReleaseEvent(QMouseEvent *event)
628{
629 if (event->button() != Qt::LeftButton) {
630 event->ignore();
631 return;
632 }
633
634 QStyle::SubControl under_mouse = getSubControl(event->pos());
635 if (under_mouse == activeControl) {
636 switch (activeControl) {
637 case QStyle::SC_MdiCloseButton:
638 emit _q_close();
639 break;
640 case QStyle::SC_MdiNormalButton:
641 emit _q_restore();
642 break;
643 case QStyle::SC_MdiMinButton:
644 emit _q_minimize();
645 break;
646 default:
647 break;
648 }
649 }
650
651 activeControl = QStyle::SC_None;
652 update();
653}
654
655/*
656 \internal
657*/
658void ControllerWidget::mouseMoveEvent(QMouseEvent *event)
659{
660 QStyle::SubControl under_mouse = getSubControl(event->pos());
661 //test if hover state changes
662 if (hoverControl != under_mouse) {
663 hoverControl = under_mouse;
664 update();
665 }
666}
667
668/*
669 \internal
670*/
671void ControllerWidget::leaveEvent(QEvent * /*event*/)
672{
673 hoverControl = QStyle::SC_None;
674 update();
675}
676
677/*
678 \internal
679*/
680bool ControllerWidget::event(QEvent *event)
681{
682#ifndef QT_NO_TOOLTIP
683 if (event->type() == QEvent::ToolTip) {
684 QStyleOptionComplex opt;
685 initStyleOption(&opt);
686 QHelpEvent *helpEvent = static_cast<QHelpEvent *>(event);
687 showToolTip(helpEvent, this, opt, QStyle::CC_MdiControls, getSubControl(helpEvent->pos()));
688 }
689#endif // QT_NO_TOOLTIP
690 return QWidget::event(event);
691}
692
693/*
694 \internal
695*/
696void ControllerWidget::initStyleOption(QStyleOptionComplex *option) const
697{
698 option->initFrom(this);
699 option->subControls = visibleControls;
700 option->activeSubControls = QStyle::SC_None;
701}
702
703/*
704 \internal
705*/
706ControlContainer::ControlContainer(QMdiSubWindow *mdiChild)
707 : QObject(mdiChild),
708 previousLeft(0),
709 previousRight(0),
710#ifndef QT_NO_MENUBAR
711 m_menuBar(0),
712#endif
713 mdiChild(mdiChild)
714{
715 Q_ASSERT(mdiChild);
716
717 m_controllerWidget = new ControlElement<ControllerWidget>(mdiChild);
718 connect(m_controllerWidget, SIGNAL(_q_close()), mdiChild, SLOT(close()));
719 connect(m_controllerWidget, SIGNAL(_q_restore()), mdiChild, SLOT(showNormal()));
720 connect(m_controllerWidget, SIGNAL(_q_minimize()), mdiChild, SLOT(showMinimized()));
721
722 m_menuLabel = new ControlElement<ControlLabel>(mdiChild);
723 m_menuLabel->setWindowIcon(mdiChild->windowIcon());
724#ifndef QT_NO_MENU
725 connect(m_menuLabel, SIGNAL(_q_clicked()), mdiChild, SLOT(showSystemMenu()));
726#endif
727 connect(m_menuLabel, SIGNAL(_q_doubleClicked()), mdiChild, SLOT(close()));
728}
729
730ControlContainer::~ControlContainer()
731{
732#ifndef QT_NO_MENUBAR
733 removeButtonsFromMenuBar();
734#endif
735 delete m_menuLabel;
736 m_menuLabel = 0;
737 delete m_controllerWidget;
738 m_controllerWidget = 0;
739}
740
741#ifndef QT_NO_MENUBAR
742/*
743 \internal
744*/
745QMenuBar *QMdiSubWindowPrivate::menuBar() const
746{
747#if defined(QT_NO_MAINWINDOW)
748 return 0;
749#else
750 Q_Q(const QMdiSubWindow);
751 if (!q->isMaximized() || drawTitleBarWhenMaximized() || isChildOfTabbedQMdiArea(q))
752 return 0;
753
754 if (QMainWindow *mainWindow = qobject_cast<QMainWindow *>(q->window()))
755 return mainWindow->menuBar();
756
757 return 0;
758#endif
759}
760
761/*
762 \internal
763*/
764void ControlContainer::showButtonsInMenuBar(QMenuBar *menuBar)
765{
766 if (!menuBar || !mdiChild || mdiChild->windowFlags() & Qt::FramelessWindowHint)
767 return;
768 m_menuBar = menuBar;
769
770 if (m_menuLabel && mdiChild->windowFlags() & Qt::WindowSystemMenuHint) {
771 QWidget *currentLeft = menuBar->cornerWidget(Qt::TopLeftCorner);
772 if (currentLeft)
773 currentLeft->hide();
774 if (currentLeft != m_menuLabel) {
775 menuBar->setCornerWidget(m_menuLabel, Qt::TopLeftCorner);
776 previousLeft = currentLeft;
777 }
778 m_menuLabel->show();
779 }
780 ControllerWidget *controllerWidget = qobject_cast<ControllerWidget *>(m_controllerWidget);
781 if (controllerWidget && controllerWidget->hasVisibleControls()) {
782 QWidget *currentRight = menuBar->cornerWidget(Qt::TopRightCorner);
783 if (currentRight)
784 currentRight->hide();
785 if (currentRight != m_controllerWidget) {
786 menuBar->setCornerWidget(m_controllerWidget, Qt::TopRightCorner);
787 previousRight = currentRight;
788 }
789 m_controllerWidget->show();
790 }
791 mdiChild->d_func()->setNewWindowTitle();
792}
793
794/*
795 \internal
796*/
797void ControlContainer::removeButtonsFromMenuBar(QMenuBar *menuBar)
798{
799 if (menuBar && menuBar != m_menuBar) {
800 // m_menubar was deleted while sub-window was maximized
801 previousRight = 0;
802 previousLeft = 0;
803 m_menuBar = menuBar;
804 }
805
806 if (!m_menuBar || !mdiChild || qt_widget_private(mdiChild->window())->data.in_destructor)
807 return;
808
809 QMdiSubWindow *child = 0;
810 if (m_controllerWidget) {
811 QWidget *currentRight = m_menuBar->cornerWidget(Qt::TopRightCorner);
812 if (currentRight == m_controllerWidget) {
813 if (ControlElement<ControllerWidget> *ce = ptr<ControllerWidget>(previousRight)) {
814 if (!ce->mdiChild || !ce->mdiChild->isMaximized())
815 previousRight = 0;
816 else
817 child = ce->mdiChild;
818 }
819 m_menuBar->setCornerWidget(previousRight, Qt::TopRightCorner);
820 if (previousRight) {
821 previousRight->show();
822 previousRight = 0;
823 }
824 }
825 m_controllerWidget->hide();
826 m_controllerWidget->setParent(0);
827 }
828 if (m_menuLabel) {
829 QWidget *currentLeft = m_menuBar->cornerWidget(Qt::TopLeftCorner);
830 if (currentLeft == m_menuLabel) {
831 if (ControlElement<ControlLabel> *ce = ptr<ControlLabel>(previousLeft)) {
832 if (!ce->mdiChild || !ce->mdiChild->isMaximized())
833 previousLeft = 0;
834 else if (!child)
835 child = mdiChild;
836 }
837 m_menuBar->setCornerWidget(previousLeft, Qt::TopLeftCorner);
838 if (previousLeft) {
839 previousLeft->show();
840 previousLeft = 0;
841 }
842 }
843 m_menuLabel->hide();
844 m_menuLabel->setParent(0);
845 }
846 m_menuBar->update();
847 if (child)
848 child->d_func()->setNewWindowTitle();
849 else if (mdiChild)
850 mdiChild->window()->setWindowTitle(mdiChild->d_func()->originalWindowTitle());
851}
852
853#endif // QT_NO_MENUBAR
854
855void ControlContainer::updateWindowIcon(const QIcon &windowIcon)
856{
857 if (m_menuLabel)
858 m_menuLabel->setWindowIcon(windowIcon);
859}
860
861/*!
862 \internal
863*/
864QMdiSubWindowPrivate::QMdiSubWindowPrivate()
865 : baseWidget(0),
866 restoreFocusWidget(0),
867 controlContainer(0),
868#ifndef QT_NO_SIZEGRIP
869 sizeGrip(0),
870#endif
871#ifndef QT_NO_RUBBERBAND
872 rubberBand(0),
873#endif
874 userMinimumSize(0,0),
875 resizeEnabled(true),
876 moveEnabled(true),
877 isInInteractiveMode(false),
878#ifndef QT_NO_RUBBERBAND
879 isInRubberBandMode(false),
880#endif
881 isShadeMode(false),
882 ignoreWindowTitleChange(false),
883 ignoreNextActivationEvent(false),
884 activationEnabled(true),
885 isShadeRequestFromMinimizeMode(false),
886 isMaximizeMode(false),
887 isWidgetHiddenByUs(false),
888 isActive(false),
889 isExplicitlyDeactivated(false),
890 keyboardSingleStep(5),
891 keyboardPageStep(20),
892 resizeTimerId(-1),
893 currentOperation(None),
894 hoveredSubControl(QStyle::SC_None),
895 activeSubControl(QStyle::SC_None),
896 focusInReason(Qt::ActiveWindowFocusReason)
897{
898 initOperationMap();
899}
900
901/*!
902 \internal
903*/
904void QMdiSubWindowPrivate::_q_updateStaysOnTopHint()
905{
906#ifndef QT_NO_ACTION
907 Q_Q(QMdiSubWindow);
908 if (QAction *senderAction = qobject_cast<QAction *>(q->sender())) {
909 if (senderAction->isChecked()) {
910 q->setWindowFlags(q->windowFlags() | Qt::WindowStaysOnTopHint);
911 q->raise();
912 } else {
913 q->setWindowFlags(q->windowFlags() & ~Qt::WindowStaysOnTopHint);
914 q->lower();
915 }
916 }
917#endif // QT_NO_ACTION
918}
919
920/*!
921 \internal
922*/
923void QMdiSubWindowPrivate::_q_enterInteractiveMode()
924{
925#ifndef QT_NO_ACTION
926 Q_Q(QMdiSubWindow);
927 QAction *action = qobject_cast<QAction *>(q->sender());
928 if (!action)
929 return;
930
931 QPoint pressPos;
932 if (actions[MoveAction] && actions[MoveAction] == action) {
933 currentOperation = Move;
934 pressPos = QPoint(q->width() / 2, titleBarHeight() - 1);
935 } else if (actions[ResizeAction] && actions[ResizeAction] == action) {
936 currentOperation = q->isLeftToRight() ? BottomRightResize : BottomLeftResize;
937 int offset = q->style()->pixelMetric(QStyle::PM_MdiSubWindowFrameWidth, 0, q) / 2;
938 int x = q->isLeftToRight() ? q->width() - offset : offset;
939 pressPos = QPoint(x, q->height() - offset);
940 } else {
941 return;
942 }
943
944 updateCursor();
945#ifndef QT_NO_CURSOR
946 q->cursor().setPos(q->mapToGlobal(pressPos));
947#endif
948 mousePressPosition = q->mapToParent(pressPos);
949 oldGeometry = q->geometry();
950 isInInteractiveMode = true;
951 q->setFocus();
952#ifndef QT_NO_RUBBERBAND
953 if ((q->testOption(QMdiSubWindow::RubberBandResize)
954 && (currentOperation == BottomRightResize || currentOperation == BottomLeftResize))
955 || (q->testOption(QMdiSubWindow::RubberBandMove) && currentOperation == Move)) {
956 enterRubberBandMode();
957 } else
958#endif // QT_NO_RUBBERBAND
959 {
960 q->grabMouse();
961 }
962#endif // QT_NO_ACTION
963}
964
965/*!
966 \internal
967*/
968void QMdiSubWindowPrivate::_q_processFocusChanged(QWidget *old, QWidget *now)
969{
970 Q_UNUSED(old);
971 Q_Q(QMdiSubWindow);
972 if (now && (now == q || q->isAncestorOf(now))) {
973 if (now == q && !isInInteractiveMode)
974 setFocusWidget();
975 setActive(true);
976 }
977}
978
979/*!
980 \internal
981*/
982void QMdiSubWindowPrivate::leaveInteractiveMode()
983{
984 Q_Q(QMdiSubWindow);
985#ifndef QT_NO_RUBBERBAND
986 if (isInRubberBandMode)
987 leaveRubberBandMode();
988 else
989#endif
990 q->releaseMouse();
991 isInInteractiveMode = false;
992 currentOperation = None;
993 updateDirtyRegions();
994 updateCursor();
995 if (baseWidget && baseWidget->focusWidget())
996 baseWidget->focusWidget()->setFocus();
997}
998
999/*!
1000 \internal
1001*/
1002void QMdiSubWindowPrivate::removeBaseWidget()
1003{
1004 if (!baseWidget)
1005 return;
1006
1007 Q_Q(QMdiSubWindow);
1008 baseWidget->removeEventFilter(q);
1009 if (QLayout *layout = q->layout())
1010 layout->removeWidget(baseWidget);
1011 if (baseWidget->windowTitle() == q->windowTitle()) {
1012 ignoreWindowTitleChange = true;
1013 q->setWindowTitle(QString());
1014 ignoreWindowTitleChange = false;
1015 q->setWindowModified(false);
1016 }
1017 lastChildWindowTitle.clear();
1018 baseWidget->setParent(0);
1019 baseWidget = 0;
1020 isWidgetHiddenByUs = false;
1021}
1022
1023/*!
1024 \internal
1025*/
1026void QMdiSubWindowPrivate::initOperationMap()
1027{
1028 operationMap.insert(Move, OperationInfo(HMove | VMove, Qt::ArrowCursor, false));
1029 operationMap.insert(TopResize, OperationInfo(VMove | VResize | VResizeReverse, Qt::SizeVerCursor));
1030 operationMap.insert(BottomResize, OperationInfo(VResize, Qt::SizeVerCursor));
1031 operationMap.insert(LeftResize, OperationInfo(HMove | HResize | HResizeReverse, Qt::SizeHorCursor));
1032 operationMap.insert(RightResize, OperationInfo(HResize, Qt::SizeHorCursor));
1033 operationMap.insert(TopLeftResize, OperationInfo(HMove | VMove | HResize | VResize | VResizeReverse
1034 | HResizeReverse, Qt::SizeFDiagCursor));
1035 operationMap.insert(TopRightResize, OperationInfo(VMove | HResize | VResize
1036 | VResizeReverse, Qt::SizeBDiagCursor));
1037 operationMap.insert(BottomLeftResize, OperationInfo(HMove | HResize | VResize | HResizeReverse,
1038 Qt::SizeBDiagCursor));
1039 operationMap.insert(BottomRightResize, OperationInfo(HResize | VResize, Qt::SizeFDiagCursor));
1040}
1041
1042#ifndef QT_NO_MENU
1043
1044/*!
1045 \internal
1046*/
1047void QMdiSubWindowPrivate::createSystemMenu()
1048{
1049 Q_Q(QMdiSubWindow);
1050 Q_ASSERT_X(q, "QMdiSubWindowPrivate::createSystemMenu",
1051 "You can NOT call this function before QMdiSubWindow's ctor");
1052 systemMenu = new QMenu(q);
1053 const QStyle *style = q->style();
1054 addToSystemMenu(RestoreAction, QMdiSubWindow::tr("&Restore"), SLOT(showNormal()));
1055 actions[RestoreAction]->setIcon(style->standardIcon(QStyle::SP_TitleBarNormalButton, 0, q));
1056 actions[RestoreAction]->setEnabled(false);
1057 addToSystemMenu(MoveAction, QMdiSubWindow::tr("&Move"), SLOT(_q_enterInteractiveMode()));
1058 addToSystemMenu(ResizeAction, QMdiSubWindow::tr("&Size"), SLOT(_q_enterInteractiveMode()));
1059 addToSystemMenu(MinimizeAction, QMdiSubWindow::tr("Mi&nimize"), SLOT(showMinimized()));
1060 actions[MinimizeAction]->setIcon(style->standardIcon(QStyle::SP_TitleBarMinButton, 0, q));
1061 addToSystemMenu(MaximizeAction, QMdiSubWindow::tr("Ma&ximize"), SLOT(showMaximized()));
1062 actions[MaximizeAction]->setIcon(style->standardIcon(QStyle::SP_TitleBarMaxButton, 0, q));
1063 addToSystemMenu(StayOnTopAction, QMdiSubWindow::tr("Stay on &Top"), SLOT(_q_updateStaysOnTopHint()));
1064 actions[StayOnTopAction]->setCheckable(true);
1065 systemMenu->addSeparator();
1066 addToSystemMenu(CloseAction, QMdiSubWindow::tr("&Close"), SLOT(close()));
1067 actions[CloseAction]->setIcon(style->standardIcon(QStyle::SP_TitleBarCloseButton, 0, q));
1068#if !defined(QT_NO_SHORTCUT)
1069 actions[CloseAction]->setShortcut(QKeySequence::Close);
1070#endif
1071 updateActions();
1072}
1073#endif
1074
1075/*!
1076 \internal
1077*/
1078void QMdiSubWindowPrivate::updateCursor()
1079{
1080#ifndef QT_NO_CURSOR
1081 Q_Q(QMdiSubWindow);
1082#if defined(Q_WS_MAC) && !defined(QT_NO_STYLE_MAC)
1083 if (qobject_cast<QMacStyle *>(q->style()))
1084 return;
1085#endif
1086
1087 if (currentOperation == None) {
1088 q->unsetCursor();
1089 return;
1090 }
1091
1092 if (currentOperation == Move || operationMap.find(currentOperation).value().hover) {
1093 q->setCursor(operationMap.find(currentOperation).value().cursorShape);
1094 return;
1095 }
1096#endif
1097}
1098
1099/*!
1100 \internal
1101*/
1102void QMdiSubWindowPrivate::updateDirtyRegions()
1103{
1104 // No update necessary
1105 if (!q_func()->parent())
1106 return;
1107
1108 foreach (Operation operation, operationMap.keys())
1109 operationMap.find(operation).value().region = getRegion(operation);
1110}
1111
1112/*!
1113 \internal
1114*/
1115void QMdiSubWindowPrivate::updateGeometryConstraints()
1116{
1117 Q_Q(QMdiSubWindow);
1118 if (!q->parent())
1119 return;
1120
1121 internalMinimumSize = (!q->isMinimized() && !q->minimumSize().isNull())
1122 ? q->minimumSize() : q->minimumSizeHint();
1123 int margin, minWidth;
1124 sizeParameters(&margin, &minWidth);
1125 q->setContentsMargins(margin, titleBarHeight(), margin, margin);
1126 if (q->isMaximized() || (q->isMinimized() && !q->isShaded())) {
1127 moveEnabled = false;
1128 resizeEnabled = false;
1129 } else {
1130 moveEnabled = true;
1131 if ((q->windowFlags() & Qt::MSWindowsFixedSizeDialogHint) || q->isShaded())
1132 resizeEnabled = false;
1133 else
1134 resizeEnabled = true;
1135 }
1136 updateDirtyRegions();
1137}
1138
1139/*!
1140 \internal
1141*/
1142void QMdiSubWindowPrivate::updateMask()
1143{
1144 Q_Q(QMdiSubWindow);
1145 if (!q->mask().isEmpty())
1146 q->clearMask();
1147
1148 if (!q->parent())
1149 return;
1150
1151 if ((q->isMaximized() && !drawTitleBarWhenMaximized())
1152 || q->windowFlags() & Qt::FramelessWindowHint)
1153 return;
1154
1155 if (resizeTimerId == -1)
1156 cachedStyleOptions = titleBarOptions();
1157 cachedStyleOptions.rect = q->rect();
1158 QStyleHintReturnMask frameMask;
1159 q->style()->styleHint(QStyle::SH_WindowFrame_Mask, &cachedStyleOptions, q, &frameMask);
1160 if (!frameMask.region.isEmpty())
1161 q->setMask(frameMask.region);
1162}
1163
1164/*!
1165 \internal
1166*/
1167void QMdiSubWindowPrivate::setNewGeometry(const QPoint &pos)
1168{
1169 Q_Q(QMdiSubWindow);
1170 Q_ASSERT(currentOperation != None);
1171 Q_ASSERT(q->parent());
1172
1173 uint cflags = operationMap.find(currentOperation).value().changeFlags;
1174 int posX = pos.x();
1175 int posY = pos.y();
1176
1177 const bool restrictHorizontal = !q->testOption(QMdiSubWindow::AllowOutsideAreaHorizontally);
1178 const bool restrictVertical = !q->testOption(QMdiSubWindow::AllowOutsideAreaVertically);
1179
1180 if (restrictHorizontal || restrictVertical) {
1181 QRect parentRect = q->parentWidget()->rect();
1182 if (restrictVertical && (cflags & VResizeReverse || currentOperation == Move)) {
1183 posY = qMin(qMax(mousePressPosition.y() - oldGeometry.y(), posY),
1184 parentRect.height() - BoundaryMargin);
1185 }
1186 if (currentOperation == Move) {
1187 if (restrictHorizontal)
1188 posX = qMin(qMax(BoundaryMargin, posX), parentRect.width() - BoundaryMargin);
1189 if (restrictVertical)
1190 posY = qMin(posY, parentRect.height() - BoundaryMargin);
1191 } else {
1192 if (restrictHorizontal) {
1193 if (cflags & HResizeReverse)
1194 posX = qMax(mousePressPosition.x() - oldGeometry.x(), posX);
1195 else
1196 posX = qMin(parentRect.width() - (oldGeometry.x() + oldGeometry.width()
1197 - mousePressPosition.x()), posX);
1198 }
1199 if (restrictVertical && !(cflags & VResizeReverse)) {
1200 posY = qMin(parentRect.height() - (oldGeometry.y() + oldGeometry.height()
1201 - mousePressPosition.y()), posY);
1202 }
1203 }
1204 }
1205
1206 QRect geometry;
1207 if (cflags & (HMove | VMove)) {
1208 int dx = getMoveDeltaComponent(cflags, HMove, HResize, posX - mousePressPosition.x(),
1209 oldGeometry.width() - internalMinimumSize.width(),
1210 oldGeometry.width() - q->maximumWidth());
1211 int dy = getMoveDeltaComponent(cflags, VMove, VResize, posY - mousePressPosition.y(),
1212 oldGeometry.height() - internalMinimumSize.height(),
1213 oldGeometry.height() - q->maximumHeight());
1214 geometry.setTopLeft(oldGeometry.topLeft() + QPoint(dx, dy));
1215 } else {
1216 geometry.setTopLeft(q->geometry().topLeft());
1217 }
1218
1219 if (cflags & (HResize | VResize)) {
1220 int dx = getResizeDeltaComponent(cflags, HResize, HResizeReverse,
1221 posX - mousePressPosition.x());
1222 int dy = getResizeDeltaComponent(cflags, VResize, VResizeReverse,
1223 posY - mousePressPosition.y());
1224 geometry.setSize(oldGeometry.size() + QSize(dx, dy));
1225 } else {
1226 geometry.setSize(q->geometry().size());
1227 }
1228
1229 setNewGeometry(&geometry);
1230}
1231
1232/*!
1233 \internal
1234*/
1235void QMdiSubWindowPrivate::setMinimizeMode()
1236{
1237 Q_Q(QMdiSubWindow);
1238 Q_ASSERT(q->parent());
1239
1240 ensureWindowState(Qt::WindowMinimized);
1241 isShadeRequestFromMinimizeMode = true;
1242 q->showShaded();
1243 isShadeRequestFromMinimizeMode = false;
1244
1245 moveEnabled = false;
1246#ifndef QT_NO_ACTION
1247 setEnabled(MoveAction, moveEnabled);
1248#endif
1249
1250 Q_ASSERT(q->windowState() & Qt::WindowMinimized);
1251 Q_ASSERT(!(q->windowState() & Qt::WindowMaximized));
1252 // This should be a valid assert, but people can actually re-implement
1253 // setVisible and do crazy stuff, so we're not guaranteed that
1254 // the widget is hidden after calling hide().
1255 // Q_ASSERT(baseWidget ? baseWidget->isHidden() : true);
1256
1257 setActive(true);
1258}
1259
1260/*!
1261 \internal
1262*/
1263void QMdiSubWindowPrivate::setNormalMode()
1264{
1265 Q_Q(QMdiSubWindow);
1266 Q_ASSERT(q->parent());
1267
1268 isShadeMode = false;
1269 isMaximizeMode = false;
1270
1271 ensureWindowState(Qt::WindowNoState);
1272#ifndef QT_NO_MENUBAR
1273 removeButtonsFromMenuBar();
1274#endif
1275
1276 // Hide the window before we change the geometry to avoid multiple resize
1277 // events and wrong window state.
1278 const bool wasVisible = q->isVisible();
1279 if (wasVisible)
1280 q->setVisible(false);
1281
1282 // Restore minimum size if set by user.
1283 if (!userMinimumSize.isNull()) {
1284 q->setMinimumSize(userMinimumSize);
1285 userMinimumSize = QSize(0, 0);
1286 }
1287
1288 // Show the internal widget if it was hidden by us,
1289 if (baseWidget && isWidgetHiddenByUs) {
1290 baseWidget->show();
1291 isWidgetHiddenByUs = false;
1292 }
1293
1294 updateGeometryConstraints();
1295 QRect newGeometry = oldGeometry;
1296 newGeometry.setSize(restoreSize.expandedTo(internalMinimumSize));
1297 q->setGeometry(newGeometry);
1298
1299 if (wasVisible)
1300 q->setVisible(true);
1301
1302 // Invalidate the restore size.
1303 restoreSize.setWidth(-1);
1304 restoreSize.setHeight(-1);
1305
1306#ifndef QT_NO_SIZEGRIP
1307 setSizeGripVisible(true);
1308#endif
1309
1310#ifndef QT_NO_ACTION
1311 setEnabled(MoveAction, true);
1312 setEnabled(MaximizeAction, true);
1313 setEnabled(MinimizeAction, true);
1314 setEnabled(RestoreAction, false);
1315 setEnabled(ResizeAction, resizeEnabled);
1316#endif // QT_NO_ACTION
1317
1318 Q_ASSERT(!(q_func()->windowState() & Qt::WindowMinimized));
1319 // This sub-window can be maximized when shown above if not the
1320 // QMdiArea::DontMaximizeSubWindowOnActionvation is set. Make sure
1321 // the Qt::WindowMaximized flag is set accordingly.
1322 Q_ASSERT((isMaximizeMode && q_func()->windowState() & Qt::WindowMaximized)
1323 || (!isMaximizeMode && !(q_func()->windowState() & Qt::WindowMaximized)));
1324 Q_ASSERT(!isShadeMode);
1325
1326 setActive(true);
1327 restoreFocus();
1328 updateMask();
1329}
1330
1331/*!
1332 \internal
1333*/
1334void QMdiSubWindowPrivate::setMaximizeMode()
1335{
1336 Q_Q(QMdiSubWindow);
1337 Q_ASSERT(q->parent());
1338
1339 ensureWindowState(Qt::WindowMaximized);
1340 isShadeMode = false;
1341 isMaximizeMode = true;
1342
1343 if (!restoreFocusWidget && q->isAncestorOf(QApplication::focusWidget()))
1344 restoreFocusWidget = QApplication::focusWidget();
1345
1346#ifndef QT_NO_SIZEGRIP
1347 setSizeGripVisible(false);
1348#endif
1349
1350 // Store old geometry and set restore size if not already set.
1351 if (!restoreSize.isValid()) {
1352 oldGeometry = q->geometry();
1353 restoreSize.setWidth(oldGeometry.width());
1354 restoreSize.setHeight(oldGeometry.height());
1355 }
1356
1357 // Hide the window before we change the geometry to avoid multiple resize
1358 // events and wrong window state.
1359 const bool wasVisible = q->isVisible();
1360 if (wasVisible)
1361 q->setVisible(false);
1362
1363 // Show the internal widget if it was hidden by us.
1364 if (baseWidget && isWidgetHiddenByUs) {
1365 baseWidget->show();
1366 isWidgetHiddenByUs = false;
1367 }
1368
1369 updateGeometryConstraints();
1370
1371 if (wasVisible) {
1372#ifndef QT_NO_MENUBAR
1373 if (QMenuBar *mBar = menuBar())
1374 showButtonsInMenuBar(mBar);
1375 else
1376#endif
1377 if (!controlContainer)
1378 controlContainer = new ControlContainer(q);
1379 }
1380
1381 QWidget *parent = q->parentWidget();
1382 QRect availableRect = parent->contentsRect();
1383
1384 // Adjust geometry if the sub-window is inside a scroll area.
1385 QAbstractScrollArea *scrollArea = qobject_cast<QAbstractScrollArea *>(parent->parentWidget());
1386 if (scrollArea && scrollArea->viewport() == parent) {
1387 QScrollBar *hbar = scrollArea->horizontalScrollBar();
1388 QScrollBar *vbar = scrollArea->verticalScrollBar();
1389 const int xOffset = hbar ? hbar->value() : 0;
1390 const int yOffset = vbar ? vbar->value() : 0;
1391 availableRect.adjust(-xOffset, -yOffset, -xOffset, -yOffset);
1392 oldGeometry.adjust(xOffset, yOffset, xOffset, yOffset);
1393 }
1394
1395 setNewGeometry(&availableRect);
1396 // QWidget::setGeometry will reset Qt::WindowMaximized so we have to update it here.
1397 ensureWindowState(Qt::WindowMaximized);
1398
1399 if (wasVisible)
1400 q->setVisible(true);
1401
1402 resizeEnabled = false;
1403 moveEnabled = false;
1404
1405#ifndef QT_NO_ACTION
1406 setEnabled(MoveAction, moveEnabled);
1407 setEnabled(MaximizeAction, false);
1408 setEnabled(MinimizeAction, true);
1409 setEnabled(RestoreAction, true);
1410 setEnabled(ResizeAction, resizeEnabled);
1411#endif // QT_NO_ACTION
1412
1413 Q_ASSERT(q->windowState() & Qt::WindowMaximized);
1414 Q_ASSERT(!(q->windowState() & Qt::WindowMinimized));
1415
1416 restoreFocus();
1417 updateMask();
1418}
1419
1420/*!
1421 \internal
1422*/
1423void QMdiSubWindowPrivate::setActive(bool activate, bool changeFocus)
1424{
1425 Q_Q(QMdiSubWindow);
1426 if (!q->parent() || !activationEnabled)
1427 return;
1428
1429 if (activate && !isActive && q->isEnabled()) {
1430 isActive = true;
1431 isExplicitlyDeactivated = false;
1432 Qt::WindowStates oldWindowState = q->windowState();
1433 ensureWindowState(Qt::WindowActive);
1434 emit q->aboutToActivate();
1435#ifndef QT_NO_MENUBAR
1436 if (QMenuBar *mBar = menuBar())
1437 showButtonsInMenuBar(mBar);
1438#endif
1439 Q_ASSERT(isActive);
1440 emit q->windowStateChanged(oldWindowState, q->windowState());
1441 } else if (!activate && isActive) {
1442 isActive = false;
1443 Qt::WindowStates oldWindowState = q->windowState();
1444 q->overrideWindowState(q->windowState() & ~Qt::WindowActive);
1445 if (changeFocus) {
1446 QWidget *focusWidget = QApplication::focusWidget();
1447 if (focusWidget && (focusWidget == q || q->isAncestorOf(focusWidget)))
1448 focusWidget->clearFocus();
1449 }
1450 if (baseWidget)
1451 baseWidget->overrideWindowState(baseWidget->windowState() & ~Qt::WindowActive);
1452 Q_ASSERT(!isActive);
1453 emit q->windowStateChanged(oldWindowState, q->windowState());
1454 }
1455
1456 if (activate && isActive && q->isEnabled() && !q->hasFocus()
1457 && !q->isAncestorOf(QApplication::focusWidget())) {
1458 if (changeFocus)
1459 setFocusWidget();
1460 ensureWindowState(Qt::WindowActive);
1461 }
1462
1463 int frameWidth = q->style()->pixelMetric(QStyle::PM_MdiSubWindowFrameWidth, 0, q);
1464 int titleBarHeight = this->titleBarHeight();
1465 QRegion windowDecoration = QRegion(0, 0, q->width(), q->height());
1466 windowDecoration -= QRegion(frameWidth, titleBarHeight, q->width() - 2 * frameWidth,
1467 q->height() - titleBarHeight - frameWidth);
1468
1469 // Make sure we don't use cached style options if we get
1470 // resize events right before activation/deactivation.
1471 if (resizeTimerId != -1) {
1472 q->killTimer(resizeTimerId);
1473 resizeTimerId = -1;
1474 updateDirtyRegions();
1475 }
1476
1477 q->update(windowDecoration);
1478}
1479
1480/*!
1481 \internal
1482*/
1483void QMdiSubWindowPrivate::processClickedSubControl()
1484{
1485 Q_Q(QMdiSubWindow);
1486 switch (activeSubControl) {
1487 case QStyle::SC_TitleBarContextHelpButton:
1488#ifndef QT_NO_WHATSTHIS
1489 QWhatsThis::enterWhatsThisMode();
1490#endif
1491 break;
1492 case QStyle::SC_TitleBarShadeButton:
1493 q->showShaded();
1494 hoveredSubControl = QStyle::SC_TitleBarUnshadeButton;
1495 break;
1496 case QStyle::SC_TitleBarUnshadeButton:
1497 if (q->isShaded())
1498 hoveredSubControl = QStyle::SC_TitleBarShadeButton;
1499 q->showNormal();
1500 break;
1501 case QStyle::SC_TitleBarMinButton:
1502#if defined(Q_WS_MAC) && !defined(QT_NO_STYLE_MAC)
1503 if (qobject_cast<QMacStyle *>(q->style())) {
1504 if (q->isMinimized())
1505 q->showNormal();
1506 else
1507 q->showMinimized();
1508 break;
1509 }
1510#endif
1511 q->showMinimized();
1512 break;
1513 case QStyle::SC_TitleBarNormalButton:
1514 if (q->isShaded())
1515 hoveredSubControl = QStyle::SC_TitleBarMinButton;
1516 q->showNormal();
1517 break;
1518 case QStyle::SC_TitleBarMaxButton:
1519#if defined(Q_WS_MAC) && !defined(QT_NO_STYLE_MAC)
1520 if (qobject_cast<QMacStyle *>(q->style())) {
1521 if (q->isMaximized())
1522 q->showNormal();
1523 else
1524 q->showMaximized();
1525 break;
1526 }
1527#endif
1528 q->showMaximized();
1529 break;
1530 case QStyle::SC_TitleBarCloseButton:
1531 q->close();
1532 break;
1533 default:
1534 break;
1535 }
1536}
1537
1538/*!
1539 \internal
1540*/
1541QRegion QMdiSubWindowPrivate::getRegion(Operation operation) const
1542{
1543 Q_Q(const QMdiSubWindow);
1544 int width = q->width();
1545 int height = q->height();
1546 int titleBarHeight = this->titleBarHeight();
1547 int frameWidth = q->style()->pixelMetric(QStyle::PM_MdiSubWindowFrameWidth, 0, q);
1548 int cornerConst = titleBarHeight - frameWidth;
1549 int titleBarConst = 2 * titleBarHeight;
1550
1551 if (operation == Move) {
1552 QStyleOptionTitleBar titleBarOptions = this->titleBarOptions();
1553 QRegion move(frameWidth, frameWidth, width - 2 * frameWidth, cornerConst);
1554 // Depending on which window flags are set, activated sub controllers will
1555 // be subtracted from the 'move' region.
1556 for (int i = 0; i < NumSubControls; ++i) {
1557 if (SubControls[i] == QStyle::SC_TitleBarLabel)
1558 continue;
1559 move -= QRegion(q->style()->subControlRect(QStyle::CC_TitleBar, &titleBarOptions,
1560 SubControls[i]));
1561 }
1562 return move;
1563 }
1564
1565 QRegion region;
1566#if defined(Q_WS_MAC) && !defined(QT_NO_STYLE_MAC)
1567 if (qobject_cast<QMacStyle *>(q->style()))
1568 return region;
1569#endif
1570
1571 switch (operation) {
1572 case TopResize:
1573 region = QRegion(titleBarHeight, 0, width - titleBarConst, frameWidth);
1574 break;
1575 case BottomResize:
1576 region = QRegion(titleBarHeight, height - frameWidth, width - titleBarConst, frameWidth);
1577 break;
1578 case LeftResize:
1579 region = QRegion(0, titleBarHeight, frameWidth, height - titleBarConst);
1580 break;
1581 case RightResize:
1582 region = QRegion(width - frameWidth, titleBarHeight, frameWidth, height - titleBarConst);
1583 break;
1584 case TopLeftResize:
1585 region = QRegion(0, 0, titleBarHeight, titleBarHeight)
1586 - QRegion(frameWidth, frameWidth, cornerConst, cornerConst);
1587 break;
1588 case TopRightResize:
1589 region = QRegion(width - titleBarHeight, 0, titleBarHeight, titleBarHeight)
1590 - QRegion(width - titleBarHeight, frameWidth, cornerConst, cornerConst);
1591 break;
1592 case BottomLeftResize:
1593 region = QRegion(0, height - titleBarHeight, titleBarHeight, titleBarHeight)
1594 - QRegion(frameWidth, height - titleBarHeight, cornerConst, cornerConst);
1595 break;
1596 case BottomRightResize:
1597 region = QRegion(width - titleBarHeight, height - titleBarHeight, titleBarHeight, titleBarHeight)
1598 - QRegion(width - titleBarHeight, height - titleBarHeight, cornerConst, cornerConst);
1599 break;
1600 default:
1601 break;
1602 }
1603
1604 return region;
1605}
1606
1607/*!
1608 \internal
1609*/
1610QMdiSubWindowPrivate::Operation QMdiSubWindowPrivate::getOperation(const QPoint &pos) const
1611{
1612 OperationInfoMap::const_iterator it;
1613 for (it = operationMap.constBegin(); it != operationMap.constEnd(); ++it)
1614 if (it.value().region.contains(pos))
1615 return it.key();
1616 return None;
1617}
1618
1619extern QString qt_setWindowTitle_helperHelper(const QString&, const QWidget*);
1620
1621/*!
1622 \internal
1623*/
1624QStyleOptionTitleBar QMdiSubWindowPrivate::titleBarOptions() const
1625{
1626 Q_Q(const QMdiSubWindow);
1627 QStyleOptionTitleBar titleBarOptions;
1628 titleBarOptions.initFrom(q);
1629 if (activeSubControl != QStyle::SC_None) {
1630 if (hoveredSubControl == activeSubControl) {
1631 titleBarOptions.state |= QStyle::State_Sunken;
1632 titleBarOptions.activeSubControls = activeSubControl;
1633 }
1634 } else if (autoRaise() && hoveredSubControl != QStyle::SC_None
1635 && hoveredSubControl != QStyle::SC_TitleBarLabel) {
1636 titleBarOptions.state |= QStyle::State_MouseOver;
1637 titleBarOptions.activeSubControls = hoveredSubControl;
1638 } else {
1639 titleBarOptions.state &= ~QStyle::State_MouseOver;
1640 titleBarOptions.activeSubControls = QStyle::SC_None;
1641 }
1642
1643 titleBarOptions.subControls = QStyle::SC_All;
1644 titleBarOptions.titleBarFlags = q->windowFlags();
1645 titleBarOptions.titleBarState = q->windowState();
1646 titleBarOptions.palette = titleBarPalette;
1647 titleBarOptions.icon = menuIcon;
1648
1649 if (isActive) {
1650 titleBarOptions.state |= QStyle::State_Active;
1651 titleBarOptions.titleBarState |= QStyle::State_Active;
1652 titleBarOptions.palette.setCurrentColorGroup(QPalette::Active);
1653 } else {
1654 titleBarOptions.state &= ~QStyle::State_Active;
1655 titleBarOptions.palette.setCurrentColorGroup(QPalette::Inactive);
1656 }
1657
1658 int border = hasBorder(titleBarOptions) ? 4 : 0;
1659 int paintHeight = titleBarHeight(titleBarOptions);
1660 paintHeight -= q->isMinimized() ? 2 * border : border;
1661 titleBarOptions.rect = QRect(border, border, q->width() - 2 * border, paintHeight);
1662
1663 if (!windowTitle.isEmpty()) {
1664 // Set the text here before asking for the width of the title bar label
1665 // in case people uses the actual text to calculate the width.
1666 titleBarOptions.text = windowTitle;
1667 titleBarOptions.fontMetrics = QFontMetrics(font);
1668 int width = q->style()->subControlRect(QStyle::CC_TitleBar, &titleBarOptions,
1669 QStyle::SC_TitleBarLabel, q).width();
1670 // Set elided text if we don't have enough space for the entire title.
1671 titleBarOptions.text = titleBarOptions.fontMetrics.elidedText(windowTitle, Qt::ElideRight, width);
1672 }
1673 return titleBarOptions;
1674}
1675
1676/*!
1677 \internal
1678*/
1679void QMdiSubWindowPrivate::ensureWindowState(Qt::WindowState state)
1680{
1681 Q_Q(QMdiSubWindow);
1682 Qt::WindowStates windowStates = q->windowState() | state;
1683 switch (state) {
1684 case Qt::WindowMinimized:
1685 windowStates &= ~Qt::WindowMaximized;
1686 windowStates &= ~Qt::WindowNoState;
1687 break;
1688 case Qt::WindowMaximized:
1689 windowStates &= ~Qt::WindowMinimized;
1690 windowStates &= ~Qt::WindowNoState;
1691 break;
1692 case Qt::WindowNoState:
1693 windowStates &= ~Qt::WindowMinimized;
1694 windowStates &= ~Qt::WindowMaximized;
1695 break;
1696 default:
1697 break;
1698 }
1699 if (baseWidget) {
1700 if (!(baseWidget->windowState() & Qt::WindowActive) && windowStates & Qt::WindowActive)
1701 baseWidget->overrideWindowState(windowStates & ~Qt::WindowActive);
1702 else
1703 baseWidget->overrideWindowState(windowStates);
1704 }
1705 q->overrideWindowState(windowStates);
1706}
1707
1708/*!
1709 \internal
1710*/
1711int QMdiSubWindowPrivate::titleBarHeight(const QStyleOptionTitleBar &options) const
1712{
1713 Q_Q(const QMdiSubWindow);
1714 if (!q->parent() || q->windowFlags() & Qt::FramelessWindowHint
1715 || (q->isMaximized() && !drawTitleBarWhenMaximized())) {
1716 return 0;
1717 }
1718
1719 int height = q->style()->pixelMetric(QStyle::PM_TitleBarHeight, &options, q);
1720#if defined(Q_WS_MAC) && !defined(QT_NO_STYLE_MAC)
1721 // ### Fix mac style, the +4 pixels hack is not necessary anymore
1722 if (qobject_cast<QMacStyle *>(q->style()))
1723 height -= 4;
1724#endif
1725 if (hasBorder(options))
1726 height += q->isMinimized() ? 8 : 4;
1727 return height;
1728}
1729
1730/*!
1731 \internal
1732*/
1733void QMdiSubWindowPrivate::sizeParameters(int *margin, int *minWidth) const
1734{
1735 Q_Q(const QMdiSubWindow);
1736 Qt::WindowFlags flags = q->windowFlags();
1737 if (!q->parent() || flags & Qt::FramelessWindowHint) {
1738 *margin = 0;
1739 *minWidth = 0;
1740 return;
1741 }
1742
1743 if (q->isMaximized() && !drawTitleBarWhenMaximized())
1744 *margin = 0;
1745 else
1746 *margin = q->style()->pixelMetric(QStyle::PM_MdiSubWindowFrameWidth, 0, q);
1747
1748 QStyleOptionTitleBar opt = this->titleBarOptions();
1749 int tempWidth = 0;
1750 for (int i = 0; i < NumSubControls; ++i) {
1751 if (SubControls[i] == QStyle::SC_TitleBarLabel) {
1752 tempWidth += 30;
1753 continue;
1754 }
1755 QRect rect = q->style()->subControlRect(QStyle::CC_TitleBar, &opt, SubControls[i], q);
1756 if (!rect.isValid())
1757 continue;
1758 tempWidth += rect.width();
1759 }
1760 *minWidth = tempWidth;
1761}
1762
1763/*!
1764 \internal
1765*/
1766bool QMdiSubWindowPrivate::drawTitleBarWhenMaximized() const
1767{
1768 Q_Q(const QMdiSubWindow);
1769 if (q->window()->testAttribute(Qt::WA_CanHostQMdiSubWindowTitleBar))
1770 return false;
1771
1772 if (isChildOfTabbedQMdiArea(q))
1773 return false;
1774
1775#if defined(Q_WS_MAC) && !defined(QT_NO_STYLE_MAC) || defined(Q_OS_WINCE_WM)
1776 return true;
1777#else
1778 if (q->style()->styleHint(QStyle::SH_Workspace_FillSpaceOnMaximize, 0, q))
1779 return true;
1780#if defined(QT_NO_MENUBAR) || defined(QT_NO_MAINWINDOW)
1781 return true;
1782#else
1783 QMainWindow *mainWindow = qobject_cast<QMainWindow *>(q->window());
1784 if (!mainWindow || !qobject_cast<QMenuBar *>(mainWindow->menuWidget())
1785 || mainWindow->menuWidget()->isHidden())
1786 return true;
1787
1788 return isChildOfQMdiSubWindow(q);
1789#endif
1790#endif
1791}
1792
1793#ifndef QT_NO_MENUBAR
1794
1795/*!
1796 \internal
1797*/
1798void QMdiSubWindowPrivate::showButtonsInMenuBar(QMenuBar *menuBar)
1799{
1800 Q_Q(QMdiSubWindow);
1801 Q_ASSERT(q->isMaximized() && !drawTitleBarWhenMaximized());
1802
1803 if (isChildOfTabbedQMdiArea(q))
1804 return;
1805
1806 removeButtonsFromMenuBar();
1807 if (!controlContainer)
1808 controlContainer = new ControlContainer(q);
1809
1810 ignoreWindowTitleChange = true;
1811 controlContainer->showButtonsInMenuBar(menuBar);
1812 ignoreWindowTitleChange = false;
1813
1814 QWidget *topLevelWindow = q->window();
1815 topLevelWindow->setWindowModified(q->isWindowModified());
1816 topLevelWindow->installEventFilter(q);
1817
1818 int buttonHeight = 0;
1819 if (controlContainer->controllerWidget())
1820 buttonHeight = controlContainer->controllerWidget()->height();
1821 else if (controlContainer->systemMenuLabel())
1822 buttonHeight = controlContainer->systemMenuLabel()->height();
1823
1824 // This will rarely happen.
1825 if (menuBar && menuBar->height() < buttonHeight
1826 && topLevelWindow->layout()) {
1827 // Make sure topLevelWindow->contentsRect returns correct geometry.
1828 // topLevelWidget->updateGeoemtry will not do the trick here since it will post the event.
1829 QEvent event(QEvent::LayoutRequest);
1830 QApplication::sendEvent(topLevelWindow, &event);
1831 }
1832}
1833
1834/*!
1835 \internal
1836*/
1837void QMdiSubWindowPrivate::removeButtonsFromMenuBar()
1838{
1839 Q_Q(QMdiSubWindow);
1840
1841 if (!controlContainer || isChildOfTabbedQMdiArea(q))
1842 return;
1843
1844 QMenuBar *currentMenuBar = 0;
1845#ifndef QT_NO_MAINWINDOW
1846 if (QMainWindow *mainWindow = qobject_cast<QMainWindow *>(q->window())) {
1847 // NB! We can't use menuBar() here because that one will actually create
1848 // a menubar for us if not set. That's not what we want :-)
1849 currentMenuBar = qobject_cast<QMenuBar *>(mainWindow->menuWidget());
1850 }
1851#endif
1852
1853 ignoreWindowTitleChange = true;
1854 controlContainer->removeButtonsFromMenuBar(currentMenuBar);
1855 ignoreWindowTitleChange = false;
1856
1857 QWidget *topLevelWindow = q->window();
1858 topLevelWindow->removeEventFilter(q);
1859 if (baseWidget && !drawTitleBarWhenMaximized())
1860 topLevelWindow->setWindowModified(false);
1861 originalTitle = QString::null;
1862}
1863
1864#endif // QT_NO_MENUBAR
1865
1866void QMdiSubWindowPrivate::updateWindowTitle(bool isRequestFromChild)
1867{
1868 Q_Q(QMdiSubWindow);
1869 if (isRequestFromChild && !q->windowTitle().isEmpty() && !lastChildWindowTitle.isEmpty()
1870 && lastChildWindowTitle != q->windowTitle()) {
1871 return;
1872 }
1873
1874 QWidget *titleWidget = 0;
1875 if (isRequestFromChild)
1876 titleWidget = baseWidget;
1877 else
1878 titleWidget = q;
1879 if (!titleWidget || titleWidget->windowTitle().isEmpty())
1880 return;
1881
1882 ignoreWindowTitleChange = true;
1883 q->setWindowTitle(titleWidget->windowTitle());
1884 if (q->maximizedButtonsWidget())
1885 setNewWindowTitle();
1886 ignoreWindowTitleChange = false;
1887}
1888
1889#ifndef QT_NO_RUBBERBAND
1890void QMdiSubWindowPrivate::enterRubberBandMode()
1891{
1892 Q_Q(QMdiSubWindow);
1893 if (q->isMaximized())
1894 return;
1895 Q_ASSERT(oldGeometry.isValid());
1896 Q_ASSERT(q->parent());
1897 if (!rubberBand) {
1898 rubberBand = new QRubberBand(QRubberBand::Rectangle, q->parentWidget());
1899 // For accessibility to identify this special widget.
1900 rubberBand->setObjectName(QLatin1String("qt_rubberband"));
1901 }
1902 QPoint rubberBandPos = q->mapToParent(QPoint(0, 0));
1903 rubberBand->setGeometry(rubberBandPos.x(), rubberBandPos.y(),
1904 oldGeometry.width(), oldGeometry.height());
1905 rubberBand->show();
1906 isInRubberBandMode = true;
1907 q->grabMouse();
1908}
1909
1910void QMdiSubWindowPrivate::leaveRubberBandMode()
1911{
1912 Q_Q(QMdiSubWindow);
1913 Q_ASSERT(rubberBand);
1914 Q_ASSERT(isInRubberBandMode);
1915 q->releaseMouse();
1916 isInRubberBandMode = false;
1917 q->setGeometry(rubberBand->geometry());
1918 rubberBand->hide();
1919 currentOperation = None;
1920}
1921#endif // QT_NO_RUBBERBAND
1922
1923// Taken from the old QWorkspace (::readColors())
1924QPalette QMdiSubWindowPrivate::desktopPalette() const
1925{
1926 Q_Q(const QMdiSubWindow);
1927 QPalette newPalette = q->palette();
1928
1929 bool colorsInitialized = false;
1930#ifdef Q_WS_WIN // ask system properties on windows
1931#ifndef SPI_GETGRADIENTCAPTIONS
1932#define SPI_GETGRADIENTCAPTIONS 0x1008
1933#endif
1934#ifndef COLOR_GRADIENTACTIVECAPTION
1935#define COLOR_GRADIENTACTIVECAPTION 27
1936#endif
1937#ifndef COLOR_GRADIENTINACTIVECAPTION
1938#define COLOR_GRADIENTINACTIVECAPTION 28
1939#endif
1940 if (QApplication::desktopSettingsAware()) {
1941 newPalette.setColor(QPalette::Active, QPalette::Highlight,
1942 colorref2qrgb(GetSysColor(COLOR_ACTIVECAPTION)));
1943 newPalette.setColor(QPalette::Inactive, QPalette::Highlight,
1944 colorref2qrgb(GetSysColor(COLOR_INACTIVECAPTION)));
1945 newPalette.setColor(QPalette::Active, QPalette::HighlightedText,
1946 colorref2qrgb(GetSysColor(COLOR_CAPTIONTEXT)));
1947 newPalette.setColor(QPalette::Inactive, QPalette::HighlightedText,
1948 colorref2qrgb(GetSysColor(COLOR_INACTIVECAPTIONTEXT)));
1949 if (QSysInfo::WindowsVersion != QSysInfo::WV_95
1950 && QSysInfo::WindowsVersion != QSysInfo::WV_NT) {
1951 colorsInitialized = true;
1952 BOOL hasGradient;
1953 QT_WA({
1954 SystemParametersInfo(SPI_GETGRADIENTCAPTIONS, 0, &hasGradient, 0);
1955 } , {
1956 SystemParametersInfoA(SPI_GETGRADIENTCAPTIONS, 0, &hasGradient, 0);
1957 });
1958 if (hasGradient) {
1959 newPalette.setColor(QPalette::Active, QPalette::Base,
1960 colorref2qrgb(GetSysColor(COLOR_GRADIENTACTIVECAPTION)));
1961 newPalette.setColor(QPalette::Inactive, QPalette::Base,
1962 colorref2qrgb(GetSysColor(COLOR_GRADIENTINACTIVECAPTION)));
1963 } else {
1964 newPalette.setColor(QPalette::Active, QPalette::Base,
1965 newPalette.color(QPalette::Active, QPalette::Highlight));
1966 newPalette.setColor(QPalette::Inactive, QPalette::Base,
1967 newPalette.color(QPalette::Inactive, QPalette::Highlight));
1968 }
1969 }
1970 }
1971#endif // Q_WS_WIN
1972 if (!colorsInitialized) {
1973 newPalette.setColor(QPalette::Active, QPalette::Highlight,
1974 newPalette.color(QPalette::Active, QPalette::Highlight));
1975 newPalette.setColor(QPalette::Active, QPalette::Base,
1976 newPalette.color(QPalette::Active, QPalette::Highlight));
1977 newPalette.setColor(QPalette::Inactive, QPalette::Highlight,
1978 newPalette.color(QPalette::Inactive, QPalette::Dark));
1979 newPalette.setColor(QPalette::Inactive, QPalette::Base,
1980 newPalette.color(QPalette::Inactive, QPalette::Dark));
1981 newPalette.setColor(QPalette::Inactive, QPalette::HighlightedText,
1982 newPalette.color(QPalette::Inactive, QPalette::Window));
1983 }
1984
1985 return newPalette;
1986}
1987
1988void QMdiSubWindowPrivate::updateActions()
1989{
1990 Qt::WindowFlags windowFlags = q_func()->windowFlags();
1991 // Hide all
1992 for (int i = 0; i < NumWindowStateActions; ++i)
1993 setVisible(WindowStateAction(i), false);
1994
1995 if (windowFlags & Qt::FramelessWindowHint)
1996 return;
1997
1998 setVisible(StayOnTopAction, true);
1999 setVisible(MoveAction, moveEnabled);
2000 setVisible(ResizeAction, resizeEnabled);
2001
2002 // CloseAction
2003 if (windowFlags & Qt::WindowSystemMenuHint)
2004 setVisible(CloseAction, true);
2005
2006 // RestoreAction
2007 if (windowFlags & (Qt::WindowMinimizeButtonHint | Qt::WindowMaximizeButtonHint))
2008 setVisible(RestoreAction, true);
2009
2010 // MinimizeAction
2011 if (windowFlags & Qt::WindowMinimizeButtonHint)
2012 setVisible(MinimizeAction, true);
2013
2014 // MaximizeAction
2015 if (windowFlags & Qt::WindowMaximizeButtonHint)
2016 setVisible(MaximizeAction, true);
2017}
2018
2019void QMdiSubWindowPrivate::setFocusWidget()
2020{
2021 Q_Q(QMdiSubWindow);
2022 if (!baseWidget) {
2023 q->setFocus();
2024 return;
2025 }
2026
2027 // This will give focus to the next child if possible, otherwise
2028 // do nothing, hence it's not possible to tab between windows with
2029 // just hitting tab (unless Qt::TabFocus is removed from the focus policy).
2030 if (focusInReason == Qt::TabFocusReason) {
2031 q->focusNextChild();
2032 return;
2033 }
2034
2035 // Same as above, but gives focus to the previous child.
2036 if (focusInReason == Qt::BacktabFocusReason) {
2037 q->focusPreviousChild();
2038 return;
2039 }
2040
2041 if (QWidget *focusWidget = baseWidget->focusWidget()) {
2042 if (!focusWidget->hasFocus() && q->isAncestorOf(focusWidget)
2043 && focusWidget->isVisible() && !q->isMinimized()
2044 && focusWidget->focusPolicy() != Qt::NoFocus) {
2045 focusWidget->setFocus();
2046 } else {
2047 q->setFocus();
2048 }
2049 return;
2050 }
2051
2052 QWidget *focusWidget = q->nextInFocusChain();
2053 while (focusWidget && focusWidget != q && focusWidget->focusPolicy() == Qt::NoFocus)
2054 focusWidget = focusWidget->nextInFocusChain();
2055 if (focusWidget && q->isAncestorOf(focusWidget))
2056 focusWidget->setFocus();
2057 else if (baseWidget->focusPolicy() != Qt::NoFocus)
2058 baseWidget->setFocus();
2059 else if (!q->hasFocus())
2060 q->setFocus();
2061}
2062
2063void QMdiSubWindowPrivate::restoreFocus()
2064{
2065 if (!restoreFocusWidget)
2066 return;
2067 if (!restoreFocusWidget->hasFocus() && q_func()->isAncestorOf(restoreFocusWidget)
2068 && restoreFocusWidget->isVisible()
2069 && restoreFocusWidget->focusPolicy() != Qt::NoFocus) {
2070 restoreFocusWidget->setFocus();
2071 }
2072 restoreFocusWidget = 0;
2073}
2074
2075/*!
2076 \internal
2077 ### Please add QEvent::WindowFlagsChange event
2078*/
2079void QMdiSubWindowPrivate::setWindowFlags(Qt::WindowFlags windowFlags)
2080{
2081 Q_Q(QMdiSubWindow);
2082 if (!q->parent()) {
2083 q->setWindowFlags(windowFlags);
2084 return;
2085 }
2086
2087 Qt::WindowFlags windowType = windowFlags & Qt::WindowType_Mask;
2088 if (windowType == Qt::Dialog || windowFlags & Qt::MSWindowsFixedSizeDialogHint)
2089 windowFlags |= Qt::WindowTitleHint | Qt::WindowSystemMenuHint;
2090
2091 // Set standard flags if none of the customize flags are set
2092 if (!(windowFlags & CustomizeWindowFlags))
2093 windowFlags |= Qt::WindowTitleHint | Qt::WindowSystemMenuHint | Qt::WindowMinMaxButtonsHint | Qt::WindowCloseButtonHint;
2094 else if (windowFlags & Qt::FramelessWindowHint && windowFlags & Qt::WindowStaysOnTopHint)
2095 windowFlags = Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint;
2096 else if (windowFlags & Qt::FramelessWindowHint)
2097 windowFlags = Qt::FramelessWindowHint;
2098
2099 windowFlags &= ~windowType;
2100 windowFlags |= Qt::SubWindow;
2101
2102#ifndef QT_NO_ACTION
2103 if (QAction *stayOnTopAction = actions[QMdiSubWindowPrivate::StayOnTopAction]) {
2104 if (windowFlags & Qt::WindowStaysOnTopHint)
2105 stayOnTopAction->setChecked(true);
2106 else
2107 stayOnTopAction->setChecked(false);
2108 }
2109#endif
2110
2111#ifndef QT_NO_SIZEGRIP
2112 if ((windowFlags & Qt::FramelessWindowHint) && sizeGrip)
2113 delete sizeGrip;
2114#endif
2115
2116 q->setWindowFlags(windowFlags);
2117 updateGeometryConstraints();
2118 updateActions();
2119 QSize currentSize = q->size();
2120 if (q->isVisible() && (currentSize.width() < internalMinimumSize.width()
2121 || currentSize.height() < internalMinimumSize.height())) {
2122 q->resize(currentSize.expandedTo(internalMinimumSize));
2123 }
2124}
2125
2126void QMdiSubWindowPrivate::setVisible(WindowStateAction action, bool visible)
2127{
2128#ifndef QT_NO_ACTION
2129 if (actions[action])
2130 actions[action]->setVisible(visible);
2131#endif
2132
2133 Q_Q(QMdiSubWindow);
2134 if (!controlContainer)
2135 controlContainer = new ControlContainer(q);
2136
2137 if (ControllerWidget *ctrlWidget = qobject_cast<ControllerWidget *>
2138 (controlContainer->controllerWidget())) {
2139 ctrlWidget->setControlVisible(action, visible);
2140 }
2141}
2142
2143#ifndef QT_NO_ACTION
2144void QMdiSubWindowPrivate::setEnabled(WindowStateAction action, bool enable)
2145{
2146 if (actions[action])
2147 actions[action]->setEnabled(enable);
2148}
2149
2150#ifndef QT_NO_MENU
2151void QMdiSubWindowPrivate::addToSystemMenu(WindowStateAction action, const QString &text,
2152 const char *slot)
2153{
2154 if (!systemMenu)
2155 return;
2156 actions[action] = systemMenu->addAction(text, q_func(), slot);
2157}
2158#endif
2159#endif // QT_NO_ACTION
2160
2161/*!
2162 \internal
2163*/
2164QSize QMdiSubWindowPrivate::iconSize() const
2165{
2166 Q_Q(const QMdiSubWindow);
2167 if (!q->parent() || q->windowFlags() & Qt::FramelessWindowHint)
2168 return QSize(-1, -1);
2169 return QSize(q->style()->pixelMetric(QStyle::PM_MdiSubWindowMinimizedWidth, 0, q), titleBarHeight());
2170}
2171
2172#ifndef QT_NO_SIZEGRIP
2173
2174/*!
2175 \internal
2176*/
2177void QMdiSubWindowPrivate::setSizeGrip(QSizeGrip *newSizeGrip)
2178{
2179 Q_Q(QMdiSubWindow);
2180 if (!newSizeGrip || sizeGrip || q->windowFlags() & Qt::FramelessWindowHint)
2181 return;
2182
2183 if (q->layout() && q->layout()->indexOf(newSizeGrip) != -1)
2184 return;
2185 newSizeGrip->setFixedSize(newSizeGrip->sizeHint());
2186 bool putSizeGripInLayout = q->layout() ? true : false;
2187#if defined(Q_WS_MAC) && !defined(QT_NO_STYLE_MAC)
2188 if (qobject_cast<QMacStyle *>(q->style()))
2189 putSizeGripInLayout = false;
2190#endif
2191 if (putSizeGripInLayout) {
2192 q->layout()->addWidget(newSizeGrip);
2193 q->layout()->setAlignment(newSizeGrip, Qt::AlignBottom | Qt::AlignRight);
2194 } else {
2195 newSizeGrip->setParent(q);
2196 newSizeGrip->move(q->isLeftToRight() ? q->width() - newSizeGrip->width() : 0,
2197 q->height() - newSizeGrip->height());
2198 sizeGrip = newSizeGrip;
2199 }
2200 newSizeGrip->raise();
2201 updateGeometryConstraints();
2202 newSizeGrip->installEventFilter(q);
2203}
2204
2205/*!
2206 \internal
2207*/
2208void QMdiSubWindowPrivate::setSizeGripVisible(bool visible) const
2209{
2210 // See if we can find any size grips
2211 QList<QSizeGrip *> sizeGrips = qFindChildren<QSizeGrip *>(q_func());
2212 foreach (QSizeGrip *grip, sizeGrips)
2213 grip->setVisible(visible);
2214}
2215
2216#endif // QT_NO_SIZEGRIP
2217
2218/*!
2219 \internal
2220*/
2221void QMdiSubWindowPrivate::updateInternalWindowTitle()
2222{
2223 Q_Q(QMdiSubWindow);
2224 if (q->isWindowModified()) {
2225 windowTitle = q->windowTitle();
2226 windowTitle.replace(QLatin1String("[*]"), QLatin1String("*"));
2227 } else {
2228 windowTitle = qt_setWindowTitle_helperHelper(q->windowTitle(), q);
2229 }
2230 q->update(0, 0, q->width(), titleBarHeight());
2231}
2232
2233/*!
2234 Constructs a new QMdiSubWindow widget. The \a parent and \a
2235 flags arguments are passed to QWidget's constructor.
2236
2237 Instead of using addSubWindow(), it is also simply possible to
2238 use setParent() when you add the subwindow to a QMdiArea.
2239
2240 Note that only \l{QMdiSubWindow}s can be set as children of
2241 QMdiArea; you cannot, for instance, write:
2242
2243 \badcode
2244 QMdiArea mdiArea;
2245 QTextEdit editor(&mdiArea); // invalid child widget
2246 \endcode
2247
2248 \sa QMdiArea::addSubWindow()
2249*/
2250QMdiSubWindow::QMdiSubWindow(QWidget *parent, Qt::WindowFlags flags)
2251 : QWidget(*new QMdiSubWindowPrivate, parent, 0)
2252{
2253 Q_D(QMdiSubWindow);
2254#ifndef QT_NO_MENU
2255 d->createSystemMenu();
2256 addActions(d->systemMenu->actions());
2257#endif
2258 d->setWindowFlags(flags);
2259 setBackgroundRole(QPalette::Window);
2260 setAutoFillBackground(true);
2261 setMouseTracking(true);
2262 setLayout(new QVBoxLayout);
2263 setFocusPolicy(Qt::StrongFocus);
2264 layout()->setMargin(0);
2265 d->updateGeometryConstraints();
2266 setAttribute(Qt::WA_Resized, false);
2267 d->titleBarPalette = d->desktopPalette();
2268 d->font = QApplication::font("QWorkspaceTitleBar");
2269 // We don't want the menu icon by default on mac.
2270#ifndef Q_WS_MAC
2271 if (windowIcon().isNull())
2272 d->menuIcon = style()->standardIcon(QStyle::SP_TitleBarMenuButton, 0, this);
2273 else
2274 d->menuIcon = windowIcon();
2275#endif
2276 connect(qApp, SIGNAL(focusChanged(QWidget *, QWidget *)),
2277 this, SLOT(_q_processFocusChanged(QWidget *, QWidget *)));
2278}
2279
2280/*!
2281 Destroys the subwindow.
2282
2283 \sa QMdiArea::removeSubWindow()
2284*/
2285QMdiSubWindow::~QMdiSubWindow()
2286{
2287 Q_D(QMdiSubWindow);
2288#ifndef QT_NO_MENUBAR
2289 d->removeButtonsFromMenuBar();
2290#endif
2291 d->setActive(false);
2292}
2293
2294/*!
2295 Sets \a widget as the internal widget of this subwindow. The
2296 internal widget is displayed in the center of the subwindow
2297 beneath the title bar.
2298
2299 QMdiSubWindow takes temporary ownership of \a widget; you do
2300 not have to delete it. Any existing internal widget will be
2301 removed and reparented to the root window.
2302
2303 \sa widget()
2304*/
2305void QMdiSubWindow::setWidget(QWidget *widget)
2306{
2307 Q_D(QMdiSubWindow);
2308 if (!widget) {
2309 d->removeBaseWidget();
2310 return;
2311 }
2312
2313 if (widget == d->baseWidget) {
2314 qWarning("QMdiSubWindow::setWidget: widget is already set");
2315 return;
2316 }
2317
2318 bool wasResized = testAttribute(Qt::WA_Resized);
2319 d->removeBaseWidget();
2320
2321 if (QLayout *layout = this->layout())
2322 layout->addWidget(widget);
2323 else
2324 widget->setParent(this);
2325
2326#ifndef QT_NO_SIZEGRIP
2327 QSizeGrip *sizeGrip = qFindChild<QSizeGrip *>(widget);
2328 if (sizeGrip)
2329 sizeGrip->installEventFilter(this);
2330 if (d->sizeGrip)
2331 d->sizeGrip->raise();
2332#endif
2333
2334 d->baseWidget = widget;
2335 d->baseWidget->installEventFilter(this);
2336
2337 d->ignoreWindowTitleChange = true;
2338 bool isWindowModified = this->isWindowModified();
2339 if (windowTitle().isEmpty()) {
2340 d->updateWindowTitle(true);
2341 isWindowModified = d->baseWidget->isWindowModified();
2342 }
2343 if (!this->isWindowModified() && isWindowModified
2344 && windowTitle().contains(QLatin1String("[*]"))) {
2345 setWindowModified(isWindowModified);
2346 }
2347 d->lastChildWindowTitle = d->baseWidget->windowTitle();
2348 d->ignoreWindowTitleChange = false;
2349
2350 if (windowIcon().isNull() && !d->baseWidget->windowIcon().isNull())
2351 setWindowIcon(d->baseWidget->windowIcon());
2352
2353 d->updateGeometryConstraints();
2354 if (!wasResized && testAttribute(Qt::WA_Resized))
2355 setAttribute(Qt::WA_Resized, false);
2356}
2357
2358/*!
2359 Returns the current internal widget.
2360
2361 \sa setWidget()
2362*/
2363QWidget *QMdiSubWindow::widget() const
2364{
2365 return d_func()->baseWidget;
2366}
2367
2368
2369/*!
2370 \internal
2371*/
2372QWidget *QMdiSubWindow::maximizedButtonsWidget() const
2373{
2374 Q_D(const QMdiSubWindow);
2375 if (isVisible() && d->controlContainer && isMaximized() && !d->drawTitleBarWhenMaximized()
2376 && !isChildOfTabbedQMdiArea(this)) {
2377 return d->controlContainer->controllerWidget();
2378 }
2379 return 0;
2380}
2381
2382/*!
2383 \internal
2384*/
2385QWidget *QMdiSubWindow::maximizedSystemMenuIconWidget() const
2386{
2387 Q_D(const QMdiSubWindow);
2388 if (isVisible() && d->controlContainer && isMaximized() && !d->drawTitleBarWhenMaximized()
2389 && !isChildOfTabbedQMdiArea(this)) {
2390 return d->controlContainer->systemMenuLabel();
2391 }
2392 return 0;
2393}
2394
2395/*!
2396 Returns true if this window is shaded; otherwise returns false.
2397
2398 A window is shaded if it is collapsed so that only the title bar is
2399 visible.
2400*/
2401bool QMdiSubWindow::isShaded() const
2402{
2403 return d_func()->isShadeMode;
2404}
2405
2406/*!
2407 If \a on is true, \a option is enabled on the subwindow; otherwise it is
2408 disabled. See SubWindowOption for the effect of each option.
2409
2410 \sa SubWindowOption, testOption()
2411*/
2412void QMdiSubWindow::setOption(SubWindowOption option, bool on)
2413{
2414 Q_D(QMdiSubWindow);
2415 if (on && !(d->options & option))
2416 d->options |= option;
2417 else if (!on && (d->options & option))
2418 d->options &= ~option;
2419
2420#ifndef QT_NO_RUBBERBAND
2421 if ((option & (RubberBandResize | RubberBandMove)) && !on && d->isInRubberBandMode)
2422 d->leaveRubberBandMode();
2423#endif
2424}
2425
2426/*!
2427 Returns true if \a option is enabled; otherwise returns false.
2428
2429 \sa SubWindowOption, setOption()
2430*/
2431bool QMdiSubWindow::testOption(SubWindowOption option) const
2432{
2433 return d_func()->options & option;
2434}
2435
2436/*!
2437 \property QMdiSubWindow::keyboardSingleStep
2438 \brief sets how far a widget should move or resize when using the
2439 keyboard arrow keys.
2440
2441 When in keyboard-interactive mode, you can use the arrow and page keys to
2442 either move or resize the window. This property controls the arrow keys.
2443 The common way to enter keyboard interactive mode is to enter the
2444 subwindow menu, and select either "resize" or "move".
2445
2446 The default keyboard single step value is 5 pixels.
2447
2448 \sa keyboardPageStep
2449*/
2450int QMdiSubWindow::keyboardSingleStep() const
2451{
2452 return d_func()->keyboardSingleStep;
2453}
2454
2455void QMdiSubWindow::setKeyboardSingleStep(int step)
2456{
2457 // Haven't done any boundary check here since negative step only
2458 // means inverted behavior, which is OK if the user want it.
2459 // A step equal to zero means "do nothing".
2460 d_func()->keyboardSingleStep = step;
2461}
2462
2463/*!
2464 \property QMdiSubWindow::keyboardPageStep
2465 \brief sets how far a widget should move or resize when using the
2466 keyboard page keys.
2467
2468 When in keyboard-interactive mode, you can use the arrow and page keys to
2469 either move or resize the window. This property controls the page
2470 keys. The common way to enter keyboard interactive mode is to enter the
2471 subwindow menu, and select either "resize" or "move".
2472
2473 The default keyboard page step value is 20 pixels.
2474
2475 \sa keyboardSingleStep
2476*/
2477int QMdiSubWindow::keyboardPageStep() const
2478{
2479 return d_func()->keyboardPageStep;
2480}
2481
2482void QMdiSubWindow::setKeyboardPageStep(int step)
2483{
2484 // Haven't done any boundary check here since negative step only
2485 // means inverted behavior, which is OK if the user want it.
2486 // A step equal to zero means "do nothing".
2487 d_func()->keyboardPageStep = step;
2488}
2489
2490#ifndef QT_NO_MENU
2491/*!
2492 Sets \a systemMenu as the current system menu for this subwindow.
2493
2494 By default, each QMdiSubWindow has a standard system menu.
2495
2496 QActions for the system menu created by QMdiSubWindow will
2497 automatically be updated depending on the current window state;
2498 e.g., the minimize action will be disabled after the window is
2499 minimized.
2500
2501 QActions added by the user are not updated by QMdiSubWindow.
2502
2503 QMdiSubWindow takes ownership of \a systemMenu; you do not have to
2504 delete it. Any existing menus will be deleted.
2505
2506 \sa systemMenu(), showSystemMenu()
2507*/
2508void QMdiSubWindow::setSystemMenu(QMenu *systemMenu)
2509{
2510 Q_D(QMdiSubWindow);
2511 if (systemMenu && systemMenu == d->systemMenu) {
2512 qWarning("QMdiSubWindow::setSystemMenu: system menu is already set");
2513 return;
2514 }
2515
2516 if (d->systemMenu) {
2517 delete d->systemMenu;
2518 d->systemMenu = 0;
2519 }
2520
2521 if (!systemMenu)
2522 return;
2523
2524 if (systemMenu->parent() != this)
2525 systemMenu->setParent(this);
2526 d->systemMenu = systemMenu;
2527}
2528
2529/*!
2530 Returns a pointer to the current system menu, or zero if no system
2531 menu is set. QMdiSubWindow provides a default system menu, but you can
2532 also set the menu with setSystemMenu().
2533
2534 \sa setSystemMenu(), showSystemMenu()
2535*/
2536QMenu *QMdiSubWindow::systemMenu() const
2537{
2538 return d_func()->systemMenu;
2539}
2540
2541/*!
2542 Shows the system menu below the system menu icon in the title bar.
2543
2544 \sa setSystemMenu(), systemMenu()
2545*/
2546void QMdiSubWindow::showSystemMenu()
2547{
2548 Q_D(QMdiSubWindow);
2549 if (!d->systemMenu)
2550 return;
2551
2552 QPoint globalPopupPos;
2553 if (QWidget *icon = maximizedSystemMenuIconWidget()) {
2554 if (isLeftToRight())
2555 globalPopupPos = icon->mapToGlobal(QPoint(0, icon->y() + icon->height()));
2556 else
2557 globalPopupPos = icon->mapToGlobal(QPoint(icon->width(), icon->y() + icon->height()));
2558 } else {
2559 if (isLeftToRight())
2560 globalPopupPos = mapToGlobal(contentsRect().topLeft());
2561 else // + QPoint(1, 0) because topRight() == QPoint(left() + width() -1, top())
2562 globalPopupPos = mapToGlobal(contentsRect().topRight()) + QPoint(1, 0);
2563 }
2564
2565 // Adjust x() with -menuwidth in reverse mode.
2566 if (isRightToLeft())
2567 globalPopupPos -= QPoint(d->systemMenu->sizeHint().width(), 0);
2568 d->systemMenu->installEventFilter(this);
2569 d->systemMenu->popup(globalPopupPos);
2570}
2571#endif // QT_NO_MENU
2572
2573/*!
2574 \since 4.4
2575
2576 Returns the area containing this sub-window, or 0 if there is none.
2577
2578 \sa QMdiArea::addSubWindow()
2579*/
2580QMdiArea *QMdiSubWindow::mdiArea() const
2581{
2582 QWidget *parent = parentWidget();
2583 while (parent) {
2584 if (QMdiArea *area = qobject_cast<QMdiArea *>(parent)) {
2585 if (area->viewport() == parentWidget())
2586 return area;
2587 }
2588 parent = parent->parentWidget();
2589 }
2590 return 0;
2591}
2592
2593/*!
2594 Calling this function makes the subwindow enter the shaded mode.
2595 When the subwindow is shaded, only the title bar is visible.
2596
2597 Although shading is not supported by all styles, this function will
2598 still show the subwindow as shaded, regardless of whether support
2599 for shading is available. However, when used with styles without
2600 shading support, the user will be unable to return from shaded mode
2601 through the user interface (e.g., through a shade button in the title
2602 bar).
2603
2604 \sa isShaded()
2605*/
2606void QMdiSubWindow::showShaded()
2607{
2608 if (!parent())
2609 return;
2610
2611 Q_D(QMdiSubWindow);
2612 // setMinimizeMode uses this function.
2613 if (!d->isShadeRequestFromMinimizeMode && isShaded())
2614 return;
2615
2616 d->isMaximizeMode = false;
2617
2618 QWidget *currentFocusWidget = QApplication::focusWidget();
2619 if (!d->restoreFocusWidget && isAncestorOf(currentFocusWidget))
2620 d->restoreFocusWidget = currentFocusWidget;
2621
2622 if (!d->isShadeRequestFromMinimizeMode) {
2623 d->isShadeMode = true;
2624 d->ensureWindowState(Qt::WindowMinimized);
2625 }
2626
2627#ifndef QT_NO_MENUBAR
2628 d->removeButtonsFromMenuBar();
2629#endif
2630
2631 // showMinimized() will reset Qt::WindowActive, which makes sense
2632 // for top level widgets, but in MDI it makes sense to have an
2633 // active window which is minimized.
2634 if (hasFocus() || isAncestorOf(currentFocusWidget))
2635 d->ensureWindowState(Qt::WindowActive);
2636
2637#ifndef QT_NO_SIZEGRIP
2638 d->setSizeGripVisible(false);
2639#endif
2640
2641 if (!d->restoreSize.isValid() || d->isShadeMode) {
2642 d->oldGeometry = geometry();
2643 d->restoreSize.setWidth(d->oldGeometry.width());
2644 d->restoreSize.setHeight(d->oldGeometry.height());
2645 }
2646
2647 // Hide the window before we change the geometry to avoid multiple resize
2648 // events and wrong window state.
2649 const bool wasVisible = isVisible();
2650 if (wasVisible)
2651 setVisible(false);
2652
2653 d->updateGeometryConstraints();
2654 // Update minimum size to internalMinimumSize if set by user.
2655 if (!minimumSize().isNull()) {
2656 d->userMinimumSize = minimumSize();
2657 setMinimumSize(d->internalMinimumSize);
2658 }
2659 resize(d->internalMinimumSize);
2660
2661 // Hide the internal widget if not already hidden by the user.
2662 if (d->baseWidget && !d->baseWidget->isHidden()) {
2663 d->baseWidget->hide();
2664 d->isWidgetHiddenByUs = true;
2665 }
2666
2667 if (wasVisible)
2668 setVisible(true);
2669
2670 d->setFocusWidget();
2671 d->resizeEnabled = false;
2672 d->moveEnabled = true;
2673 d->updateDirtyRegions();
2674 d->updateMask();
2675
2676#ifndef QT_NO_ACTION
2677 d->setEnabled(QMdiSubWindowPrivate::MinimizeAction, false);
2678 d->setEnabled(QMdiSubWindowPrivate::ResizeAction, d->resizeEnabled);
2679 d->setEnabled(QMdiSubWindowPrivate::MaximizeAction, true);
2680 d->setEnabled(QMdiSubWindowPrivate::RestoreAction, true);
2681 d->setEnabled(QMdiSubWindowPrivate::MoveAction, d->moveEnabled);
2682#endif
2683}
2684
2685/*!
2686 \reimp
2687*/
2688bool QMdiSubWindow::eventFilter(QObject *object, QEvent *event)
2689{
2690 Q_D(QMdiSubWindow);
2691 if (!object)
2692 return QWidget::eventFilter(object, event);
2693
2694#ifndef QT_NO_MENU
2695 // System menu events.
2696 if (d->systemMenu && d->systemMenu == object) {
2697 if (event->type() == QEvent::MouseButtonDblClick) {
2698 close();
2699 } else if (event->type() == QEvent::MouseMove) {
2700 QMouseEvent *mouseEvent = static_cast<QMouseEvent *>(event);
2701 d->hoveredSubControl = d->getSubControl(mapFromGlobal(mouseEvent->globalPos()));
2702 } else if (event->type() == QEvent::Hide) {
2703 d->systemMenu->removeEventFilter(this);
2704 d->activeSubControl = QStyle::SC_None;
2705 update(QRegion(0, 0, width(), d->titleBarHeight()));
2706 }
2707 return QWidget::eventFilter(object, event);
2708 }
2709#endif
2710
2711#ifndef QT_NO_SIZEGRIP
2712 if (object != d->baseWidget && parent() && qobject_cast<QSizeGrip *>(object)) {
2713 if (event->type() != QEvent::MouseButtonPress || !testOption(QMdiSubWindow::RubberBandResize))
2714 return QWidget::eventFilter(object, event);
2715 const QMouseEvent *mouseEvent = static_cast<QMouseEvent *>(event);
2716 d->mousePressPosition = parentWidget()->mapFromGlobal(mouseEvent->globalPos());
2717 d->oldGeometry = geometry();
2718 d->currentOperation = isLeftToRight() ? QMdiSubWindowPrivate::BottomRightResize
2719 : QMdiSubWindowPrivate::BottomLeftResize;
2720#ifndef QT_NO_RUBBERBAND
2721 d->enterRubberBandMode();
2722#endif
2723 return true;
2724 }
2725#endif
2726
2727 if (object != d->baseWidget && event->type() != QEvent::WindowTitleChange)
2728 return QWidget::eventFilter(object, event);
2729
2730 switch (event->type()) {
2731 case QEvent::Show:
2732 d->setActive(true);
2733 break;
2734 case QEvent::ShowToParent:
2735 if (!d->isWidgetHiddenByUs)
2736 show();
2737 break;
2738 case QEvent::WindowStateChange: {
2739 QWindowStateChangeEvent *changeEvent = static_cast<QWindowStateChangeEvent*>(event);
2740 if (changeEvent->isOverride())
2741 break;
2742 Qt::WindowStates oldState = changeEvent->oldState();
2743 Qt::WindowStates newState = d->baseWidget->windowState();
2744 if (!(oldState & Qt::WindowMinimized) && (newState & Qt::WindowMinimized))
2745 showMinimized();
2746 else if (!(oldState & Qt::WindowMaximized) && (newState & Qt::WindowMaximized))
2747 showMaximized();
2748 else if (!(newState & (Qt::WindowMaximized | Qt::WindowMinimized)))
2749 showNormal();
2750 break;
2751 }
2752 case QEvent::Enter:
2753 d->currentOperation = QMdiSubWindowPrivate::None;
2754 d->updateCursor();
2755 break;
2756 case QEvent::LayoutRequest:
2757 d->updateGeometryConstraints();
2758 break;
2759 case QEvent::WindowTitleChange:
2760 if (d->ignoreWindowTitleChange)
2761 break;
2762 if (object == d->baseWidget) {
2763 d->updateWindowTitle(true);
2764 d->lastChildWindowTitle = d->baseWidget->windowTitle();
2765#ifndef QT_NO_MENUBAR
2766 } else if (maximizedButtonsWidget() && d->controlContainer->menuBar() && d->controlContainer->menuBar()
2767 ->cornerWidget(Qt::TopRightCorner) == maximizedButtonsWidget()) {
2768 d->originalTitle = QString::null;
2769 if (d->baseWidget && d->baseWidget->windowTitle() == windowTitle())
2770 d->updateWindowTitle(true);
2771 else
2772 d->updateWindowTitle(false);
2773#endif
2774 }
2775 break;
2776 case QEvent::ModifiedChange: {
2777 if (object != d->baseWidget)
2778 break;
2779 bool windowModified = d->baseWidget->isWindowModified();
2780 if (!windowModified && d->baseWidget->windowTitle() != windowTitle())
2781 break;
2782 if (windowTitle().contains(QLatin1String("[*]")))
2783 setWindowModified(windowModified);
2784 break;
2785 }
2786 default:
2787 break;
2788 }
2789 return QWidget::eventFilter(object, event);
2790}
2791
2792/*!
2793 \reimp
2794*/
2795bool QMdiSubWindow::event(QEvent *event)
2796{
2797 Q_D(QMdiSubWindow);
2798 switch (event->type()) {
2799 case QEvent::StyleChange: {
2800 bool wasShaded = isShaded();
2801 bool wasMinimized = isMinimized();
2802 bool wasMaximized = isMaximized();
2803 ensurePolished();
2804 setContentsMargins(0, 0, 0, 0);
2805 if (wasMinimized || wasMaximized || wasShaded)
2806 showNormal();
2807 d->updateGeometryConstraints();
2808 resize(d->internalMinimumSize.expandedTo(size()));
2809 d->updateMask();
2810 d->updateDirtyRegions();
2811 if (wasShaded)
2812 showShaded();
2813 else if (wasMinimized)
2814 showMinimized();
2815 else if (wasMaximized)
2816 showMaximized();
2817 break;
2818 }
2819 case QEvent::ParentAboutToChange:
2820 d->setActive(false);
2821 break;
2822 case QEvent::ParentChange: {
2823 bool wasResized = testAttribute(Qt::WA_Resized);
2824#ifndef QT_NO_MENUBAR
2825 d->removeButtonsFromMenuBar();
2826#endif
2827 d->currentOperation = QMdiSubWindowPrivate::None;
2828 d->activeSubControl = QStyle::SC_None;
2829 d->hoveredSubControl = QStyle::SC_None;
2830#ifndef QT_NO_RUBBERBAND
2831 if (d->isInRubberBandMode)
2832 d->leaveRubberBandMode();
2833#endif
2834 d->isShadeMode = false;
2835 d->isMaximizeMode = false;
2836 d->isWidgetHiddenByUs = false;
2837 if (!parent()) {
2838#if !defined(QT_NO_SIZEGRIP) && defined(Q_WS_MAC) && !defined(QT_NO_STYLE_MAC)
2839 if (qobject_cast<QMacStyle *>(style()))
2840 delete d->sizeGrip;
2841#endif
2842 setOption(RubberBandResize, false);
2843 setOption(RubberBandMove, false);
2844 } else {
2845 d->setWindowFlags(windowFlags());
2846 }
2847 setContentsMargins(0, 0, 0, 0);
2848 d->updateGeometryConstraints();
2849 d->updateCursor();
2850 d->updateMask();
2851 d->updateDirtyRegions();
2852 d->updateActions();
2853 if (!wasResized && testAttribute(Qt::WA_Resized))
2854 setAttribute(Qt::WA_Resized, false);
2855 break;
2856 }
2857 case QEvent::WindowActivate:
2858 if (d->ignoreNextActivationEvent) {
2859 d->ignoreNextActivationEvent = false;
2860 break;
2861 }
2862 d->isExplicitlyDeactivated = false;
2863 d->setActive(true);
2864 break;
2865 case QEvent::WindowDeactivate:
2866 if (d->ignoreNextActivationEvent) {
2867 d->ignoreNextActivationEvent = false;
2868 break;
2869 }
2870 d->isExplicitlyDeactivated = true;
2871 d->setActive(false);
2872 break;
2873 case QEvent::WindowTitleChange:
2874 if (!d->ignoreWindowTitleChange)
2875 d->updateWindowTitle(false);
2876 d->updateInternalWindowTitle();
2877 break;
2878 case QEvent::ModifiedChange:
2879 if (!windowTitle().contains(QLatin1String("[*]")))
2880 break;
2881#ifndef QT_NO_MENUBAR
2882 if (maximizedButtonsWidget() && d->controlContainer->menuBar() && d->controlContainer->menuBar()
2883 ->cornerWidget(Qt::TopRightCorner) == maximizedButtonsWidget()) {
2884 window()->setWindowModified(isWindowModified());
2885 }
2886#endif // QT_NO_MENUBAR
2887 d->updateInternalWindowTitle();
2888 break;
2889 case QEvent::LayoutDirectionChange:
2890 d->updateDirtyRegions();
2891 break;
2892 case QEvent::LayoutRequest:
2893 d->updateGeometryConstraints();
2894 break;
2895 case QEvent::WindowIconChange:
2896 d->menuIcon = windowIcon();
2897 if (d->menuIcon.isNull())
2898 d->menuIcon = style()->standardIcon(QStyle::SP_TitleBarMenuButton, 0, this);
2899 if (d->controlContainer)
2900 d->controlContainer->updateWindowIcon(d->menuIcon);
2901 if (!maximizedSystemMenuIconWidget())
2902 update(0, 0, width(), d->titleBarHeight());
2903 break;
2904 case QEvent::PaletteChange:
2905 d->titleBarPalette = d->desktopPalette();
2906 break;
2907 case QEvent::FontChange:
2908 d->font = font();
2909 break;
2910#ifndef QT_NO_TOOLTIP
2911 case QEvent::ToolTip:
2912 showToolTip(static_cast<QHelpEvent *>(event), this, d->titleBarOptions(),
2913 QStyle::CC_TitleBar, d->hoveredSubControl);
2914 break;
2915#endif
2916 default:
2917 break;
2918 }
2919 return QWidget::event(event);
2920}
2921
2922/*!
2923 \reimp
2924*/
2925void QMdiSubWindow::showEvent(QShowEvent *showEvent)
2926{
2927 Q_D(QMdiSubWindow);
2928 if (!parent()) {
2929 QWidget::showEvent(showEvent);
2930 return;
2931 }
2932
2933#if !defined(QT_NO_SIZEGRIP) && defined(Q_WS_MAC) && !defined(QT_NO_STYLE_MAC)
2934 if (qobject_cast<QMacStyle *>(style()) && !d->sizeGrip
2935 && !(windowFlags() & Qt::FramelessWindowHint)) {
2936 d->setSizeGrip(new QSizeGrip(0));
2937 Q_ASSERT(d->sizeGrip);
2938 if (isMinimized())
2939 d->setSizeGripVisible(false);
2940 else
2941 d->setSizeGripVisible(true);
2942 resize(size().expandedTo(d->internalMinimumSize));
2943 }
2944#endif
2945
2946 d->updateDirtyRegions();
2947 // Show buttons in the menu bar if they're already not there.
2948 // We want to do this when QMdiSubWindow becomes visible after being hidden.
2949#ifndef QT_NO_MENUBAR
2950 if (d->controlContainer) {
2951 if (QMenuBar *menuBar = d->menuBar()) {
2952 if (menuBar->cornerWidget(Qt::TopRightCorner) != maximizedButtonsWidget())
2953 d->showButtonsInMenuBar(menuBar);
2954 }
2955 }
2956#endif
2957 d->setActive(true);
2958}
2959
2960/*!
2961 \reimp
2962*/
2963void QMdiSubWindow::hideEvent(QHideEvent * /*hideEvent*/)
2964{
2965#ifndef QT_NO_MENUBAR
2966 d_func()->removeButtonsFromMenuBar();
2967#endif
2968}
2969
2970/*!
2971 \reimp
2972*/
2973void QMdiSubWindow::changeEvent(QEvent *changeEvent)
2974{
2975 if (!parent()) {
2976 QWidget::changeEvent(changeEvent);
2977 return;
2978 }
2979
2980 if (changeEvent->type() != QEvent::WindowStateChange) {
2981 QWidget::changeEvent(changeEvent);
2982 return;
2983 }
2984
2985 QWindowStateChangeEvent *event = static_cast<QWindowStateChangeEvent *>(changeEvent);
2986 if (event->isOverride()) {
2987 event->ignore();
2988 return;
2989 }
2990
2991 Qt::WindowStates oldState = event->oldState();
2992 Qt::WindowStates newState = windowState();
2993 if (oldState == newState) {
2994 changeEvent->ignore();
2995 return;
2996 }
2997
2998 // QWidget ensures that the widget is visible _after_ setWindowState(),
2999 // but we need to ensure that the widget is visible _before_
3000 // setWindowState() returns.
3001 Q_D(QMdiSubWindow);
3002 if (!isVisible()) {
3003 d->ensureWindowState(Qt::WindowNoState);
3004 setVisible(true);
3005 }
3006
3007 if (!d->oldGeometry.isValid())
3008 d->oldGeometry = geometry();
3009
3010 if ((oldState & Qt::WindowActive) && (newState & Qt::WindowActive))
3011 d->currentOperation = QMdiSubWindowPrivate::None;
3012
3013 if (!(oldState & Qt::WindowMinimized) && (newState & Qt::WindowMinimized))
3014 d->setMinimizeMode();
3015 else if (!(oldState & Qt::WindowMaximized) && (newState & Qt::WindowMaximized))
3016 d->setMaximizeMode();
3017 else if (!(newState & (Qt::WindowMaximized | Qt::WindowMinimized)))
3018 d->setNormalMode();
3019
3020 if (d->isActive)
3021 d->ensureWindowState(Qt::WindowActive);
3022 emit windowStateChanged(oldState, windowState());
3023}
3024
3025/*!
3026 \reimp
3027*/
3028void QMdiSubWindow::closeEvent(QCloseEvent *closeEvent)
3029{
3030 Q_D(QMdiSubWindow);
3031 bool acceptClose = true;
3032 if (d->baseWidget)
3033 acceptClose = d->baseWidget->close();
3034 if (!acceptClose) {
3035 closeEvent->ignore();
3036 return;
3037 }
3038#ifndef QT_NO_MENUBAR
3039 d->removeButtonsFromMenuBar();
3040#endif
3041 d->setActive(false);
3042 if (parentWidget() && testAttribute(Qt::WA_DeleteOnClose)) {
3043 QChildEvent childRemoved(QEvent::ChildRemoved, this);
3044 QApplication::sendEvent(parentWidget(), &childRemoved);
3045 }
3046 closeEvent->accept();
3047}
3048
3049/*!
3050 \reimp
3051*/
3052void QMdiSubWindow::leaveEvent(QEvent * /*leaveEvent*/)
3053{
3054 Q_D(QMdiSubWindow);
3055 if (d->hoveredSubControl != QStyle::SC_None) {
3056 d->hoveredSubControl = QStyle::SC_None;
3057 update(QRegion(0, 0, width(), d->titleBarHeight()));
3058 }
3059}
3060
3061/*!
3062 \reimp
3063*/
3064void QMdiSubWindow::resizeEvent(QResizeEvent *resizeEvent)
3065{
3066 Q_D(QMdiSubWindow);
3067#ifndef QT_NO_SIZEGRIP
3068 if (d->sizeGrip) {
3069 d->sizeGrip->move(isLeftToRight() ? width() - d->sizeGrip->width() : 0,
3070 height() - d->sizeGrip->height());
3071 }
3072#endif
3073
3074 if (!parent()) {
3075 QWidget::resizeEvent(resizeEvent);
3076 return;
3077 }
3078
3079 if (d->isMaximizeMode)
3080 d->ensureWindowState(Qt::WindowMaximized);
3081
3082 d->updateMask();
3083 if (!isVisible())
3084 return;
3085
3086 if (d->resizeTimerId <= 0)
3087 d->cachedStyleOptions = d->titleBarOptions();
3088 else
3089 killTimer(d->resizeTimerId);
3090 d->resizeTimerId = startTimer(200);
3091}
3092
3093/*!
3094 \reimp
3095*/
3096void QMdiSubWindow::timerEvent(QTimerEvent *timerEvent)
3097{
3098 Q_D(QMdiSubWindow);
3099 if (timerEvent->timerId() == d->resizeTimerId) {
3100 killTimer(d->resizeTimerId);
3101 d->resizeTimerId = -1;
3102 d->updateDirtyRegions();
3103 }
3104}
3105
3106/*!
3107 \reimp
3108*/
3109void QMdiSubWindow::moveEvent(QMoveEvent *moveEvent)
3110{
3111 if (!parent()) {
3112 QWidget::moveEvent(moveEvent);
3113 return;
3114 }
3115
3116 Q_D(QMdiSubWindow);
3117 if (d->isMaximizeMode)
3118 d->ensureWindowState(Qt::WindowMaximized);
3119}
3120
3121/*!
3122 \reimp
3123*/
3124void QMdiSubWindow::paintEvent(QPaintEvent *paintEvent)
3125{
3126 if (!parent() || (windowFlags() & Qt::FramelessWindowHint)) {
3127 QWidget::paintEvent(paintEvent);
3128 return;
3129 }
3130
3131 Q_D(QMdiSubWindow);
3132 if (isMaximized() && !d->drawTitleBarWhenMaximized())
3133 return;
3134
3135 if (d->resizeTimerId != -1) {
3136 // Only update the style option rect and the window title.
3137 int border = d->hasBorder(d->cachedStyleOptions) ? 4 : 0;
3138 int titleBarHeight = d->titleBarHeight(d->cachedStyleOptions);
3139 titleBarHeight -= isMinimized() ? 2 * border : border;
3140 d->cachedStyleOptions.rect = QRect(border, border, width() - 2 * border, titleBarHeight);
3141 if (!d->windowTitle.isEmpty()) {
3142 int width = style()->subControlRect(QStyle::CC_TitleBar, &d->cachedStyleOptions,
3143 QStyle::SC_TitleBarLabel, this).width();
3144 d->cachedStyleOptions.text = d->cachedStyleOptions.fontMetrics
3145 .elidedText(d->windowTitle, Qt::ElideRight, width);
3146 }
3147 } else {
3148 // Force full update.
3149 d->cachedStyleOptions = d->titleBarOptions();
3150 }
3151
3152 QStylePainter painter(this);
3153 if (!d->windowTitle.isEmpty())
3154 painter.setFont(d->font);
3155 painter.drawComplexControl(QStyle::CC_TitleBar, d->cachedStyleOptions);
3156
3157 if (isMinimized() && !d->hasBorder(d->cachedStyleOptions))
3158 return;
3159
3160 QStyleOptionFrame frameOptions;
3161 frameOptions.initFrom(this);
3162 frameOptions.lineWidth = style()->pixelMetric(QStyle::PM_MdiSubWindowFrameWidth, 0, this);
3163 if (d->isActive)
3164 frameOptions.state |= QStyle::State_Active;
3165 else
3166 frameOptions.state &= ~QStyle::State_Active;
3167
3168 // ### Ensure that we do not require setting the cliprect for 4.4
3169 if (!isMinimized() && !d->hasBorder(d->cachedStyleOptions))
3170 painter.setClipRect(rect().adjusted(0, d->titleBarHeight(d->cachedStyleOptions), 0, 0));
3171 if (!isMinimized() || d->hasBorder(d->cachedStyleOptions))
3172 painter.drawPrimitive(QStyle::PE_FrameWindow, frameOptions);
3173}
3174
3175/*!
3176 \reimp
3177*/
3178void QMdiSubWindow::mousePressEvent(QMouseEvent *mouseEvent)
3179{
3180 if (!parent()) {
3181 QWidget::mousePressEvent(mouseEvent);
3182 return;
3183 }
3184
3185 Q_D(QMdiSubWindow);
3186 if (d->isInInteractiveMode)
3187 d->leaveInteractiveMode();
3188#ifndef QT_NO_RUBBERBAND
3189 if (d->isInRubberBandMode)
3190 d->leaveRubberBandMode();
3191#endif
3192
3193 if (mouseEvent->button() != Qt::LeftButton) {
3194 mouseEvent->ignore();
3195 return;
3196 }
3197
3198 if (d->currentOperation != QMdiSubWindowPrivate::None) {
3199 d->updateCursor();
3200 d->mousePressPosition = mapToParent(mouseEvent->pos());
3201 if (d->resizeEnabled || d->moveEnabled)
3202 d->oldGeometry = geometry();
3203#ifndef QT_NO_RUBBERBAND
3204 if ((testOption(QMdiSubWindow::RubberBandResize) && d->isResizeOperation())
3205 || (testOption(QMdiSubWindow::RubberBandMove) && d->isMoveOperation())) {
3206 d->enterRubberBandMode();
3207 }
3208#endif
3209 return;
3210 }
3211
3212 d->activeSubControl = d->hoveredSubControl;
3213#ifndef QT_NO_MENU
3214 if (d->activeSubControl == QStyle::SC_TitleBarSysMenu)
3215 showSystemMenu();
3216 else
3217#endif
3218 update(QRegion(0, 0, width(), d->titleBarHeight()));
3219}
3220
3221/*!
3222 \reimp
3223*/
3224void QMdiSubWindow::mouseDoubleClickEvent(QMouseEvent *mouseEvent)
3225{
3226 if (!parent()) {
3227 QWidget::mouseDoubleClickEvent(mouseEvent);
3228 return;
3229 }
3230
3231 if (mouseEvent->button() != Qt::LeftButton) {
3232 mouseEvent->ignore();
3233 return;
3234 }
3235
3236 Q_D(QMdiSubWindow);
3237 if (!d->isMoveOperation()) {
3238#ifndef QT_NO_MENU
3239 if (d->hoveredSubControl == QStyle::SC_TitleBarSysMenu)
3240 close();
3241#endif
3242 return;
3243 }
3244
3245 Qt::WindowFlags flags = windowFlags();
3246 if (isMinimized()) {
3247 if ((isShaded() && (flags & Qt::WindowShadeButtonHint))
3248 || (flags & Qt::WindowMinimizeButtonHint)) {
3249 showNormal();
3250 }
3251 return;
3252 }
3253
3254 if (isMaximized()) {
3255 if (flags & Qt::WindowMaximizeButtonHint)
3256 showNormal();
3257 return;
3258 }
3259
3260 if (flags & Qt::WindowShadeButtonHint)
3261 showShaded();
3262 else if (flags & Qt::WindowMaximizeButtonHint)
3263 showMaximized();
3264}
3265
3266/*!
3267 \reimp
3268*/
3269void QMdiSubWindow::mouseReleaseEvent(QMouseEvent *mouseEvent)
3270{
3271 if (!parent()) {
3272 QWidget::mouseReleaseEvent(mouseEvent);
3273 return;
3274 }
3275
3276 if (mouseEvent->button() != Qt::LeftButton) {
3277 mouseEvent->ignore();
3278 return;
3279 }
3280
3281 Q_D(QMdiSubWindow);
3282 if (d->currentOperation != QMdiSubWindowPrivate::None) {
3283#ifndef QT_NO_RUBBERBAND
3284 if (d->isInRubberBandMode && !d->isInInteractiveMode)
3285 d->leaveRubberBandMode();
3286#endif
3287 if (d->resizeEnabled || d->moveEnabled)
3288 d->oldGeometry = geometry();
3289 }
3290
3291 d->currentOperation = d->getOperation(mouseEvent->pos());
3292 d->updateCursor();
3293
3294 d->hoveredSubControl = d->getSubControl(mouseEvent->pos());
3295 if (d->activeSubControl != QStyle::SC_None
3296 && d->activeSubControl == d->hoveredSubControl) {
3297 d->processClickedSubControl();
3298 }
3299 d->activeSubControl = QStyle::SC_None;
3300 update(QRegion(0, 0, width(), d->titleBarHeight()));
3301}
3302
3303/*!
3304 \reimp
3305*/
3306void QMdiSubWindow::mouseMoveEvent(QMouseEvent *mouseEvent)
3307{
3308 if (!parent()) {
3309 QWidget::mouseMoveEvent(mouseEvent);
3310 return;
3311 }
3312
3313 Q_D(QMdiSubWindow);
3314 // No update needed if we're in a move/resize operation.
3315 if (!d->isMoveOperation() && !d->isResizeOperation()) {
3316 // Find previous and current hover region.
3317 const QStyleOptionTitleBar options = d->titleBarOptions();
3318 QStyle::SubControl oldHover = d->hoveredSubControl;
3319 d->hoveredSubControl = d->getSubControl(mouseEvent->pos());
3320 QRegion hoverRegion;
3321 if (isHoverControl(oldHover) && oldHover != d->hoveredSubControl)
3322 hoverRegion += style()->subControlRect(QStyle::CC_TitleBar, &options, oldHover, this);
3323 if (isHoverControl(d->hoveredSubControl) && d->hoveredSubControl != oldHover) {
3324 hoverRegion += style()->subControlRect(QStyle::CC_TitleBar, &options,
3325 d->hoveredSubControl, this);
3326 }
3327#if defined(Q_WS_MAC) && !defined(QT_NO_STYLE_MAC)
3328 if (qobject_cast<QMacStyle *>(style()) && !hoverRegion.isEmpty())
3329 hoverRegion += QRegion(0, 0, width(), d->titleBarHeight(options));
3330#endif
3331 if (!hoverRegion.isEmpty())
3332 update(hoverRegion);
3333 }
3334
3335 if ((mouseEvent->buttons() & Qt::LeftButton) || d->isInInteractiveMode) {
3336 if ((d->isResizeOperation() && d->resizeEnabled) || (d->isMoveOperation() && d->moveEnabled))
3337 d->setNewGeometry(mapToParent(mouseEvent->pos()));
3338 return;
3339 }
3340
3341 // Do not resize/move if not allowed.
3342 d->currentOperation = d->getOperation(mouseEvent->pos());
3343 if ((d->isResizeOperation() && !d->resizeEnabled) || (d->isMoveOperation() && !d->moveEnabled))
3344 d->currentOperation = QMdiSubWindowPrivate::None;
3345 d->updateCursor();
3346}
3347
3348/*!
3349 \reimp
3350*/
3351void QMdiSubWindow::keyPressEvent(QKeyEvent *keyEvent)
3352{
3353 Q_D(QMdiSubWindow);
3354 if (!d->isInInteractiveMode || !parent()) {
3355 keyEvent->ignore();
3356 return;
3357 }
3358
3359 QPoint delta;
3360 switch (keyEvent->key()) {
3361 case Qt::Key_Right:
3362 if (keyEvent->modifiers() & Qt::ShiftModifier)
3363 delta = QPoint(d->keyboardPageStep, 0);
3364 else
3365 delta = QPoint(d->keyboardSingleStep, 0);
3366 break;
3367 case Qt::Key_Up:
3368 if (keyEvent->modifiers() & Qt::ShiftModifier)
3369 delta = QPoint(0, -d->keyboardPageStep);
3370 else
3371 delta = QPoint(0, -d->keyboardSingleStep);
3372 break;
3373 case Qt::Key_Left:
3374 if (keyEvent->modifiers() & Qt::ShiftModifier)
3375 delta = QPoint(-d->keyboardPageStep, 0);
3376 else
3377 delta = QPoint(-d->keyboardSingleStep, 0);
3378 break;
3379 case Qt::Key_Down:
3380 if (keyEvent->modifiers() & Qt::ShiftModifier)
3381 delta = QPoint(0, d->keyboardPageStep);
3382 else
3383 delta = QPoint(0, d->keyboardSingleStep);
3384 break;
3385 case Qt::Key_Escape:
3386 case Qt::Key_Return:
3387 case Qt::Key_Enter:
3388 d->leaveInteractiveMode();
3389 return;
3390 default:
3391 keyEvent->ignore();
3392 return;
3393 }
3394
3395#ifndef QT_NO_CURSOR
3396 QPoint newPosition = parentWidget()->mapFromGlobal(cursor().pos() + delta);
3397 QRect oldGeometry =
3398#ifndef QT_NO_RUBBERBAND
3399 d->isInRubberBandMode ? d->rubberBand->geometry() :
3400#endif
3401 geometry();
3402 d->setNewGeometry(newPosition);
3403 QRect currentGeometry =
3404#ifndef QT_NO_RUBBERBAND
3405 d->isInRubberBandMode ? d->rubberBand->geometry() :
3406#endif
3407 geometry();
3408 if (currentGeometry == oldGeometry)
3409 return;
3410
3411 // Update cursor position
3412
3413 QPoint actualDelta;
3414 if (d->isMoveOperation()) {
3415 actualDelta = QPoint(currentGeometry.x() - oldGeometry.x(),
3416 currentGeometry.y() - oldGeometry.y());
3417 } else {
3418 int dx = isLeftToRight() ? currentGeometry.width() - oldGeometry.width()
3419 : currentGeometry.x() - oldGeometry.x();
3420 actualDelta = QPoint(dx, currentGeometry.height() - oldGeometry.height());
3421 }
3422
3423 // Adjust in case we weren't able to move as long as wanted.
3424 if (actualDelta != delta)
3425 newPosition += (actualDelta - delta);
3426 cursor().setPos(parentWidget()->mapToGlobal(newPosition));
3427#endif
3428}
3429
3430#ifndef QT_NO_CONTEXTMENU
3431/*!
3432 \reimp
3433*/
3434void QMdiSubWindow::contextMenuEvent(QContextMenuEvent *contextMenuEvent)
3435{
3436 Q_D(QMdiSubWindow);
3437 if (!d->systemMenu) {
3438 contextMenuEvent->ignore();
3439 return;
3440 }
3441
3442 if (d->hoveredSubControl == QStyle::SC_TitleBarSysMenu
3443 || d->getRegion(QMdiSubWindowPrivate::Move).contains(contextMenuEvent->pos())) {
3444 d->systemMenu->exec(contextMenuEvent->globalPos());
3445 } else {
3446 contextMenuEvent->ignore();
3447 }
3448}
3449#endif // QT_NO_CONTEXTMENU
3450
3451/*!
3452 \reimp
3453*/
3454void QMdiSubWindow::focusInEvent(QFocusEvent *focusInEvent)
3455{
3456 d_func()->focusInReason = focusInEvent->reason();
3457}
3458
3459/*!
3460 \reimp
3461*/
3462void QMdiSubWindow::focusOutEvent(QFocusEvent * /*focusOutEvent*/)
3463{
3464 // To avoid update() in QWidget::focusOutEvent.
3465}
3466
3467/*!
3468 \reimp
3469*/
3470void QMdiSubWindow::childEvent(QChildEvent *childEvent)
3471{
3472 if (childEvent->type() != QEvent::ChildPolished)
3473 return;
3474#ifndef QT_NO_SIZEGRIP
3475 if (QSizeGrip *sizeGrip = qobject_cast<QSizeGrip *>(childEvent->child()))
3476 d_func()->setSizeGrip(sizeGrip);
3477#endif
3478}
3479
3480/*!
3481 \reimp
3482*/
3483QSize QMdiSubWindow::sizeHint() const
3484{
3485 Q_D(const QMdiSubWindow);
3486 int margin, minWidth;
3487 d->sizeParameters(&margin, &minWidth);
3488 QSize size(2 * margin, d->titleBarHeight() + margin);
3489 if (d->baseWidget && d->baseWidget->sizeHint().isValid())
3490 size += d->baseWidget->sizeHint();
3491 return size.expandedTo(minimumSizeHint());
3492}
3493
3494/*!
3495 \reimp
3496*/
3497QSize QMdiSubWindow::minimumSizeHint() const
3498{
3499 Q_D(const QMdiSubWindow);
3500 if (isVisible())
3501 ensurePolished();
3502
3503 // Minimized window.
3504 if (parent() && isMinimized() && !isShaded())
3505 return d->iconSize();
3506
3507 // Calculate window decoration.
3508 int margin, minWidth;
3509 d->sizeParameters(&margin, &minWidth);
3510 int decorationHeight = margin + d->titleBarHeight();
3511 int minHeight = decorationHeight;
3512
3513 // Shaded window.
3514 if (parent() && isShaded())
3515 return QSize(qMax(minWidth, width()), d->titleBarHeight());
3516
3517 // Content
3518 if (layout()) {
3519 QSize minLayoutSize = layout()->minimumSize();
3520 if (minLayoutSize.isValid()) {
3521 minWidth = qMax(minWidth, minLayoutSize.width() + 2 * margin);
3522 minHeight += minLayoutSize.height();
3523 }
3524 } else if (d->baseWidget && d->baseWidget->isVisible()) {
3525 QSize minBaseWidgetSize = d->baseWidget->minimumSizeHint();
3526 if (minBaseWidgetSize.isValid()) {
3527 minWidth = qMax(minWidth, minBaseWidgetSize.width() + 2 * margin);
3528 minHeight += minBaseWidgetSize.height();
3529 }
3530 }
3531
3532#ifndef QT_NO_SIZEGRIP
3533 // SizeGrip
3534 int sizeGripHeight = 0;
3535 if (d->sizeGrip && d->sizeGrip->isVisibleTo(const_cast<QMdiSubWindow *>(this)))
3536 sizeGripHeight = d->sizeGrip->height();
3537#if defined(Q_WS_MAC) && !defined(QT_NO_STYLE_MAC)
3538 else if (parent() && qobject_cast<QMacStyle *>(style()) && !d->sizeGrip)
3539 sizeGripHeight = style()->pixelMetric(QStyle::PM_SizeGripSize, 0, this);
3540#endif
3541 minHeight = qMax(minHeight, decorationHeight + sizeGripHeight);
3542#endif
3543
3544 return QSize(minWidth, minHeight).expandedTo(QApplication::globalStrut());
3545}
3546
3547QT_END_NAMESPACE
3548
3549#include "moc_qmdisubwindow.cpp"
3550#include "qmdisubwindow.moc"
3551
3552#endif //QT_NO_MDIAREA
Note: See TracBrowser for help on using the repository browser.