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

Last change on this file since 754 was 651, checked in by Dmitry A. Kuminov, 15 years ago

trunk: Merged in qt 4.6.2 sources.

File size: 106.8 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation ([email protected])
6**
7** This file is part of the QtGui module of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial Usage
11** Licensees holding valid Qt Commercial licenses may use this file in
12** accordance with the Qt Commercial License Agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and Nokia.
15**
16** GNU Lesser General Public License Usage
17** Alternatively, this file may be used under the terms of the GNU Lesser
18** General Public License version 2.1 as published by the Free Software
19** Foundation and appearing in the file LICENSE.LGPL included in the
20** packaging of this file. Please review the following information to
21** ensure the GNU Lesser General Public License version 2.1 requirements
22** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23**
24** In addition, as a special exception, Nokia gives you certain additional
25** rights. These rights are described in the Nokia Qt LGPL Exception
26** version 1.1, included in the file LGPL_EXCEPTION.txt in this 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 have questions regarding the use of this file, please contact
37** Nokia at [email protected].
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 mainwindow-classes
48
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 (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]->setShortcuts(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 (!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 (!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 (!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(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(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(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(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 (!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 (!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 (!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_WS_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(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
1950 colorsInitialized = true;
1951 BOOL hasGradient = false;
1952 SystemParametersInfo(SPI_GETGRADIENTCAPTIONS, 0, &hasGradient, 0);
1953
1954 if (hasGradient) {
1955 newPalette.setColor(QPalette::Active, QPalette::Base,
1956 colorref2qrgb(GetSysColor(COLOR_GRADIENTACTIVECAPTION)));
1957 newPalette.setColor(QPalette::Inactive, QPalette::Base,
1958 colorref2qrgb(GetSysColor(COLOR_GRADIENTINACTIVECAPTION)));
1959 } else {
1960 newPalette.setColor(QPalette::Active, QPalette::Base,
1961 newPalette.color(QPalette::Active, QPalette::Highlight));
1962 newPalette.setColor(QPalette::Inactive, QPalette::Base,
1963 newPalette.color(QPalette::Inactive, QPalette::Highlight));
1964 }
1965 }
1966#endif // Q_WS_WIN
1967 if (!colorsInitialized) {
1968 newPalette.setColor(QPalette::Active, QPalette::Highlight,
1969 newPalette.color(QPalette::Active, QPalette::Highlight));
1970 newPalette.setColor(QPalette::Active, QPalette::Base,
1971 newPalette.color(QPalette::Active, QPalette::Highlight));
1972 newPalette.setColor(QPalette::Inactive, QPalette::Highlight,
1973 newPalette.color(QPalette::Inactive, QPalette::Dark));
1974 newPalette.setColor(QPalette::Inactive, QPalette::Base,
1975 newPalette.color(QPalette::Inactive, QPalette::Dark));
1976 newPalette.setColor(QPalette::Inactive, QPalette::HighlightedText,
1977 newPalette.color(QPalette::Inactive, QPalette::Window));
1978 }
1979
1980 return newPalette;
1981}
1982
1983void QMdiSubWindowPrivate::updateActions()
1984{
1985 Qt::WindowFlags windowFlags = q_func()->windowFlags();
1986 // Hide all
1987 for (int i = 0; i < NumWindowStateActions; ++i)
1988 setVisible(WindowStateAction(i), false);
1989
1990 if (windowFlags & Qt::FramelessWindowHint)
1991 return;
1992
1993 setVisible(StayOnTopAction, true);
1994 setVisible(MoveAction, moveEnabled);
1995 setVisible(ResizeAction, resizeEnabled);
1996
1997 // CloseAction
1998 if (windowFlags & Qt::WindowSystemMenuHint)
1999 setVisible(CloseAction, true);
2000
2001 // RestoreAction
2002 if (windowFlags & (Qt::WindowMinimizeButtonHint | Qt::WindowMaximizeButtonHint))
2003 setVisible(RestoreAction, true);
2004
2005 // MinimizeAction
2006 if (windowFlags & Qt::WindowMinimizeButtonHint)
2007 setVisible(MinimizeAction, true);
2008
2009 // MaximizeAction
2010 if (windowFlags & Qt::WindowMaximizeButtonHint)
2011 setVisible(MaximizeAction, true);
2012}
2013
2014void QMdiSubWindowPrivate::setFocusWidget()
2015{
2016 Q_Q(QMdiSubWindow);
2017 if (!baseWidget) {
2018 q->setFocus();
2019 return;
2020 }
2021
2022 // This will give focus to the next child if possible, otherwise
2023 // do nothing, hence it's not possible to tab between windows with
2024 // just hitting tab (unless Qt::TabFocus is removed from the focus policy).
2025 if (focusInReason == Qt::TabFocusReason) {
2026 q->focusNextChild();
2027 return;
2028 }
2029
2030 // Same as above, but gives focus to the previous child.
2031 if (focusInReason == Qt::BacktabFocusReason) {
2032 q->focusPreviousChild();
2033 return;
2034 }
2035
2036 if (QWidget *focusWidget = baseWidget->focusWidget()) {
2037 if (!focusWidget->hasFocus() && q->isAncestorOf(focusWidget)
2038 && focusWidget->isVisible() && !q->isMinimized()
2039 && focusWidget->focusPolicy() != Qt::NoFocus) {
2040 focusWidget->setFocus();
2041 } else {
2042 q->setFocus();
2043 }
2044 return;
2045 }
2046
2047 QWidget *focusWidget = q->nextInFocusChain();
2048 while (focusWidget && focusWidget != q && focusWidget->focusPolicy() == Qt::NoFocus)
2049 focusWidget = focusWidget->nextInFocusChain();
2050 if (focusWidget && q->isAncestorOf(focusWidget))
2051 focusWidget->setFocus();
2052 else if (baseWidget->focusPolicy() != Qt::NoFocus)
2053 baseWidget->setFocus();
2054 else if (!q->hasFocus())
2055 q->setFocus();
2056}
2057
2058void QMdiSubWindowPrivate::restoreFocus()
2059{
2060 if (!restoreFocusWidget)
2061 return;
2062 if (!restoreFocusWidget->hasFocus() && q_func()->isAncestorOf(restoreFocusWidget)
2063 && restoreFocusWidget->isVisible()
2064 && restoreFocusWidget->focusPolicy() != Qt::NoFocus) {
2065 restoreFocusWidget->setFocus();
2066 }
2067 restoreFocusWidget = 0;
2068}
2069
2070/*!
2071 \internal
2072 ### Please add QEvent::WindowFlagsChange event
2073*/
2074void QMdiSubWindowPrivate::setWindowFlags(Qt::WindowFlags windowFlags)
2075{
2076 Q_Q(QMdiSubWindow);
2077 if (!parent) {
2078 q->setWindowFlags(windowFlags);
2079 return;
2080 }
2081
2082 Qt::WindowFlags windowType = windowFlags & Qt::WindowType_Mask;
2083 if (windowType == Qt::Dialog || windowFlags & Qt::MSWindowsFixedSizeDialogHint)
2084 windowFlags |= Qt::WindowTitleHint | Qt::WindowSystemMenuHint;
2085
2086 // Set standard flags if none of the customize flags are set
2087 if (!(windowFlags & CustomizeWindowFlags))
2088 windowFlags |= Qt::WindowTitleHint | Qt::WindowSystemMenuHint | Qt::WindowMinMaxButtonsHint | Qt::WindowCloseButtonHint;
2089 else if (windowFlags & Qt::FramelessWindowHint && windowFlags & Qt::WindowStaysOnTopHint)
2090 windowFlags = Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint;
2091 else if (windowFlags & Qt::FramelessWindowHint)
2092 windowFlags = Qt::FramelessWindowHint;
2093
2094 windowFlags &= ~windowType;
2095 windowFlags |= Qt::SubWindow;
2096
2097#ifndef QT_NO_ACTION
2098 if (QAction *stayOnTopAction = actions[QMdiSubWindowPrivate::StayOnTopAction]) {
2099 if (windowFlags & Qt::WindowStaysOnTopHint)
2100 stayOnTopAction->setChecked(true);
2101 else
2102 stayOnTopAction->setChecked(false);
2103 }
2104#endif
2105
2106#ifndef QT_NO_SIZEGRIP
2107 if ((windowFlags & Qt::FramelessWindowHint) && sizeGrip)
2108 delete sizeGrip;
2109#endif
2110
2111 q->setWindowFlags(windowFlags);
2112 updateGeometryConstraints();
2113 updateActions();
2114 QSize currentSize = q->size();
2115 if (q->isVisible() && (currentSize.width() < internalMinimumSize.width()
2116 || currentSize.height() < internalMinimumSize.height())) {
2117 q->resize(currentSize.expandedTo(internalMinimumSize));
2118 }
2119}
2120
2121void QMdiSubWindowPrivate::setVisible(WindowStateAction action, bool visible)
2122{
2123#ifndef QT_NO_ACTION
2124 if (actions[action])
2125 actions[action]->setVisible(visible);
2126#endif
2127
2128 Q_Q(QMdiSubWindow);
2129 if (!controlContainer)
2130 controlContainer = new ControlContainer(q);
2131
2132 if (ControllerWidget *ctrlWidget = qobject_cast<ControllerWidget *>
2133 (controlContainer->controllerWidget())) {
2134 ctrlWidget->setControlVisible(action, visible);
2135 }
2136}
2137
2138#ifndef QT_NO_ACTION
2139void QMdiSubWindowPrivate::setEnabled(WindowStateAction action, bool enable)
2140{
2141 if (actions[action])
2142 actions[action]->setEnabled(enable);
2143}
2144
2145#ifndef QT_NO_MENU
2146void QMdiSubWindowPrivate::addToSystemMenu(WindowStateAction action, const QString &text,
2147 const char *slot)
2148{
2149 if (!systemMenu)
2150 return;
2151 actions[action] = systemMenu->addAction(text, q_func(), slot);
2152}
2153#endif
2154#endif // QT_NO_ACTION
2155
2156/*!
2157 \internal
2158*/
2159QSize QMdiSubWindowPrivate::iconSize() const
2160{
2161 Q_Q(const QMdiSubWindow);
2162 if (!parent || q->windowFlags() & Qt::FramelessWindowHint)
2163 return QSize(-1, -1);
2164 return QSize(q->style()->pixelMetric(QStyle::PM_MdiSubWindowMinimizedWidth, 0, q), titleBarHeight());
2165}
2166
2167#ifndef QT_NO_SIZEGRIP
2168
2169/*!
2170 \internal
2171*/
2172void QMdiSubWindowPrivate::setSizeGrip(QSizeGrip *newSizeGrip)
2173{
2174 Q_Q(QMdiSubWindow);
2175 if (!newSizeGrip || sizeGrip || q->windowFlags() & Qt::FramelessWindowHint)
2176 return;
2177
2178 if (layout && layout->indexOf(newSizeGrip) != -1)
2179 return;
2180 newSizeGrip->setFixedSize(newSizeGrip->sizeHint());
2181 bool putSizeGripInLayout = layout ? true : false;
2182#if defined(Q_WS_MAC) && !defined(QT_NO_STYLE_MAC)
2183 if (qobject_cast<QMacStyle *>(q->style()))
2184 putSizeGripInLayout = false;
2185#endif
2186 if (putSizeGripInLayout) {
2187 layout->addWidget(newSizeGrip);
2188 layout->setAlignment(newSizeGrip, Qt::AlignBottom | Qt::AlignRight);
2189 } else {
2190 newSizeGrip->setParent(q);
2191 newSizeGrip->move(q->isLeftToRight() ? q->width() - newSizeGrip->width() : 0,
2192 q->height() - newSizeGrip->height());
2193 sizeGrip = newSizeGrip;
2194 }
2195 newSizeGrip->raise();
2196 updateGeometryConstraints();
2197 newSizeGrip->installEventFilter(q);
2198}
2199
2200/*!
2201 \internal
2202*/
2203void QMdiSubWindowPrivate::setSizeGripVisible(bool visible) const
2204{
2205 // See if we can find any size grips
2206 QList<QSizeGrip *> sizeGrips = qFindChildren<QSizeGrip *>(q_func());
2207 foreach (QSizeGrip *grip, sizeGrips)
2208 grip->setVisible(visible);
2209}
2210
2211#endif // QT_NO_SIZEGRIP
2212
2213/*!
2214 \internal
2215*/
2216void QMdiSubWindowPrivate::updateInternalWindowTitle()
2217{
2218 Q_Q(QMdiSubWindow);
2219 if (q->isWindowModified()) {
2220 windowTitle = q->windowTitle();
2221 windowTitle.replace(QLatin1String("[*]"), QLatin1String("*"));
2222 } else {
2223 windowTitle = qt_setWindowTitle_helperHelper(q->windowTitle(), q);
2224 }
2225 q->update(0, 0, q->width(), titleBarHeight());
2226}
2227
2228/*!
2229 Constructs a new QMdiSubWindow widget. The \a parent and \a
2230 flags arguments are passed to QWidget's constructor.
2231
2232 Instead of using addSubWindow(), it is also simply possible to
2233 use setParent() when you add the subwindow to a QMdiArea.
2234
2235 Note that only \l{QMdiSubWindow}s can be set as children of
2236 QMdiArea; you cannot, for instance, write:
2237
2238 \badcode
2239 QMdiArea mdiArea;
2240 QTextEdit editor(&mdiArea); // invalid child widget
2241 \endcode
2242
2243 \sa QMdiArea::addSubWindow()
2244*/
2245QMdiSubWindow::QMdiSubWindow(QWidget *parent, Qt::WindowFlags flags)
2246 : QWidget(*new QMdiSubWindowPrivate, parent, 0)
2247{
2248 Q_D(QMdiSubWindow);
2249#ifndef QT_NO_MENU
2250 d->createSystemMenu();
2251 addActions(d->systemMenu->actions());
2252#endif
2253 d->setWindowFlags(flags);
2254 setBackgroundRole(QPalette::Window);
2255 setAutoFillBackground(true);
2256 setMouseTracking(true);
2257 setLayout(new QVBoxLayout);
2258 setFocusPolicy(Qt::StrongFocus);
2259 layout()->setMargin(0);
2260 d->updateGeometryConstraints();
2261 setAttribute(Qt::WA_Resized, false);
2262 d->titleBarPalette = d->desktopPalette();
2263 d->font = QApplication::font("QWorkspaceTitleBar");
2264 // We don't want the menu icon by default on mac.
2265#ifndef Q_WS_MAC
2266 if (windowIcon().isNull())
2267 d->menuIcon = style()->standardIcon(QStyle::SP_TitleBarMenuButton, 0, this);
2268 else
2269 d->menuIcon = windowIcon();
2270#endif
2271 connect(qApp, SIGNAL(focusChanged(QWidget*,QWidget*)),
2272 this, SLOT(_q_processFocusChanged(QWidget*,QWidget*)));
2273}
2274
2275/*!
2276 Destroys the subwindow.
2277
2278 \sa QMdiArea::removeSubWindow()
2279*/
2280QMdiSubWindow::~QMdiSubWindow()
2281{
2282 Q_D(QMdiSubWindow);
2283#ifndef QT_NO_MENUBAR
2284 d->removeButtonsFromMenuBar();
2285#endif
2286 d->setActive(false);
2287}
2288
2289/*!
2290 Sets \a widget as the internal widget of this subwindow. The
2291 internal widget is displayed in the center of the subwindow
2292 beneath the title bar.
2293
2294 QMdiSubWindow takes temporary ownership of \a widget; you do
2295 not have to delete it. Any existing internal widget will be
2296 removed and reparented to the root window.
2297
2298 \sa widget()
2299*/
2300void QMdiSubWindow::setWidget(QWidget *widget)
2301{
2302 Q_D(QMdiSubWindow);
2303 if (!widget) {
2304 d->removeBaseWidget();
2305 return;
2306 }
2307
2308 if (widget == d->baseWidget) {
2309 qWarning("QMdiSubWindow::setWidget: widget is already set");
2310 return;
2311 }
2312
2313 bool wasResized = testAttribute(Qt::WA_Resized);
2314 d->removeBaseWidget();
2315
2316 if (QLayout *layout = this->layout())
2317 layout->addWidget(widget);
2318 else
2319 widget->setParent(this);
2320
2321#ifndef QT_NO_SIZEGRIP
2322 QSizeGrip *sizeGrip = qFindChild<QSizeGrip *>(widget);
2323 if (sizeGrip)
2324 sizeGrip->installEventFilter(this);
2325 if (d->sizeGrip)
2326 d->sizeGrip->raise();
2327#endif
2328
2329 d->baseWidget = widget;
2330 d->baseWidget->installEventFilter(this);
2331
2332 d->ignoreWindowTitleChange = true;
2333 bool isWindowModified = this->isWindowModified();
2334 if (windowTitle().isEmpty()) {
2335 d->updateWindowTitle(true);
2336 isWindowModified = d->baseWidget->isWindowModified();
2337 }
2338 if (!this->isWindowModified() && isWindowModified
2339 && windowTitle().contains(QLatin1String("[*]"))) {
2340 setWindowModified(isWindowModified);
2341 }
2342 d->lastChildWindowTitle = d->baseWidget->windowTitle();
2343 d->ignoreWindowTitleChange = false;
2344
2345 if (windowIcon().isNull() && !d->baseWidget->windowIcon().isNull())
2346 setWindowIcon(d->baseWidget->windowIcon());
2347
2348 d->updateGeometryConstraints();
2349 if (!wasResized && testAttribute(Qt::WA_Resized))
2350 setAttribute(Qt::WA_Resized, false);
2351}
2352
2353/*!
2354 Returns the current internal widget.
2355
2356 \sa setWidget()
2357*/
2358QWidget *QMdiSubWindow::widget() const
2359{
2360 return d_func()->baseWidget;
2361}
2362
2363
2364/*!
2365 \internal
2366*/
2367QWidget *QMdiSubWindow::maximizedButtonsWidget() const
2368{
2369 Q_D(const QMdiSubWindow);
2370 if (isVisible() && d->controlContainer && isMaximized() && !d->drawTitleBarWhenMaximized()
2371 && !isChildOfTabbedQMdiArea(this)) {
2372 return d->controlContainer->controllerWidget();
2373 }
2374 return 0;
2375}
2376
2377/*!
2378 \internal
2379*/
2380QWidget *QMdiSubWindow::maximizedSystemMenuIconWidget() const
2381{
2382 Q_D(const QMdiSubWindow);
2383 if (isVisible() && d->controlContainer && isMaximized() && !d->drawTitleBarWhenMaximized()
2384 && !isChildOfTabbedQMdiArea(this)) {
2385 return d->controlContainer->systemMenuLabel();
2386 }
2387 return 0;
2388}
2389
2390/*!
2391 Returns true if this window is shaded; otherwise returns false.
2392
2393 A window is shaded if it is collapsed so that only the title bar is
2394 visible.
2395*/
2396bool QMdiSubWindow::isShaded() const
2397{
2398 return d_func()->isShadeMode;
2399}
2400
2401/*!
2402 If \a on is true, \a option is enabled on the subwindow; otherwise it is
2403 disabled. See SubWindowOption for the effect of each option.
2404
2405 \sa SubWindowOption, testOption()
2406*/
2407void QMdiSubWindow::setOption(SubWindowOption option, bool on)
2408{
2409 Q_D(QMdiSubWindow);
2410 if (on && !(d->options & option))
2411 d->options |= option;
2412 else if (!on && (d->options & option))
2413 d->options &= ~option;
2414
2415#ifndef QT_NO_RUBBERBAND
2416 if ((option & (RubberBandResize | RubberBandMove)) && !on && d->isInRubberBandMode)
2417 d->leaveRubberBandMode();
2418#endif
2419}
2420
2421/*!
2422 Returns true if \a option is enabled; otherwise returns false.
2423
2424 \sa SubWindowOption, setOption()
2425*/
2426bool QMdiSubWindow::testOption(SubWindowOption option) const
2427{
2428 return d_func()->options & option;
2429}
2430
2431/*!
2432 \property QMdiSubWindow::keyboardSingleStep
2433 \brief sets how far a widget should move or resize when using the
2434 keyboard arrow keys.
2435
2436 When in keyboard-interactive mode, you can use the arrow and page keys to
2437 either move or resize the window. This property controls the arrow keys.
2438 The common way to enter keyboard interactive mode is to enter the
2439 subwindow menu, and select either "resize" or "move".
2440
2441 The default keyboard single step value is 5 pixels.
2442
2443 \sa keyboardPageStep
2444*/
2445int QMdiSubWindow::keyboardSingleStep() const
2446{
2447 return d_func()->keyboardSingleStep;
2448}
2449
2450void QMdiSubWindow::setKeyboardSingleStep(int step)
2451{
2452 // Haven't done any boundary check here since negative step only
2453 // means inverted behavior, which is OK if the user want it.
2454 // A step equal to zero means "do nothing".
2455 d_func()->keyboardSingleStep = step;
2456}
2457
2458/*!
2459 \property QMdiSubWindow::keyboardPageStep
2460 \brief sets how far a widget should move or resize when using the
2461 keyboard page keys.
2462
2463 When in keyboard-interactive mode, you can use the arrow and page keys to
2464 either move or resize the window. This property controls the page
2465 keys. The common way to enter keyboard interactive mode is to enter the
2466 subwindow menu, and select either "resize" or "move".
2467
2468 The default keyboard page step value is 20 pixels.
2469
2470 \sa keyboardSingleStep
2471*/
2472int QMdiSubWindow::keyboardPageStep() const
2473{
2474 return d_func()->keyboardPageStep;
2475}
2476
2477void QMdiSubWindow::setKeyboardPageStep(int step)
2478{
2479 // Haven't done any boundary check here since negative step only
2480 // means inverted behavior, which is OK if the user want it.
2481 // A step equal to zero means "do nothing".
2482 d_func()->keyboardPageStep = step;
2483}
2484
2485#ifndef QT_NO_MENU
2486/*!
2487 Sets \a systemMenu as the current system menu for this subwindow.
2488
2489 By default, each QMdiSubWindow has a standard system menu.
2490
2491 QActions for the system menu created by QMdiSubWindow will
2492 automatically be updated depending on the current window state;
2493 e.g., the minimize action will be disabled after the window is
2494 minimized.
2495
2496 QActions added by the user are not updated by QMdiSubWindow.
2497
2498 QMdiSubWindow takes ownership of \a systemMenu; you do not have to
2499 delete it. Any existing menus will be deleted.
2500
2501 \sa systemMenu(), showSystemMenu()
2502*/
2503void QMdiSubWindow::setSystemMenu(QMenu *systemMenu)
2504{
2505 Q_D(QMdiSubWindow);
2506 if (systemMenu && systemMenu == d->systemMenu) {
2507 qWarning("QMdiSubWindow::setSystemMenu: system menu is already set");
2508 return;
2509 }
2510
2511 if (d->systemMenu) {
2512 delete d->systemMenu;
2513 d->systemMenu = 0;
2514 }
2515
2516 if (!systemMenu)
2517 return;
2518
2519 if (systemMenu->parent() != this)
2520 systemMenu->setParent(this);
2521 d->systemMenu = systemMenu;
2522}
2523
2524/*!
2525 Returns a pointer to the current system menu, or zero if no system
2526 menu is set. QMdiSubWindow provides a default system menu, but you can
2527 also set the menu with setSystemMenu().
2528
2529 \sa setSystemMenu(), showSystemMenu()
2530*/
2531QMenu *QMdiSubWindow::systemMenu() const
2532{
2533 return d_func()->systemMenu;
2534}
2535
2536/*!
2537 Shows the system menu below the system menu icon in the title bar.
2538
2539 \sa setSystemMenu(), systemMenu()
2540*/
2541void QMdiSubWindow::showSystemMenu()
2542{
2543 Q_D(QMdiSubWindow);
2544 if (!d->systemMenu)
2545 return;
2546
2547 QPoint globalPopupPos;
2548 if (QWidget *icon = maximizedSystemMenuIconWidget()) {
2549 if (isLeftToRight())
2550 globalPopupPos = icon->mapToGlobal(QPoint(0, icon->y() + icon->height()));
2551 else
2552 globalPopupPos = icon->mapToGlobal(QPoint(icon->width(), icon->y() + icon->height()));
2553 } else {
2554 if (isLeftToRight())
2555 globalPopupPos = mapToGlobal(contentsRect().topLeft());
2556 else // + QPoint(1, 0) because topRight() == QPoint(left() + width() -1, top())
2557 globalPopupPos = mapToGlobal(contentsRect().topRight()) + QPoint(1, 0);
2558 }
2559
2560 // Adjust x() with -menuwidth in reverse mode.
2561 if (isRightToLeft())
2562 globalPopupPos -= QPoint(d->systemMenu->sizeHint().width(), 0);
2563 d->systemMenu->installEventFilter(this);
2564 d->systemMenu->popup(globalPopupPos);
2565}
2566#endif // QT_NO_MENU
2567
2568/*!
2569 \since 4.4
2570
2571 Returns the area containing this sub-window, or 0 if there is none.
2572
2573 \sa QMdiArea::addSubWindow()
2574*/
2575QMdiArea *QMdiSubWindow::mdiArea() const
2576{
2577 QWidget *parent = parentWidget();
2578 while (parent) {
2579 if (QMdiArea *area = qobject_cast<QMdiArea *>(parent)) {
2580 if (area->viewport() == parentWidget())
2581 return area;
2582 }
2583 parent = parent->parentWidget();
2584 }
2585 return 0;
2586}
2587
2588/*!
2589 Calling this function makes the subwindow enter the shaded mode.
2590 When the subwindow is shaded, only the title bar is visible.
2591
2592 Although shading is not supported by all styles, this function will
2593 still show the subwindow as shaded, regardless of whether support
2594 for shading is available. However, when used with styles without
2595 shading support, the user will be unable to return from shaded mode
2596 through the user interface (e.g., through a shade button in the title
2597 bar).
2598
2599 \sa isShaded()
2600*/
2601void QMdiSubWindow::showShaded()
2602{
2603 if (!parent())
2604 return;
2605
2606 Q_D(QMdiSubWindow);
2607 // setMinimizeMode uses this function.
2608 if (!d->isShadeRequestFromMinimizeMode && isShaded())
2609 return;
2610
2611 d->isMaximizeMode = false;
2612
2613 QWidget *currentFocusWidget = QApplication::focusWidget();
2614 if (!d->restoreFocusWidget && isAncestorOf(currentFocusWidget))
2615 d->restoreFocusWidget = currentFocusWidget;
2616
2617 if (!d->isShadeRequestFromMinimizeMode) {
2618 d->isShadeMode = true;
2619 d->ensureWindowState(Qt::WindowMinimized);
2620 }
2621
2622#ifndef QT_NO_MENUBAR
2623 d->removeButtonsFromMenuBar();
2624#endif
2625
2626 // showMinimized() will reset Qt::WindowActive, which makes sense
2627 // for top level widgets, but in MDI it makes sense to have an
2628 // active window which is minimized.
2629 if (hasFocus() || isAncestorOf(currentFocusWidget))
2630 d->ensureWindowState(Qt::WindowActive);
2631
2632#ifndef QT_NO_SIZEGRIP
2633 d->setSizeGripVisible(false);
2634#endif
2635
2636 if (!d->restoreSize.isValid() || d->isShadeMode) {
2637 d->oldGeometry = geometry();
2638 d->restoreSize.setWidth(d->oldGeometry.width());
2639 d->restoreSize.setHeight(d->oldGeometry.height());
2640 }
2641
2642 // Hide the window before we change the geometry to avoid multiple resize
2643 // events and wrong window state.
2644 const bool wasVisible = isVisible();
2645 if (wasVisible)
2646 setVisible(false);
2647
2648 d->updateGeometryConstraints();
2649 // Update minimum size to internalMinimumSize if set by user.
2650 if (!minimumSize().isNull()) {
2651 d->userMinimumSize = minimumSize();
2652 setMinimumSize(d->internalMinimumSize);
2653 }
2654 resize(d->internalMinimumSize);
2655
2656 // Hide the internal widget if not already hidden by the user.
2657 if (d->baseWidget && !d->baseWidget->isHidden()) {
2658 d->baseWidget->hide();
2659 d->isWidgetHiddenByUs = true;
2660 }
2661
2662 if (wasVisible)
2663 setVisible(true);
2664
2665 d->setFocusWidget();
2666 d->resizeEnabled = false;
2667 d->moveEnabled = true;
2668 d->updateDirtyRegions();
2669 d->updateMask();
2670
2671#ifndef QT_NO_ACTION
2672 d->setEnabled(QMdiSubWindowPrivate::MinimizeAction, false);
2673 d->setEnabled(QMdiSubWindowPrivate::ResizeAction, d->resizeEnabled);
2674 d->setEnabled(QMdiSubWindowPrivate::MaximizeAction, true);
2675 d->setEnabled(QMdiSubWindowPrivate::RestoreAction, true);
2676 d->setEnabled(QMdiSubWindowPrivate::MoveAction, d->moveEnabled);
2677#endif
2678}
2679
2680/*!
2681 \reimp
2682*/
2683bool QMdiSubWindow::eventFilter(QObject *object, QEvent *event)
2684{
2685 Q_D(QMdiSubWindow);
2686 if (!object)
2687 return QWidget::eventFilter(object, event);
2688
2689#ifndef QT_NO_MENU
2690 // System menu events.
2691 if (d->systemMenu && d->systemMenu == object) {
2692 if (event->type() == QEvent::MouseButtonDblClick) {
2693 close();
2694 } else if (event->type() == QEvent::MouseMove) {
2695 QMouseEvent *mouseEvent = static_cast<QMouseEvent *>(event);
2696 d->hoveredSubControl = d->getSubControl(mapFromGlobal(mouseEvent->globalPos()));
2697 } else if (event->type() == QEvent::Hide) {
2698 d->systemMenu->removeEventFilter(this);
2699 d->activeSubControl = QStyle::SC_None;
2700 update(QRegion(0, 0, width(), d->titleBarHeight()));
2701 }
2702 return QWidget::eventFilter(object, event);
2703 }
2704#endif
2705
2706#ifndef QT_NO_SIZEGRIP
2707 if (object != d->baseWidget && parent() && qobject_cast<QSizeGrip *>(object)) {
2708 if (event->type() != QEvent::MouseButtonPress || !testOption(QMdiSubWindow::RubberBandResize))
2709 return QWidget::eventFilter(object, event);
2710 const QMouseEvent *mouseEvent = static_cast<QMouseEvent *>(event);
2711 d->mousePressPosition = parentWidget()->mapFromGlobal(mouseEvent->globalPos());
2712 d->oldGeometry = geometry();
2713 d->currentOperation = isLeftToRight() ? QMdiSubWindowPrivate::BottomRightResize
2714 : QMdiSubWindowPrivate::BottomLeftResize;
2715#ifndef QT_NO_RUBBERBAND
2716 d->enterRubberBandMode();
2717#endif
2718 return true;
2719 }
2720#endif
2721
2722 if (object != d->baseWidget && event->type() != QEvent::WindowTitleChange)
2723 return QWidget::eventFilter(object, event);
2724
2725 switch (event->type()) {
2726 case QEvent::Show:
2727 d->setActive(true);
2728 break;
2729 case QEvent::ShowToParent:
2730 if (!d->isWidgetHiddenByUs)
2731 show();
2732 break;
2733 case QEvent::WindowStateChange: {
2734 QWindowStateChangeEvent *changeEvent = static_cast<QWindowStateChangeEvent*>(event);
2735 if (changeEvent->isOverride())
2736 break;
2737 Qt::WindowStates oldState = changeEvent->oldState();
2738 Qt::WindowStates newState = d->baseWidget->windowState();
2739 if (!(oldState & Qt::WindowMinimized) && (newState & Qt::WindowMinimized))
2740 showMinimized();
2741 else if (!(oldState & Qt::WindowMaximized) && (newState & Qt::WindowMaximized))
2742 showMaximized();
2743 else if (!(newState & (Qt::WindowMaximized | Qt::WindowMinimized)))
2744 showNormal();
2745 break;
2746 }
2747 case QEvent::Enter:
2748 d->currentOperation = QMdiSubWindowPrivate::None;
2749 d->updateCursor();
2750 break;
2751 case QEvent::LayoutRequest:
2752 d->updateGeometryConstraints();
2753 break;
2754 case QEvent::WindowTitleChange:
2755 if (d->ignoreWindowTitleChange)
2756 break;
2757 if (object == d->baseWidget) {
2758 d->updateWindowTitle(true);
2759 d->lastChildWindowTitle = d->baseWidget->windowTitle();
2760#ifndef QT_NO_MENUBAR
2761 } else if (maximizedButtonsWidget() && d->controlContainer->menuBar() && d->controlContainer->menuBar()
2762 ->cornerWidget(Qt::TopRightCorner) == maximizedButtonsWidget()) {
2763 d->originalTitle = QString::null;
2764 if (d->baseWidget && d->baseWidget->windowTitle() == windowTitle())
2765 d->updateWindowTitle(true);
2766 else
2767 d->updateWindowTitle(false);
2768#endif
2769 }
2770 break;
2771 case QEvent::ModifiedChange: {
2772 if (object != d->baseWidget)
2773 break;
2774 bool windowModified = d->baseWidget->isWindowModified();
2775 if (!windowModified && d->baseWidget->windowTitle() != windowTitle())
2776 break;
2777 if (windowTitle().contains(QLatin1String("[*]")))
2778 setWindowModified(windowModified);
2779 break;
2780 }
2781 default:
2782 break;
2783 }
2784 return QWidget::eventFilter(object, event);
2785}
2786
2787/*!
2788 \reimp
2789*/
2790bool QMdiSubWindow::event(QEvent *event)
2791{
2792 Q_D(QMdiSubWindow);
2793 switch (event->type()) {
2794 case QEvent::StyleChange: {
2795 bool wasShaded = isShaded();
2796 bool wasMinimized = isMinimized();
2797 bool wasMaximized = isMaximized();
2798 ensurePolished();
2799 setContentsMargins(0, 0, 0, 0);
2800 if (wasMinimized || wasMaximized || wasShaded)
2801 showNormal();
2802 d->updateGeometryConstraints();
2803 resize(d->internalMinimumSize.expandedTo(size()));
2804 d->updateMask();
2805 d->updateDirtyRegions();
2806 if (wasShaded)
2807 showShaded();
2808 else if (wasMinimized)
2809 showMinimized();
2810 else if (wasMaximized)
2811 showMaximized();
2812 break;
2813 }
2814 case QEvent::ParentAboutToChange:
2815 d->setActive(false);
2816 break;
2817 case QEvent::ParentChange: {
2818 bool wasResized = testAttribute(Qt::WA_Resized);
2819#ifndef QT_NO_MENUBAR
2820 d->removeButtonsFromMenuBar();
2821#endif
2822 d->currentOperation = QMdiSubWindowPrivate::None;
2823 d->activeSubControl = QStyle::SC_None;
2824 d->hoveredSubControl = QStyle::SC_None;
2825#ifndef QT_NO_RUBBERBAND
2826 if (d->isInRubberBandMode)
2827 d->leaveRubberBandMode();
2828#endif
2829 d->isShadeMode = false;
2830 d->isMaximizeMode = false;
2831 d->isWidgetHiddenByUs = false;
2832 if (!parent()) {
2833#if !defined(QT_NO_SIZEGRIP) && defined(Q_WS_MAC) && !defined(QT_NO_STYLE_MAC)
2834 if (qobject_cast<QMacStyle *>(style()))
2835 delete d->sizeGrip;
2836#endif
2837 setOption(RubberBandResize, false);
2838 setOption(RubberBandMove, false);
2839 } else {
2840 d->setWindowFlags(windowFlags());
2841 }
2842 setContentsMargins(0, 0, 0, 0);
2843 d->updateGeometryConstraints();
2844 d->updateCursor();
2845 d->updateMask();
2846 d->updateDirtyRegions();
2847 d->updateActions();
2848 if (!wasResized && testAttribute(Qt::WA_Resized))
2849 setAttribute(Qt::WA_Resized, false);
2850 break;
2851 }
2852 case QEvent::WindowActivate:
2853 if (d->ignoreNextActivationEvent) {
2854 d->ignoreNextActivationEvent = false;
2855 break;
2856 }
2857 d->isExplicitlyDeactivated = false;
2858 d->setActive(true);
2859 break;
2860 case QEvent::WindowDeactivate:
2861 if (d->ignoreNextActivationEvent) {
2862 d->ignoreNextActivationEvent = false;
2863 break;
2864 }
2865 d->isExplicitlyDeactivated = true;
2866 d->setActive(false);
2867 break;
2868 case QEvent::WindowTitleChange:
2869 if (!d->ignoreWindowTitleChange)
2870 d->updateWindowTitle(false);
2871 d->updateInternalWindowTitle();
2872 break;
2873 case QEvent::ModifiedChange:
2874 if (!windowTitle().contains(QLatin1String("[*]")))
2875 break;
2876#ifndef QT_NO_MENUBAR
2877 if (maximizedButtonsWidget() && d->controlContainer->menuBar() && d->controlContainer->menuBar()
2878 ->cornerWidget(Qt::TopRightCorner) == maximizedButtonsWidget()) {
2879 window()->setWindowModified(isWindowModified());
2880 }
2881#endif // QT_NO_MENUBAR
2882 d->updateInternalWindowTitle();
2883 break;
2884 case QEvent::LayoutDirectionChange:
2885 d->updateDirtyRegions();
2886 break;
2887 case QEvent::LayoutRequest:
2888 d->updateGeometryConstraints();
2889 break;
2890 case QEvent::WindowIconChange:
2891 d->menuIcon = windowIcon();
2892 if (d->menuIcon.isNull())
2893 d->menuIcon = style()->standardIcon(QStyle::SP_TitleBarMenuButton, 0, this);
2894 if (d->controlContainer)
2895 d->controlContainer->updateWindowIcon(d->menuIcon);
2896 if (!maximizedSystemMenuIconWidget())
2897 update(0, 0, width(), d->titleBarHeight());
2898 break;
2899 case QEvent::PaletteChange:
2900 d->titleBarPalette = d->desktopPalette();
2901 break;
2902 case QEvent::FontChange:
2903 d->font = font();
2904 break;
2905#ifndef QT_NO_TOOLTIP
2906 case QEvent::ToolTip:
2907 showToolTip(static_cast<QHelpEvent *>(event), this, d->titleBarOptions(),
2908 QStyle::CC_TitleBar, d->hoveredSubControl);
2909 break;
2910#endif
2911 default:
2912 break;
2913 }
2914 return QWidget::event(event);
2915}
2916
2917/*!
2918 \reimp
2919*/
2920void QMdiSubWindow::showEvent(QShowEvent *showEvent)
2921{
2922 Q_D(QMdiSubWindow);
2923 if (!parent()) {
2924 QWidget::showEvent(showEvent);
2925 return;
2926 }
2927
2928#if !defined(QT_NO_SIZEGRIP) && defined(Q_WS_MAC) && !defined(QT_NO_STYLE_MAC)
2929 if (qobject_cast<QMacStyle *>(style()) && !d->sizeGrip
2930 && !(windowFlags() & Qt::FramelessWindowHint)) {
2931 d->setSizeGrip(new QSizeGrip(0));
2932 Q_ASSERT(d->sizeGrip);
2933 if (isMinimized())
2934 d->setSizeGripVisible(false);
2935 else
2936 d->setSizeGripVisible(true);
2937 resize(size().expandedTo(d->internalMinimumSize));
2938 }
2939#endif
2940
2941 d->updateDirtyRegions();
2942 // Show buttons in the menu bar if they're already not there.
2943 // We want to do this when QMdiSubWindow becomes visible after being hidden.
2944#ifndef QT_NO_MENUBAR
2945 if (d->controlContainer) {
2946 if (QMenuBar *menuBar = d->menuBar()) {
2947 if (menuBar->cornerWidget(Qt::TopRightCorner) != maximizedButtonsWidget())
2948 d->showButtonsInMenuBar(menuBar);
2949 }
2950 }
2951#endif
2952 d->setActive(true);
2953}
2954
2955/*!
2956 \reimp
2957*/
2958void QMdiSubWindow::hideEvent(QHideEvent * /*hideEvent*/)
2959{
2960#ifndef QT_NO_MENUBAR
2961 d_func()->removeButtonsFromMenuBar();
2962#endif
2963}
2964
2965/*!
2966 \reimp
2967*/
2968void QMdiSubWindow::changeEvent(QEvent *changeEvent)
2969{
2970 if (!parent()) {
2971 QWidget::changeEvent(changeEvent);
2972 return;
2973 }
2974
2975 if (changeEvent->type() != QEvent::WindowStateChange) {
2976 QWidget::changeEvent(changeEvent);
2977 return;
2978 }
2979
2980 QWindowStateChangeEvent *event = static_cast<QWindowStateChangeEvent *>(changeEvent);
2981 if (event->isOverride()) {
2982 event->ignore();
2983 return;
2984 }
2985
2986 Qt::WindowStates oldState = event->oldState();
2987 Qt::WindowStates newState = windowState();
2988 if (oldState == newState) {
2989 changeEvent->ignore();
2990 return;
2991 }
2992
2993 // QWidget ensures that the widget is visible _after_ setWindowState(),
2994 // but we need to ensure that the widget is visible _before_
2995 // setWindowState() returns.
2996 Q_D(QMdiSubWindow);
2997 if (!isVisible()) {
2998 d->ensureWindowState(Qt::WindowNoState);
2999 setVisible(true);
3000 }
3001
3002 if (!d->oldGeometry.isValid())
3003 d->oldGeometry = geometry();
3004
3005 if ((oldState & Qt::WindowActive) && (newState & Qt::WindowActive))
3006 d->currentOperation = QMdiSubWindowPrivate::None;
3007
3008 if (!(oldState & Qt::WindowMinimized) && (newState & Qt::WindowMinimized))
3009 d->setMinimizeMode();
3010 else if (!(oldState & Qt::WindowMaximized) && (newState & Qt::WindowMaximized))
3011 d->setMaximizeMode();
3012 else if (!(newState & (Qt::WindowMaximized | Qt::WindowMinimized)))
3013 d->setNormalMode();
3014
3015 if (d->isActive)
3016 d->ensureWindowState(Qt::WindowActive);
3017 emit windowStateChanged(oldState, windowState());
3018}
3019
3020/*!
3021 \reimp
3022*/
3023void QMdiSubWindow::closeEvent(QCloseEvent *closeEvent)
3024{
3025 Q_D(QMdiSubWindow);
3026 bool acceptClose = true;
3027 if (d->baseWidget)
3028 acceptClose = d->baseWidget->close();
3029 if (!acceptClose) {
3030 closeEvent->ignore();
3031 return;
3032 }
3033#ifndef QT_NO_MENUBAR
3034 d->removeButtonsFromMenuBar();
3035#endif
3036 d->setActive(false);
3037 if (parentWidget() && testAttribute(Qt::WA_DeleteOnClose)) {
3038 QChildEvent childRemoved(QEvent::ChildRemoved, this);
3039 QApplication::sendEvent(parentWidget(), &childRemoved);
3040 }
3041 closeEvent->accept();
3042}
3043
3044/*!
3045 \reimp
3046*/
3047void QMdiSubWindow::leaveEvent(QEvent * /*leaveEvent*/)
3048{
3049 Q_D(QMdiSubWindow);
3050 if (d->hoveredSubControl != QStyle::SC_None) {
3051 d->hoveredSubControl = QStyle::SC_None;
3052 update(QRegion(0, 0, width(), d->titleBarHeight()));
3053 }
3054}
3055
3056/*!
3057 \reimp
3058*/
3059void QMdiSubWindow::resizeEvent(QResizeEvent *resizeEvent)
3060{
3061 Q_D(QMdiSubWindow);
3062#ifndef QT_NO_SIZEGRIP
3063 if (d->sizeGrip) {
3064 d->sizeGrip->move(isLeftToRight() ? width() - d->sizeGrip->width() : 0,
3065 height() - d->sizeGrip->height());
3066 }
3067#endif
3068
3069 if (!parent()) {
3070 QWidget::resizeEvent(resizeEvent);
3071 return;
3072 }
3073
3074 if (d->isMaximizeMode)
3075 d->ensureWindowState(Qt::WindowMaximized);
3076
3077 d->updateMask();
3078 if (!isVisible())
3079 return;
3080
3081 if (d->resizeTimerId <= 0)
3082 d->cachedStyleOptions = d->titleBarOptions();
3083 else
3084 killTimer(d->resizeTimerId);
3085 d->resizeTimerId = startTimer(200);
3086}
3087
3088/*!
3089 \reimp
3090*/
3091void QMdiSubWindow::timerEvent(QTimerEvent *timerEvent)
3092{
3093 Q_D(QMdiSubWindow);
3094 if (timerEvent->timerId() == d->resizeTimerId) {
3095 killTimer(d->resizeTimerId);
3096 d->resizeTimerId = -1;
3097 d->updateDirtyRegions();
3098 }
3099}
3100
3101/*!
3102 \reimp
3103*/
3104void QMdiSubWindow::moveEvent(QMoveEvent *moveEvent)
3105{
3106 if (!parent()) {
3107 QWidget::moveEvent(moveEvent);
3108 return;
3109 }
3110
3111 Q_D(QMdiSubWindow);
3112 if (d->isMaximizeMode)
3113 d->ensureWindowState(Qt::WindowMaximized);
3114}
3115
3116/*!
3117 \reimp
3118*/
3119void QMdiSubWindow::paintEvent(QPaintEvent *paintEvent)
3120{
3121 if (!parent() || (windowFlags() & Qt::FramelessWindowHint)) {
3122 QWidget::paintEvent(paintEvent);
3123 return;
3124 }
3125
3126 Q_D(QMdiSubWindow);
3127 if (isMaximized() && !d->drawTitleBarWhenMaximized())
3128 return;
3129
3130 if (d->resizeTimerId != -1) {
3131 // Only update the style option rect and the window title.
3132 int border = d->hasBorder(d->cachedStyleOptions) ? 4 : 0;
3133 int titleBarHeight = d->titleBarHeight(d->cachedStyleOptions);
3134 titleBarHeight -= isMinimized() ? 2 * border : border;
3135 d->cachedStyleOptions.rect = QRect(border, border, width() - 2 * border, titleBarHeight);
3136 if (!d->windowTitle.isEmpty()) {
3137 int width = style()->subControlRect(QStyle::CC_TitleBar, &d->cachedStyleOptions,
3138 QStyle::SC_TitleBarLabel, this).width();
3139 d->cachedStyleOptions.text = d->cachedStyleOptions.fontMetrics
3140 .elidedText(d->windowTitle, Qt::ElideRight, width);
3141 }
3142 } else {
3143 // Force full update.
3144 d->cachedStyleOptions = d->titleBarOptions();
3145 }
3146
3147 QStylePainter painter(this);
3148 if (!d->windowTitle.isEmpty())
3149 painter.setFont(d->font);
3150 painter.drawComplexControl(QStyle::CC_TitleBar, d->cachedStyleOptions);
3151
3152 if (isMinimized() && !d->hasBorder(d->cachedStyleOptions))
3153 return;
3154
3155 QStyleOptionFrame frameOptions;
3156 frameOptions.initFrom(this);
3157 frameOptions.lineWidth = style()->pixelMetric(QStyle::PM_MdiSubWindowFrameWidth, 0, this);
3158 if (d->isActive)
3159 frameOptions.state |= QStyle::State_Active;
3160 else
3161 frameOptions.state &= ~QStyle::State_Active;
3162
3163 // ### Ensure that we do not require setting the cliprect for 4.4
3164 if (!isMinimized() && !d->hasBorder(d->cachedStyleOptions))
3165 painter.setClipRect(rect().adjusted(0, d->titleBarHeight(d->cachedStyleOptions), 0, 0));
3166 if (!isMinimized() || d->hasBorder(d->cachedStyleOptions))
3167 painter.drawPrimitive(QStyle::PE_FrameWindow, frameOptions);
3168}
3169
3170/*!
3171 \reimp
3172*/
3173void QMdiSubWindow::mousePressEvent(QMouseEvent *mouseEvent)
3174{
3175 if (!parent()) {
3176 QWidget::mousePressEvent(mouseEvent);
3177 return;
3178 }
3179
3180 Q_D(QMdiSubWindow);
3181 if (d->isInInteractiveMode)
3182 d->leaveInteractiveMode();
3183#ifndef QT_NO_RUBBERBAND
3184 if (d->isInRubberBandMode)
3185 d->leaveRubberBandMode();
3186#endif
3187
3188 if (mouseEvent->button() != Qt::LeftButton) {
3189 mouseEvent->ignore();
3190 return;
3191 }
3192
3193 if (d->currentOperation != QMdiSubWindowPrivate::None) {
3194 d->updateCursor();
3195 d->mousePressPosition = mapToParent(mouseEvent->pos());
3196 if (d->resizeEnabled || d->moveEnabled)
3197 d->oldGeometry = geometry();
3198#ifndef QT_NO_RUBBERBAND
3199 if ((testOption(QMdiSubWindow::RubberBandResize) && d->isResizeOperation())
3200 || (testOption(QMdiSubWindow::RubberBandMove) && d->isMoveOperation())) {
3201 d->enterRubberBandMode();
3202 }
3203#endif
3204 return;
3205 }
3206
3207 d->activeSubControl = d->hoveredSubControl;
3208#ifndef QT_NO_MENU
3209 if (d->activeSubControl == QStyle::SC_TitleBarSysMenu)
3210 showSystemMenu();
3211 else
3212#endif
3213 update(QRegion(0, 0, width(), d->titleBarHeight()));
3214}
3215
3216/*!
3217 \reimp
3218*/
3219void QMdiSubWindow::mouseDoubleClickEvent(QMouseEvent *mouseEvent)
3220{
3221 if (!parent()) {
3222 QWidget::mouseDoubleClickEvent(mouseEvent);
3223 return;
3224 }
3225
3226 if (mouseEvent->button() != Qt::LeftButton) {
3227 mouseEvent->ignore();
3228 return;
3229 }
3230
3231 Q_D(QMdiSubWindow);
3232 if (!d->isMoveOperation()) {
3233#ifndef QT_NO_MENU
3234 if (d->hoveredSubControl == QStyle::SC_TitleBarSysMenu)
3235 close();
3236#endif
3237 return;
3238 }
3239
3240 Qt::WindowFlags flags = windowFlags();
3241 if (isMinimized()) {
3242 if ((isShaded() && (flags & Qt::WindowShadeButtonHint))
3243 || (flags & Qt::WindowMinimizeButtonHint)) {
3244 showNormal();
3245 }
3246 return;
3247 }
3248
3249 if (isMaximized()) {
3250 if (flags & Qt::WindowMaximizeButtonHint)
3251 showNormal();
3252 return;
3253 }
3254
3255 if (flags & Qt::WindowShadeButtonHint)
3256 showShaded();
3257 else if (flags & Qt::WindowMaximizeButtonHint)
3258 showMaximized();
3259}
3260
3261/*!
3262 \reimp
3263*/
3264void QMdiSubWindow::mouseReleaseEvent(QMouseEvent *mouseEvent)
3265{
3266 if (!parent()) {
3267 QWidget::mouseReleaseEvent(mouseEvent);
3268 return;
3269 }
3270
3271 if (mouseEvent->button() != Qt::LeftButton) {
3272 mouseEvent->ignore();
3273 return;
3274 }
3275
3276 Q_D(QMdiSubWindow);
3277 if (d->currentOperation != QMdiSubWindowPrivate::None) {
3278#ifndef QT_NO_RUBBERBAND
3279 if (d->isInRubberBandMode && !d->isInInteractiveMode)
3280 d->leaveRubberBandMode();
3281#endif
3282 if (d->resizeEnabled || d->moveEnabled)
3283 d->oldGeometry = geometry();
3284 }
3285
3286 d->currentOperation = d->getOperation(mouseEvent->pos());
3287 d->updateCursor();
3288
3289 d->hoveredSubControl = d->getSubControl(mouseEvent->pos());
3290 if (d->activeSubControl != QStyle::SC_None
3291 && d->activeSubControl == d->hoveredSubControl) {
3292 d->processClickedSubControl();
3293 }
3294 d->activeSubControl = QStyle::SC_None;
3295 update(QRegion(0, 0, width(), d->titleBarHeight()));
3296}
3297
3298/*!
3299 \reimp
3300*/
3301void QMdiSubWindow::mouseMoveEvent(QMouseEvent *mouseEvent)
3302{
3303 if (!parent()) {
3304 QWidget::mouseMoveEvent(mouseEvent);
3305 return;
3306 }
3307
3308 Q_D(QMdiSubWindow);
3309 // No update needed if we're in a move/resize operation.
3310 if (!d->isMoveOperation() && !d->isResizeOperation()) {
3311 // Find previous and current hover region.
3312 const QStyleOptionTitleBar options = d->titleBarOptions();
3313 QStyle::SubControl oldHover = d->hoveredSubControl;
3314 d->hoveredSubControl = d->getSubControl(mouseEvent->pos());
3315 QRegion hoverRegion;
3316 if (isHoverControl(oldHover) && oldHover != d->hoveredSubControl)
3317 hoverRegion += style()->subControlRect(QStyle::CC_TitleBar, &options, oldHover, this);
3318 if (isHoverControl(d->hoveredSubControl) && d->hoveredSubControl != oldHover) {
3319 hoverRegion += style()->subControlRect(QStyle::CC_TitleBar, &options,
3320 d->hoveredSubControl, this);
3321 }
3322#if defined(Q_WS_MAC) && !defined(QT_NO_STYLE_MAC)
3323 if (qobject_cast<QMacStyle *>(style()) && !hoverRegion.isEmpty())
3324 hoverRegion += QRegion(0, 0, width(), d->titleBarHeight(options));
3325#endif
3326 if (!hoverRegion.isEmpty())
3327 update(hoverRegion);
3328 }
3329
3330 if ((mouseEvent->buttons() & Qt::LeftButton) || d->isInInteractiveMode) {
3331 if ((d->isResizeOperation() && d->resizeEnabled) || (d->isMoveOperation() && d->moveEnabled))
3332 d->setNewGeometry(mapToParent(mouseEvent->pos()));
3333 return;
3334 }
3335
3336 // Do not resize/move if not allowed.
3337 d->currentOperation = d->getOperation(mouseEvent->pos());
3338 if ((d->isResizeOperation() && !d->resizeEnabled) || (d->isMoveOperation() && !d->moveEnabled))
3339 d->currentOperation = QMdiSubWindowPrivate::None;
3340 d->updateCursor();
3341}
3342
3343/*!
3344 \reimp
3345*/
3346void QMdiSubWindow::keyPressEvent(QKeyEvent *keyEvent)
3347{
3348 Q_D(QMdiSubWindow);
3349 if (!d->isInInteractiveMode || !parent()) {
3350 keyEvent->ignore();
3351 return;
3352 }
3353
3354 QPoint delta;
3355 switch (keyEvent->key()) {
3356 case Qt::Key_Right:
3357 if (keyEvent->modifiers() & Qt::ShiftModifier)
3358 delta = QPoint(d->keyboardPageStep, 0);
3359 else
3360 delta = QPoint(d->keyboardSingleStep, 0);
3361 break;
3362 case Qt::Key_Up:
3363 if (keyEvent->modifiers() & Qt::ShiftModifier)
3364 delta = QPoint(0, -d->keyboardPageStep);
3365 else
3366 delta = QPoint(0, -d->keyboardSingleStep);
3367 break;
3368 case Qt::Key_Left:
3369 if (keyEvent->modifiers() & Qt::ShiftModifier)
3370 delta = QPoint(-d->keyboardPageStep, 0);
3371 else
3372 delta = QPoint(-d->keyboardSingleStep, 0);
3373 break;
3374 case Qt::Key_Down:
3375 if (keyEvent->modifiers() & Qt::ShiftModifier)
3376 delta = QPoint(0, d->keyboardPageStep);
3377 else
3378 delta = QPoint(0, d->keyboardSingleStep);
3379 break;
3380 case Qt::Key_Escape:
3381 case Qt::Key_Return:
3382 case Qt::Key_Enter:
3383 d->leaveInteractiveMode();
3384 return;
3385 default:
3386 keyEvent->ignore();
3387 return;
3388 }
3389
3390#ifndef QT_NO_CURSOR
3391 QPoint newPosition = parentWidget()->mapFromGlobal(cursor().pos() + delta);
3392 QRect oldGeometry =
3393#ifndef QT_NO_RUBBERBAND
3394 d->isInRubberBandMode ? d->rubberBand->geometry() :
3395#endif
3396 geometry();
3397 d->setNewGeometry(newPosition);
3398 QRect currentGeometry =
3399#ifndef QT_NO_RUBBERBAND
3400 d->isInRubberBandMode ? d->rubberBand->geometry() :
3401#endif
3402 geometry();
3403 if (currentGeometry == oldGeometry)
3404 return;
3405
3406 // Update cursor position
3407
3408 QPoint actualDelta;
3409 if (d->isMoveOperation()) {
3410 actualDelta = QPoint(currentGeometry.x() - oldGeometry.x(),
3411 currentGeometry.y() - oldGeometry.y());
3412 } else {
3413 int dx = isLeftToRight() ? currentGeometry.width() - oldGeometry.width()
3414 : currentGeometry.x() - oldGeometry.x();
3415 actualDelta = QPoint(dx, currentGeometry.height() - oldGeometry.height());
3416 }
3417
3418 // Adjust in case we weren't able to move as long as wanted.
3419 if (actualDelta != delta)
3420 newPosition += (actualDelta - delta);
3421 cursor().setPos(parentWidget()->mapToGlobal(newPosition));
3422#endif
3423}
3424
3425#ifndef QT_NO_CONTEXTMENU
3426/*!
3427 \reimp
3428*/
3429void QMdiSubWindow::contextMenuEvent(QContextMenuEvent *contextMenuEvent)
3430{
3431 Q_D(QMdiSubWindow);
3432 if (!d->systemMenu) {
3433 contextMenuEvent->ignore();
3434 return;
3435 }
3436
3437 if (d->hoveredSubControl == QStyle::SC_TitleBarSysMenu
3438 || d->getRegion(QMdiSubWindowPrivate::Move).contains(contextMenuEvent->pos())) {
3439 d->systemMenu->exec(contextMenuEvent->globalPos());
3440 } else {
3441 contextMenuEvent->ignore();
3442 }
3443}
3444#endif // QT_NO_CONTEXTMENU
3445
3446/*!
3447 \reimp
3448*/
3449void QMdiSubWindow::focusInEvent(QFocusEvent *focusInEvent)
3450{
3451 d_func()->focusInReason = focusInEvent->reason();
3452}
3453
3454/*!
3455 \reimp
3456*/
3457void QMdiSubWindow::focusOutEvent(QFocusEvent * /*focusOutEvent*/)
3458{
3459 // To avoid update() in QWidget::focusOutEvent.
3460}
3461
3462/*!
3463 \reimp
3464*/
3465void QMdiSubWindow::childEvent(QChildEvent *childEvent)
3466{
3467 if (childEvent->type() != QEvent::ChildPolished)
3468 return;
3469#ifndef QT_NO_SIZEGRIP
3470 if (QSizeGrip *sizeGrip = qobject_cast<QSizeGrip *>(childEvent->child()))
3471 d_func()->setSizeGrip(sizeGrip);
3472#endif
3473}
3474
3475/*!
3476 \reimp
3477*/
3478QSize QMdiSubWindow::sizeHint() const
3479{
3480 Q_D(const QMdiSubWindow);
3481 int margin, minWidth;
3482 d->sizeParameters(&margin, &minWidth);
3483 QSize size(2 * margin, d->titleBarHeight() + margin);
3484 if (d->baseWidget && d->baseWidget->sizeHint().isValid())
3485 size += d->baseWidget->sizeHint();
3486 return size.expandedTo(minimumSizeHint());
3487}
3488
3489/*!
3490 \reimp
3491*/
3492QSize QMdiSubWindow::minimumSizeHint() const
3493{
3494 Q_D(const QMdiSubWindow);
3495 if (isVisible())
3496 ensurePolished();
3497
3498 // Minimized window.
3499 if (parent() && isMinimized() && !isShaded())
3500 return d->iconSize();
3501
3502 // Calculate window decoration.
3503 int margin, minWidth;
3504 d->sizeParameters(&margin, &minWidth);
3505 int decorationHeight = margin + d->titleBarHeight();
3506 int minHeight = decorationHeight;
3507
3508 // Shaded window.
3509 if (parent() && isShaded())
3510 return QSize(qMax(minWidth, width()), d->titleBarHeight());
3511
3512 // Content
3513 if (layout()) {
3514 QSize minLayoutSize = layout()->minimumSize();
3515 if (minLayoutSize.isValid()) {
3516 minWidth = qMax(minWidth, minLayoutSize.width() + 2 * margin);
3517 minHeight += minLayoutSize.height();
3518 }
3519 } else if (d->baseWidget && d->baseWidget->isVisible()) {
3520 QSize minBaseWidgetSize = d->baseWidget->minimumSizeHint();
3521 if (minBaseWidgetSize.isValid()) {
3522 minWidth = qMax(minWidth, minBaseWidgetSize.width() + 2 * margin);
3523 minHeight += minBaseWidgetSize.height();
3524 }
3525 }
3526
3527#ifndef QT_NO_SIZEGRIP
3528 // SizeGrip
3529 int sizeGripHeight = 0;
3530 if (d->sizeGrip && d->sizeGrip->isVisibleTo(const_cast<QMdiSubWindow *>(this)))
3531 sizeGripHeight = d->sizeGrip->height();
3532#if defined(Q_WS_MAC) && !defined(QT_NO_STYLE_MAC)
3533 else if (parent() && qobject_cast<QMacStyle *>(style()) && !d->sizeGrip)
3534 sizeGripHeight = style()->pixelMetric(QStyle::PM_SizeGripSize, 0, this);
3535#endif
3536 minHeight = qMax(minHeight, decorationHeight + sizeGripHeight);
3537#endif
3538
3539 return QSize(minWidth, minHeight).expandedTo(QApplication::globalStrut());
3540}
3541
3542QT_END_NAMESPACE
3543
3544#include "moc_qmdisubwindow.cpp"
3545#include "qmdisubwindow.moc"
3546
3547#endif //QT_NO_MDIAREA
Note: See TracBrowser for help on using the repository browser.