/****************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the QtGui module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
/*!
\class QMdiSubWindow
\brief The QMdiSubWindow class provides a subwindow class for
QMdiArea.
\since 4.3
\ingroup mainwindow-classes
QMdiSubWindow represents a top-level window in a QMdiArea, and consists
of a title bar with window decorations, an internal widget, and
(depending on the current style) a window frame and a size
grip. QMdiSubWindow has its own layout, which consists of the
title bar and a center area for the internal widget.
\image qmdisubwindowlayout.png
The most common way to construct a QMdiSubWindow is to call
QMdiArea::addSubWindow() with the internal widget as the argument.
You can also create a subwindow yourself, and set an internal
widget by calling setWidget().
You use the same API when programming with subwindows as with
regular top-level windows (e.g., you can call functions such as
show(), hide(), showMaximized(), and setWindowTitle()).
\section1 Subwindow Handling
QMdiSubWindow also supports behavior specific to subwindows in
an MDI area.
By default, each QMdiSubWindow is visible inside the MDI area
viewport when moved around, but it is also possible to specify
transparent window movement and resizing behavior, where only
the outline of a subwindow is updated during these operations.
The setOption() function is used to enable this behavior.
The isShaded() function detects whether the subwindow is
currently shaded (i.e., the window is collapsed so that only the
title bar is visible). To enter shaded mode, call showShaded().
QMdiSubWindow emits the windowStateChanged() signal whenever the
window state has changed (e.g., when the window becomes minimized,
or is restored). It also emits aboutToActivate() before it is
activated.
In keyboard-interactive mode, the windows are moved and resized
with the keyboard. You can enter this mode through the system menu
of the window. The keyboardSingleStep and keyboardPageStep
properties control the distance the widget is moved or resized for
each keypress event. When shift is pressed down page step is used;
otherwise single step is used.
You can also change the active window with the keyboard. By
pressing the control and tab keys at the same time, the next
(using the current \l{QMdiArea::}{WindowOrder}) subwindow will be
activated. By pressing control, shift, and tab, you will activate
the previous window. This is equivalent to calling
\l{QMdiArea::}{activateNextSubWindow()} and
\l{QMdiArea::}{activatePreviousSubWindow()}. Note that these
shortcuts overrides global shortcuts, but not the \l{QMdiArea}s
shortcuts.
\sa QMdiArea
*/
/*!
\enum QMdiSubWindow::SubWindowOption
This enum describes options that customize the behavior
of QMdiSubWindow.
\omitvalue AllowOutsideAreaHorizontally
\omitvalue AllowOutsideAreaVertically
\value RubberBandResize If you enable this option, a rubber band
control is used to represent the subwindow's outline, and the user
resizes this instead of the subwindow itself.
As a result, the subwindow maintains its original position and size
until the resize operation has been completed, at which time it will
receive a single QResizeEvent.
By default, this option is disabled.
\value RubberBandMove If you enable this option, a rubber band
control is used to represent the subwindow's outline, and the user
moves this instead of the subwindow itself.
As a result, the subwindow remains in its original position until
the move operation has completed, at which time a QMoveEvent is
sent to the window. By default, this option is disabled.
*/
/*!
\fn QMdiSubWindow::windowStateChanged(Qt::WindowStates oldState, Qt::WindowStates newState)
QMdiSubWindow emits this signal after the window state changes. \a
oldState is the window state before it changed, and \a newState is the
new, current state.
*/
/*!
\fn QMdiSubWindow::aboutToActivate()
QMdiSubWindow emits this signal immediately before it is
activated. After the subwindow has been activated, the QMdiArea that
manages the subwindow will also emit the
\l{QMdiArea::}{subWindowActivated()} signal.
\sa QMdiArea::subWindowActivated()
*/
#include "qmdisubwindow_p.h"
#ifndef QT_NO_MDIAREA
#include <QApplication>
#include <QStylePainter>
#include <QVBoxLayout>
#include <QMouseEvent>
#include <QWhatsThis>
#include <QToolTip>
#include <QMainWindow>
#include <QScrollBar>
#include <QDebug>
#if defined(Q_WS_MAC) && !defined(QT_NO_STYLE_MAC)
#include <QMacStyle>
#endif
#include <QMdiArea>
QT_BEGIN_NAMESPACE
using namespace QMdi;
static const QStyle::SubControl SubControls[] =
{
QStyle::SC_TitleBarLabel, // 1
QStyle::SC_TitleBarSysMenu, // 2
QStyle::SC_TitleBarMinButton, // 3
QStyle::SC_TitleBarMaxButton, // 4
QStyle::SC_TitleBarShadeButton, // 5
QStyle::SC_TitleBarCloseButton, // 6
QStyle::SC_TitleBarNormalButton, // 7
QStyle::SC_TitleBarUnshadeButton, // 8
QStyle::SC_TitleBarContextHelpButton // 9
};
static const int NumSubControls = sizeof(SubControls) / sizeof(SubControls[0]);
static const QStyle::StandardPixmap ButtonPixmaps[] =
{
QStyle::SP_TitleBarMinButton,
QStyle::SP_TitleBarNormalButton,
QStyle::SP_TitleBarCloseButton
};
static const int NumButtonPixmaps = sizeof(ButtonPixmaps) / sizeof(ButtonPixmaps[0]);
static const Qt::WindowFlags CustomizeWindowFlags =
Qt::FramelessWindowHint
| Qt::CustomizeWindowHint
| Qt::WindowTitleHint
| Qt::WindowSystemMenuHint
| Qt::WindowMinimizeButtonHint
| Qt::WindowMaximizeButtonHint
| Qt::WindowMinMaxButtonsHint;
static const int BoundaryMargin = 5;
static inline int getMoveDeltaComponent(uint cflags, uint moveFlag, uint resizeFlag,
int delta, int maxDelta, int minDelta)
{
if (cflags & moveFlag) {
if (delta > 0)
return (cflags & resizeFlag) ? qMin(delta, maxDelta) : delta;
return (cflags & resizeFlag) ? qMax(delta, minDelta) : delta;
}
return 0;
}
static inline int getResizeDeltaComponent(uint cflags, uint resizeFlag,
uint resizeReverseFlag, int delta)
{
if (cflags & resizeFlag) {
if (cflags & resizeReverseFlag)
return -delta;
return delta;
}
return 0;
}
static inline bool isChildOfQMdiSubWindow(const QWidget *child)
{
Q_ASSERT(child);
QWidget *parent = child->parentWidget();
while (parent) {
if (qobject_cast<QMdiSubWindow *>(parent))
return true;
parent = parent->parentWidget();
}
return false;
}
static inline bool isChildOfTabbedQMdiArea(const QMdiSubWindow *child)
{
Q_ASSERT(child);
if (QMdiArea *mdiArea = child->mdiArea()) {
if (mdiArea->viewMode() == QMdiArea::TabbedView)
return true;
}
return false;
}
template<typename T>
static inline ControlElement<T> *ptr(QWidget *widget)
{
if (widget && widget->qt_metacast("ControlElement")
&& strcmp(widget->metaObject()->className(), T::staticMetaObject.className()) == 0) {
return static_cast<ControlElement<T> *>(widget);
}
return 0;
}
QString QMdiSubWindowPrivate::originalWindowTitle()
{
Q_Q(QMdiSubWindow);
if (originalTitle.isNull()) {
originalTitle = q->window()->windowTitle();
if (originalTitle.isNull())
originalTitle = QLatin1String("");
}
return originalTitle;
}
void QMdiSubWindowPrivate::setNewWindowTitle()
{
Q_Q(QMdiSubWindow);
QString childTitle = q->windowTitle();
if (childTitle.isEmpty())
return;
QString original = originalWindowTitle();
if (!original.isEmpty()) {
if (!original.contains(QMdiSubWindow::tr("- [%1]").arg(childTitle)))
q->window()->setWindowTitle(QMdiSubWindow::tr("%1 - [%2]").arg(original, childTitle));
} else {
q->window()->setWindowTitle(childTitle);
}
}
static inline bool isHoverControl(QStyle::SubControl control)
{
return control != QStyle::SC_None && control != QStyle::SC_TitleBarLabel;
}
#if defined(Q_WS_WIN)
static inline QRgb colorref2qrgb(COLORREF col)
{
return qRgb(GetRValue(col),GetGValue(col),GetBValue(col));
}
#endif
#ifndef QT_NO_TOOLTIP
static void showToolTip(QHelpEvent *helpEvent, QWidget *widget, const QStyleOptionComplex &opt,
QStyle::ComplexControl complexControl, QStyle::SubControl subControl)
{
Q_ASSERT(helpEvent);
Q_ASSERT(helpEvent->type() == QEvent::ToolTip);
Q_ASSERT(widget);
#if defined(Q_WS_MAC) && !defined(QT_NO_STYLE_MAC)
// Native Mac windows don't show tool tip.
if (qobject_cast<QMacStyle *>(widget->style()))
return;
#endif
// Convert CC_MdiControls to CC_TitleBar. Sub controls of different complex
// controls cannot be in the same switch as they might have the same value.
if (complexControl == QStyle::CC_MdiControls) {
if (subControl == QStyle::SC_MdiMinButton)
subControl = QStyle::SC_TitleBarMinButton;
else if (subControl == QStyle::SC_MdiCloseButton)
subControl = QStyle::SC_TitleBarCloseButton;
else if (subControl == QStyle::SC_MdiNormalButton)
subControl = QStyle::SC_TitleBarNormalButton;
else
subControl = QStyle::SC_None;
}
// Don't change the tooltip for the base widget itself.
if (subControl == QStyle::SC_None)
return;
QString toolTip;
switch (subControl) {
case QStyle::SC_TitleBarMinButton:
toolTip = QMdiSubWindow::tr("Minimize");
break;
case QStyle::SC_TitleBarMaxButton:
toolTip = QMdiSubWindow::tr("Maximize");
break;
case QStyle::SC_TitleBarUnshadeButton:
toolTip = QMdiSubWindow::tr("Unshade");
break;
case QStyle::SC_TitleBarShadeButton:
toolTip = QMdiSubWindow::tr("Shade");
break;
case QStyle::SC_TitleBarNormalButton:
if (widget->isMaximized() || !qobject_cast<QMdiSubWindow *>(widget))
toolTip = QMdiSubWindow::tr("Restore Down");
else
toolTip = QMdiSubWindow::tr("Restore");
break;
case QStyle::SC_TitleBarCloseButton:
toolTip = QMdiSubWindow::tr("Close");
break;
case QStyle::SC_TitleBarContextHelpButton:
toolTip = QMdiSubWindow::tr("Help");
break;
case QStyle::SC_TitleBarSysMenu:
toolTip = QMdiSubWindow::tr("Menu");
break;
default:
break;
}
const QRect rect = widget->style()->subControlRect(complexControl, &opt, subControl, widget);
QToolTip::showText(helpEvent->globalPos(), toolTip, widget, rect);
}
#endif // QT_NO_TOOLTIP
namespace QMdi {
/*
\class ControlLabel
\internal
*/
class ControlLabel : public QWidget
{
Q_OBJECT
public:
ControlLabel(QMdiSubWindow *subWindow, QWidget *parent = 0);
QSize sizeHint() const;
signals:
void _q_clicked();
void _q_doubleClicked();
protected:
bool event(QEvent *event);
void paintEvent(QPaintEvent *paintEvent);
void mousePressEvent(QMouseEvent *mouseEvent);
void mouseDoubleClickEvent(QMouseEvent *mouseEvent);
void mouseReleaseEvent(QMouseEvent *mouseEvent);
private:
QPixmap label;
bool isPressed;
void updateWindowIcon();
};
} // namespace QMdi
ControlLabel::ControlLabel(QMdiSubWindow *subWindow, QWidget *parent)
: QWidget(parent), isPressed(false)
{
Q_UNUSED(subWindow);
setFocusPolicy(Qt::NoFocus);
updateWindowIcon();
setFixedSize(label.size());
}
/*
\internal
*/
QSize ControlLabel::sizeHint() const
{
return label.size();
}
/*
\internal
*/
bool ControlLabel::event(QEvent *event)
{
if (event->type() == QEvent::WindowIconChange)
updateWindowIcon();
#ifndef QT_NO_TOOLTIP
else if (event->type() == QEvent::ToolTip) {
QStyleOptionTitleBar options;
options.initFrom(this);
showToolTip(static_cast<QHelpEvent *>(event), this, options,
QStyle::CC_TitleBar, QStyle::SC_TitleBarSysMenu);
}
#endif
return QWidget::event(event);
}
/*
\internal
*/
void ControlLabel::paintEvent(QPaintEvent * /*paintEvent*/)
{
QPainter painter(this);
painter.drawPixmap(0, 0, label);
}
/*
\internal
*/
void ControlLabel::mousePressEvent(QMouseEvent *mouseEvent)
{
if (mouseEvent->button() != Qt::LeftButton) {
mouseEvent->ignore();
return;
}
isPressed = true;
}
/*
\internal
*/
void ControlLabel::mouseDoubleClickEvent(QMouseEvent *mouseEvent)
{
if (mouseEvent->button() != Qt::LeftButton) {
mouseEvent->ignore();
return;
}
isPressed = false;
emit _q_doubleClicked();
}
/*
\internal
*/
void ControlLabel::mouseReleaseEvent(QMouseEvent *mouseEvent)
{
if (mouseEvent->button() != Qt::LeftButton) {
mouseEvent->ignore();
return;
}
if (isPressed) {
isPressed = false;
emit _q_clicked();
}
}
/*
\internal
*/
void ControlLabel::updateWindowIcon()
{
QIcon menuIcon = windowIcon();
if (menuIcon.isNull())
menuIcon = style()->standardIcon(QStyle::SP_TitleBarMenuButton, 0, parentWidget());
label = menuIcon.pixmap(16, 16);
update();
}
namespace QMdi {
/*
\class ControllerWidget
\internal
*/
class ControllerWidget : public QWidget
{
Q_OBJECT
public:
ControllerWidget(QMdiSubWindow *subWindow, QWidget *parent = 0);
QSize sizeHint() const;
void setControlVisible(QMdiSubWindowPrivate::WindowStateAction action, bool visible);
inline bool hasVisibleControls() const
{
return (visibleControls & QStyle::SC_MdiMinButton)
|| (visibleControls & QStyle::SC_MdiNormalButton)
|| (visibleControls & QStyle::SC_MdiCloseButton);
}
signals:
void _q_minimize();
void _q_restore();
void _q_close();
protected:
void paintEvent(QPaintEvent *event);
void mousePressEvent(QMouseEvent *event);
void mouseReleaseEvent(QMouseEvent *event);
void mouseMoveEvent(QMouseEvent *event);
void leaveEvent(QEvent *event);
bool event(QEvent *event);
private:
QStyle::SubControl activeControl;
QStyle::SubControl hoverControl;
QStyle::SubControls visibleControls;
void initStyleOption(QStyleOptionComplex *option) const;
QMdiArea *mdiArea;
inline QStyle::SubControl getSubControl(const QPoint &pos) const
{
QStyleOptionComplex opt;
initStyleOption(&opt);
return style()->hitTestComplexControl(QStyle::CC_MdiControls, &opt, pos, mdiArea);
}
};
} // namespace QMdi
/*
\internal
*/
ControllerWidget::ControllerWidget(QMdiSubWindow *subWindow, QWidget *parent)
: QWidget(parent),
activeControl(QStyle::SC_None),
hoverControl(QStyle::SC_None),
visibleControls(QStyle::SC_None),
mdiArea(0)
{
if (subWindow->parentWidget())
mdiArea = qobject_cast<QMdiArea *>(subWindow->parentWidget()->parentWidget());
setFocusPolicy(Qt::NoFocus);
setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
setMouseTracking(true);
}
/*
\internal
*/
QSize ControllerWidget::sizeHint() const
{
ensurePolished();
QStyleOptionComplex opt;
initStyleOption(&opt);
QSize size(48, 16);
return style()->sizeFromContents(QStyle::CT_MdiControls, &opt, size, mdiArea);
}
void ControllerWidget::setControlVisible(QMdiSubWindowPrivate::WindowStateAction action, bool visible)
{
QStyle::SubControl subControl = QStyle::SC_None;
// Map action from QMdiSubWindowPrivate::WindowStateAction to QStyle::SubControl.
if (action == QMdiSubWindowPrivate::MaximizeAction)
subControl = QStyle::SC_MdiNormalButton;
else if (action == QMdiSubWindowPrivate::CloseAction)
subControl = QStyle::SC_MdiCloseButton;
else if (action == QMdiSubWindowPrivate::MinimizeAction)
subControl = QStyle::SC_MdiMinButton;
if (subControl == QStyle::SC_None)
return;
if (visible && !(visibleControls & subControl))
visibleControls |= subControl;
else if (!visible && (visibleControls & subControl))
visibleControls &= ~subControl;
}
/*
\internal
*/
void ControllerWidget::paintEvent(QPaintEvent * /*paintEvent*/)
{
QStyleOptionComplex opt;
initStyleOption(&opt);
if (activeControl == hoverControl) {
opt.activeSubControls = activeControl;
opt.state |= QStyle::State_Sunken;
} else if (hoverControl != QStyle::SC_None && (activeControl == QStyle::SC_None)) {
opt.activeSubControls = hoverControl;
opt.state |= QStyle::State_MouseOver;
}
QPainter painter(this);
style()->drawComplexControl(QStyle::CC_MdiControls, &opt, &painter, mdiArea);
}
/*
\internal
*/
void ControllerWidget::mousePressEvent(QMouseEvent *event)
{
if (event->button() != Qt::LeftButton) {
event->ignore();
return;
}
activeControl = getSubControl(event->pos());
update();
}
/*
\internal
*/
void ControllerWidget::mouseReleaseEvent(QMouseEvent *event)
{
if (event->button() != Qt::LeftButton) {
event->ignore();
return;
}
QStyle::SubControl under_mouse = getSubControl(event->pos());
if (under_mouse == activeControl) {
switch (activeControl) {
case QStyle::SC_MdiCloseButton:
emit _q_close();
break;
case QStyle::SC_MdiNormalButton:
emit _q_restore();
break;
case QStyle::SC_MdiMinButton:
emit _q_minimize();
break;
default:
break;
}
}
activeControl = QStyle::SC_None;
update();
}
/*
\internal
*/
void ControllerWidget::mouseMoveEvent(QMouseEvent *event)
{
QStyle::SubControl under_mouse = getSubControl(event->pos());
//test if hover state changes
if (hoverControl != under_mouse) {
hoverControl = under_mouse;
update();
}
}
/*
\internal
*/
void ControllerWidget::leaveEvent(QEvent * /*event*/)
{
hoverControl = QStyle::SC_None;
update();
}
/*
\internal
*/
bool ControllerWidget::event(QEvent *event)
{
#ifndef QT_NO_TOOLTIP
if (event->type() == QEvent::ToolTip) {
QStyleOptionComplex opt;
initStyleOption(&opt);
QHelpEvent *helpEvent = static_cast<QHelpEvent *>(event);
showToolTip(helpEvent, this, opt, QStyle::CC_MdiControls, getSubControl(helpEvent->pos()));
}
#endif // QT_NO_TOOLTIP
return QWidget::event(event);
}
/*
\internal
*/
void ControllerWidget::initStyleOption(QStyleOptionComplex *option) const
{
option->initFrom(this);
option->subControls = visibleControls;
option->activeSubControls = QStyle::SC_None;
}
/*
\internal
*/
ControlContainer::ControlContainer(QMdiSubWindow *mdiChild)
: QObject(mdiChild),
previousLeft(0),
previousRight(0),
#ifndef QT_NO_MENUBAR
m_menuBar(0),
#endif
mdiChild(mdiChild)
{
Q_ASSERT(mdiChild);
m_controllerWidget = new ControlElement<ControllerWidget>(mdiChild);
connect(m_controllerWidget, SIGNAL(_q_close()), mdiChild, SLOT(close()));
connect(m_controllerWidget, SIGNAL(_q_restore()), mdiChild, SLOT(showNormal()));
connect(m_controllerWidget, SIGNAL(_q_minimize()), mdiChild, SLOT(showMinimized()));
m_menuLabel = new ControlElement<ControlLabel>(mdiChild);
m_menuLabel->setWindowIcon(mdiChild->windowIcon());
#ifndef QT_NO_MENU
connect(m_menuLabel, SIGNAL(_q_clicked()), mdiChild, SLOT(showSystemMenu()));
#endif
connect(m_menuLabel, SIGNAL(_q_doubleClicked()), mdiChild, SLOT(close()));
}
ControlContainer::~ControlContainer()
{
#ifndef QT_NO_MENUBAR
removeButtonsFromMenuBar();
#endif
delete m_menuLabel;
m_menuLabel = 0;
delete m_controllerWidget;
m_controllerWidget = 0;
}
#ifndef QT_NO_MENUBAR
/*
\internal
*/
QMenuBar *QMdiSubWindowPrivate::menuBar() const
{
#if defined(QT_NO_MAINWINDOW)
return 0;
#else
Q_Q(const QMdiSubWindow);
if (!q->isMaximized() || drawTitleBarWhenMaximized() || isChildOfTabbedQMdiArea(q))
return 0;
if (QMainWindow *mainWindow = qobject_cast<QMainWindow *>(q->window()))
return mainWindow->menuBar();
return 0;
#endif
}
/*
\internal
*/
void ControlContainer::showButtonsInMenuBar(QMenuBar *menuBar)
{
if (!menuBar || !mdiChild || mdiChild->windowFlags() & Qt::FramelessWindowHint)
return;
m_menuBar = menuBar;
if (m_menuLabel && mdiChild->windowFlags() & Qt::WindowSystemMenuHint) {
QWidget *currentLeft = menuBar->cornerWidget(Qt::TopLeftCorner);
if (currentLeft)
currentLeft->hide();
if (currentLeft != m_menuLabel) {
menuBar->setCornerWidget(m_menuLabel, Qt::TopLeftCorner);
previousLeft = currentLeft;
}
m_menuLabel->show();
}
ControllerWidget *controllerWidget = qobject_cast<ControllerWidget *>(m_controllerWidget);
if (controllerWidget && controllerWidget->hasVisibleControls()) {
QWidget *currentRight = menuBar->cornerWidget(Qt::TopRightCorner);
if (currentRight)
currentRight->hide();
if (currentRight != m_controllerWidget) {
menuBar->setCornerWidget(m_controllerWidget, Qt::TopRightCorner);
previousRight = currentRight;
}
m_controllerWidget->show();
}
mdiChild->d_func()->setNewWindowTitle();
}
/*
\internal
*/
void ControlContainer::removeButtonsFromMenuBar(QMenuBar *menuBar)
{
if (menuBar && menuBar != m_menuBar) {
// m_menubar was deleted while sub-window was maximized
previousRight = 0;
previousLeft = 0;
m_menuBar = menuBar;
}
if (!m_menuBar || !mdiChild || qt_widget_private(mdiChild->window())->data.in_destructor)
return;
QMdiSubWindow *child = 0;
if (m_controllerWidget) {
QWidget *currentRight = m_menuBar->cornerWidget(Qt::TopRightCorner);
if (currentRight == m_controllerWidget) {
if (ControlElement<ControllerWidget> *ce = ptr<ControllerWidget>(previousRight)) {
if (!ce->mdiChild || !ce->mdiChild->isMaximized())
previousRight = 0;
else
child = ce->mdiChild;
}
m_menuBar->setCornerWidget(previousRight, Qt::TopRightCorner);
if (previousRight) {
previousRight->show();
previousRight = 0;
}
}
m_controllerWidget->hide();
m_controllerWidget->setParent(0);
}
if (m_menuLabel) {
QWidget *currentLeft = m_menuBar->cornerWidget(Qt::TopLeftCorner);
if (currentLeft == m_menuLabel) {
if (ControlElement<ControlLabel> *ce = ptr<ControlLabel>(previousLeft)) {
if (!ce->mdiChild || !ce->mdiChild->isMaximized())
previousLeft = 0;
else if (!child)
child = mdiChild;
}
m_menuBar->setCornerWidget(previousLeft, Qt::TopLeftCorner);
if (previousLeft) {
previousLeft->show();
previousLeft = 0;
}
}
m_menuLabel->hide();
m_menuLabel->setParent(0);
}
m_menuBar->update();
if (child)
child->d_func()->setNewWindowTitle();
else if (mdiChild)
mdiChild->window()->setWindowTitle(mdiChild->d_func()->originalWindowTitle());
}
#endif // QT_NO_MENUBAR
void ControlContainer::updateWindowIcon(const QIcon &windowIcon)
{
if (m_menuLabel)
m_menuLabel->setWindowIcon(windowIcon);
}
/*!
\internal
*/
QMdiSubWindowPrivate::QMdiSubWindowPrivate()
: baseWidget(0),
restoreFocusWidget(0),
controlContainer(0),
#ifndef QT_NO_SIZEGRIP
sizeGrip(0),
#endif
#ifndef QT_NO_RUBBERBAND
rubberBand(0),
#endif
userMinimumSize(0,0),
resizeEnabled(true),
moveEnabled(true),
isInInteractiveMode(false),
#ifndef QT_NO_RUBBERBAND
isInRubberBandMode(false),
#endif
isShadeMode(false),
ignoreWindowTitleChange(false),
ignoreNextActivationEvent(false),
activationEnabled(true),
isShadeRequestFromMinimizeMode(false),
isMaximizeMode(false),
isWidgetHiddenByUs(false),
isActive(false),
isExplicitlyDeactivated(false),
keyboardSingleStep(5),
keyboardPageStep(20),
resizeTimerId(-1),
currentOperation(None),
hoveredSubControl(QStyle::SC_None),
activeSubControl(QStyle::SC_None),
focusInReason(Qt::ActiveWindowFocusReason)
{
initOperationMap();
}
/*!
\internal
*/
void QMdiSubWindowPrivate::_q_updateStaysOnTopHint()
{
#ifndef QT_NO_ACTION
Q_Q(QMdiSubWindow);
if (QAction *senderAction = qobject_cast<QAction *>(q->sender())) {
if (senderAction->isChecked()) {
q->setWindowFlags(q->windowFlags() | Qt::WindowStaysOnTopHint);
q->raise();
} else {
q->setWindowFlags(q->windowFlags() & ~Qt::WindowStaysOnTopHint);
q->lower();
}
}
#endif // QT_NO_ACTION
}
/*!
\internal
*/
void QMdiSubWindowPrivate::_q_enterInteractiveMode()
{
#ifndef QT_NO_ACTION
Q_Q(QMdiSubWindow);
QAction *action = qobject_cast<QAction *>(q->sender());
if (!action)
return;
QPoint pressPos;
if (actions[MoveAction] && actions[MoveAction] == action) {
currentOperation = Move;
pressPos = QPoint(q->width() / 2, titleBarHeight() - 1);
} else if (actions[ResizeAction] && actions[ResizeAction] == action) {
currentOperation = q->isLeftToRight() ? BottomRightResize : BottomLeftResize;
int offset = q->style()->pixelMetric(QStyle::PM_MdiSubWindowFrameWidth, 0, q) / 2;
int x = q->isLeftToRight() ? q->width() - offset : offset;
pressPos = QPoint(x, q->height() - offset);
} else {
return;
}
updateCursor();
#ifndef QT_NO_CURSOR
q->cursor().setPos(q->mapToGlobal(pressPos));
#endif
mousePressPosition = q->mapToParent(pressPos);
oldGeometry = q->geometry();
isInInteractiveMode = true;
q->setFocus();
#ifndef QT_NO_RUBBERBAND
if ((q->testOption(QMdiSubWindow::RubberBandResize)
&& (currentOperation == BottomRightResize || currentOperation == BottomLeftResize))
|| (q->testOption(QMdiSubWindow::RubberBandMove) && currentOperation == Move)) {
enterRubberBandMode();
} else
#endif // QT_NO_RUBBERBAND
{
q->grabMouse();
}
#endif // QT_NO_ACTION
}
/*!
\internal
*/
void QMdiSubWindowPrivate::_q_processFocusChanged(QWidget *old, QWidget *now)
{
Q_UNUSED(old);
Q_Q(QMdiSubWindow);
if (now && (now == q || q->isAncestorOf(now))) {
if (now == q && !isInInteractiveMode)
setFocusWidget();
setActive(true);
}
}
/*!
\internal
*/
void QMdiSubWindowPrivate::leaveInteractiveMode()
{
Q_Q(QMdiSubWindow);
#ifndef QT_NO_RUBBERBAND
if (isInRubberBandMode)
leaveRubberBandMode();
else
#endif
q->releaseMouse();
isInInteractiveMode = false;
currentOperation = None;
updateDirtyRegions();
updateCursor();
if (baseWidget && baseWidget->focusWidget())
baseWidget->focusWidget()->setFocus();
}
/*!
\internal
*/
void QMdiSubWindowPrivate::removeBaseWidget()
{
if (!baseWidget)
return;
Q_Q(QMdiSubWindow);
baseWidget->removeEventFilter(q);
if (layout)
layout->removeWidget(baseWidget);
if (baseWidget->windowTitle() == q->windowTitle()) {
ignoreWindowTitleChange = true;
q->setWindowTitle(QString());
ignoreWindowTitleChange = false;
q->setWindowModified(false);
}
lastChildWindowTitle.clear();
baseWidget->setParent(0);
baseWidget = 0;
isWidgetHiddenByUs = false;
}
/*!
\internal
*/
void QMdiSubWindowPrivate::initOperationMap()
{
operationMap.insert(Move, OperationInfo(HMove | VMove, Qt::ArrowCursor, false));
operationMap.insert(TopResize, OperationInfo(VMove | VResize | VResizeReverse, Qt::SizeVerCursor));
operationMap.insert(BottomResize, OperationInfo(VResize, Qt::SizeVerCursor));
operationMap.insert(LeftResize, OperationInfo(HMove | HResize | HResizeReverse, Qt::SizeHorCursor));
operationMap.insert(RightResize, OperationInfo(HResize, Qt::SizeHorCursor));
operationMap.insert(TopLeftResize, OperationInfo(HMove | VMove | HResize | VResize | VResizeReverse
| HResizeReverse, Qt::SizeFDiagCursor));
operationMap.insert(TopRightResize, OperationInfo(VMove | HResize | VResize
| VResizeReverse, Qt::SizeBDiagCursor));
operationMap.insert(BottomLeftResize, OperationInfo(HMove | HResize | VResize | HResizeReverse,
Qt::SizeBDiagCursor));
operationMap.insert(BottomRightResize, OperationInfo(HResize | VResize, Qt::SizeFDiagCursor));
}
#ifndef QT_NO_MENU
/*!
\internal
*/
void QMdiSubWindowPrivate::createSystemMenu()
{
Q_Q(QMdiSubWindow);
Q_ASSERT_X(q, "QMdiSubWindowPrivate::createSystemMenu",
"You can NOT call this function before QMdiSubWindow's ctor");
systemMenu = new QMenu(q);
const QStyle *style = q->style();
addToSystemMenu(RestoreAction, QMdiSubWindow::tr("&Restore"), SLOT(showNormal()));
actions[RestoreAction]->setIcon(style->standardIcon(QStyle::SP_TitleBarNormalButton, 0, q));
actions[RestoreAction]->setEnabled(false);
addToSystemMenu(MoveAction, QMdiSubWindow::tr("&Move"), SLOT(_q_enterInteractiveMode()));
addToSystemMenu(ResizeAction, QMdiSubWindow::tr("&Size"), SLOT(_q_enterInteractiveMode()));
addToSystemMenu(MinimizeAction, QMdiSubWindow::tr("Mi&nimize"), SLOT(showMinimized()));
actions[MinimizeAction]->setIcon(style->standardIcon(QStyle::SP_TitleBarMinButton, 0, q));
addToSystemMenu(MaximizeAction, QMdiSubWindow::tr("Ma&ximize"), SLOT(showMaximized()));
actions[MaximizeAction]->setIcon(style->standardIcon(QStyle::SP_TitleBarMaxButton, 0, q));
addToSystemMenu(StayOnTopAction, QMdiSubWindow::tr("Stay on &Top"), SLOT(_q_updateStaysOnTopHint()));
actions[StayOnTopAction]->setCheckable(true);
systemMenu->addSeparator();
addToSystemMenu(CloseAction, QMdiSubWindow::tr("&Close"), SLOT(close()));
actions[CloseAction]->setIcon(style->standardIcon(QStyle::SP_TitleBarCloseButton, 0, q));
#if !defined(QT_NO_SHORTCUT)
actions[CloseAction]->setShortcuts(QKeySequence::Close);
#endif
updateActions();
}
#endif
/*!
\internal
*/
void QMdiSubWindowPrivate::updateCursor()
{
#ifndef QT_NO_CURSOR
Q_Q(QMdiSubWindow);
#if defined(Q_WS_MAC) && !defined(QT_NO_STYLE_MAC)
if (qobject_cast<QMacStyle *>(q->style()))
return;
#endif
if (currentOperation == None) {
q->unsetCursor();
return;
}
if (currentOperation == Move || operationMap.find(currentOperation).value().hover) {
q->setCursor(operationMap.find(currentOperation).value().cursorShape);
return;
}
#endif
}
/*!
\internal
*/
void QMdiSubWindowPrivate::updateDirtyRegions()
{
// No update necessary
if (!parent)
return;
foreach (Operation operation, operationMap.keys())
operationMap.find(operation).value().region = getRegion(operation);
}
/*!
\internal
*/
void QMdiSubWindowPrivate::updateGeometryConstraints()
{
Q_Q(QMdiSubWindow);
if (!parent)
return;
internalMinimumSize = (!q->isMinimized() && !q->minimumSize().isNull())
? q->minimumSize() : q->minimumSizeHint();
int margin, minWidth;
sizeParameters(&margin, &minWidth);
q->setContentsMargins(margin, titleBarHeight(), margin, margin);
if (q->isMaximized() || (q->isMinimized() && !q->isShaded())) {
moveEnabled = false;
resizeEnabled = false;
} else {
moveEnabled = true;
if ((q->windowFlags() & Qt::MSWindowsFixedSizeDialogHint) || q->isShaded())
resizeEnabled = false;
else
resizeEnabled = true;
}
updateDirtyRegions();
}
/*!
\internal
*/
void QMdiSubWindowPrivate::updateMask()
{
Q_Q(QMdiSubWindow);
if (!q->mask().isEmpty())
q->clearMask();
if (!parent)
return;
if ((q->isMaximized() && !drawTitleBarWhenMaximized())
|| q->windowFlags() & Qt::FramelessWindowHint)
return;
if (resizeTimerId == -1)
cachedStyleOptions = titleBarOptions();
cachedStyleOptions.rect = q->rect();
QStyleHintReturnMask frameMask;
q->style()->styleHint(QStyle::SH_WindowFrame_Mask, &cachedStyleOptions, q, &frameMask);
if (!frameMask.region.isEmpty())
q->setMask(frameMask.region);
}
/*!
\internal
*/
void QMdiSubWindowPrivate::setNewGeometry(const QPoint &pos)
{
Q_Q(QMdiSubWindow);
Q_ASSERT(currentOperation != None);
Q_ASSERT(parent);
uint cflags = operationMap.find(currentOperation).value().changeFlags;
int posX = pos.x();
int posY = pos.y();
const bool restrictHorizontal = !q->testOption(QMdiSubWindow::AllowOutsideAreaHorizontally);
const bool restrictVertical = !q->testOption(QMdiSubWindow::AllowOutsideAreaVertically);
if (restrictHorizontal || restrictVertical) {
QRect parentRect = q->parentWidget()->rect();
if (restrictVertical && (cflags & VResizeReverse || currentOperation == Move)) {
posY = qMin(qMax(mousePressPosition.y() - oldGeometry.y(), posY),
parentRect.height() - BoundaryMargin);
}
if (currentOperation == Move) {
if (restrictHorizontal)
posX = qMin(qMax(BoundaryMargin, posX), parentRect.width() - BoundaryMargin);
if (restrictVertical)
posY = qMin(posY, parentRect.height() - BoundaryMargin);
} else {
if (restrictHorizontal) {
if (cflags & HResizeReverse)
posX = qMax(mousePressPosition.x() - oldGeometry.x(), posX);
else
posX = qMin(parentRect.width() - (oldGeometry.x() + oldGeometry.width()
- mousePressPosition.x()), posX);
}
if (restrictVertical && !(cflags & VResizeReverse)) {
posY = qMin(parentRect.height() - (oldGeometry.y() + oldGeometry.height()
- mousePressPosition.y()), posY);
}
}
}
QRect geometry;
if (cflags & (HMove | VMove)) {
int dx = getMoveDeltaComponent(cflags, HMove, HResize, posX - mousePressPosition.x(),
oldGeometry.width() - internalMinimumSize.width(),
oldGeometry.width() - q->maximumWidth());
int dy = getMoveDeltaComponent(cflags, VMove, VResize, posY - mousePressPosition.y(),
oldGeometry.height() - internalMinimumSize.height(),
oldGeometry.height() - q->maximumHeight());
geometry.setTopLeft(oldGeometry.topLeft() + QPoint(dx, dy));
} else {
geometry.setTopLeft(q->geometry().topLeft());
}
if (cflags & (HResize | VResize)) {
int dx = getResizeDeltaComponent(cflags, HResize, HResizeReverse,
posX - mousePressPosition.x());
int dy = getResizeDeltaComponent(cflags, VResize, VResizeReverse,
posY - mousePressPosition.y());
geometry.setSize(oldGeometry.size() + QSize(dx, dy));
} else {
geometry.setSize(q->geometry().size());
}
setNewGeometry(&geometry);
}
/*!
\internal
*/
void QMdiSubWindowPrivate::setMinimizeMode()
{
Q_Q(QMdiSubWindow);
Q_ASSERT(parent);
ensureWindowState(Qt::WindowMinimized);
isShadeRequestFromMinimizeMode = true;
q->showShaded();
isShadeRequestFromMinimizeMode = false;
moveEnabled = false;
#ifndef QT_NO_ACTION
setEnabled(MoveAction, moveEnabled);
#endif
Q_ASSERT(q->windowState() & Qt::WindowMinimized);
Q_ASSERT(!(q->windowState() & Qt::WindowMaximized));
// This should be a valid assert, but people can actually re-implement
// setVisible and do crazy stuff, so we're not guaranteed that
// the widget is hidden after calling hide().
// Q_ASSERT(baseWidget ? baseWidget->isHidden() : true);
setActive(true);
}
/*!
\internal
*/
void QMdiSubWindowPrivate::setNormalMode()
{
Q_Q(QMdiSubWindow);
Q_ASSERT(parent);
isShadeMode = false;
isMaximizeMode = false;
ensureWindowState(Qt::WindowNoState);
#ifndef QT_NO_MENUBAR
removeButtonsFromMenuBar();
#endif
// Hide the window before we change the geometry to avoid multiple resize
// events and wrong window state.
const bool wasVisible = q->isVisible();
if (wasVisible)
q->setVisible(false);
// Restore minimum size if set by user.
if (!userMinimumSize.isNull()) {
q->setMinimumSize(userMinimumSize);
userMinimumSize = QSize(0, 0);
}
// Show the internal widget if it was hidden by us,
if (baseWidget && isWidgetHiddenByUs) {
baseWidget->show();
isWidgetHiddenByUs = false;
}
updateGeometryConstraints();
QRect newGeometry = oldGeometry;
newGeometry.setSize(restoreSize.expandedTo(internalMinimumSize));
q->setGeometry(newGeometry);
if (wasVisible)
q->setVisible(true);
// Invalidate the restore size.
restoreSize.setWidth(-1);
restoreSize.setHeight(-1);
#ifndef QT_NO_SIZEGRIP
setSizeGripVisible(true);
#endif
#ifndef QT_NO_ACTION
setEnabled(MoveAction, true);
setEnabled(MaximizeAction, true);
setEnabled(MinimizeAction, true);
setEnabled(RestoreAction, false);
setEnabled(ResizeAction, resizeEnabled);
#endif // QT_NO_ACTION
Q_ASSERT(!(q_func()->windowState() & Qt::WindowMinimized));
// This sub-window can be maximized when shown above if not the
// QMdiArea::DontMaximizeSubWindowOnActionvation is set. Make sure
// the Qt::WindowMaximized flag is set accordingly.
Q_ASSERT((isMaximizeMode && q_func()->windowState() & Qt::WindowMaximized)
|| (!isMaximizeMode && !(q_func()->windowState() & Qt::WindowMaximized)));
Q_ASSERT(!isShadeMode);
setActive(true);
restoreFocus();
updateMask();
}
/*!
\internal
*/
void QMdiSubWindowPrivate::setMaximizeMode()
{
Q_Q(QMdiSubWindow);
Q_ASSERT(parent);
ensureWindowState(Qt::WindowMaximized);
isShadeMode = false;
isMaximizeMode = true;
if (!restoreFocusWidget && q->isAncestorOf(QApplication::focusWidget()))
restoreFocusWidget = QApplication::focusWidget();
#ifndef QT_NO_SIZEGRIP
setSizeGripVisible(false);
#endif
// Store old geometry and set restore size if not already set.
if (!restoreSize.isValid()) {
oldGeometry = q->geometry();
restoreSize.setWidth(oldGeometry.width());
restoreSize.setHeight(oldGeometry.height());
}
// Hide the window before we change the geometry to avoid multiple resize
// events and wrong window state.
const bool wasVisible = q->isVisible();
if (wasVisible)
q->setVisible(false);
// Show the internal widget if it was hidden by us.
if (baseWidget && isWidgetHiddenByUs) {
baseWidget->show();
isWidgetHiddenByUs = false;
}
updateGeometryConstraints();
if (wasVisible) {
#ifndef QT_NO_MENUBAR
if (QMenuBar *mBar = menuBar())
showButtonsInMenuBar(mBar);
else
#endif
if (!controlContainer)
controlContainer = new ControlContainer(q);
}
QWidget *parent = q->parentWidget();
QRect availableRect = parent->contentsRect();
// Adjust geometry if the sub-window is inside a scroll area.
QAbstractScrollArea *scrollArea = qobject_cast<QAbstractScrollArea *>(parent->parentWidget());
if (scrollArea && scrollArea->viewport() == parent) {
QScrollBar *hbar = scrollArea->horizontalScrollBar();
QScrollBar *vbar = scrollArea->verticalScrollBar();
const int xOffset = hbar ? hbar->value() : 0;
const int yOffset = vbar ? vbar->value() : 0;
availableRect.adjust(-xOffset, -yOffset, -xOffset, -yOffset);
oldGeometry.adjust(xOffset, yOffset, xOffset, yOffset);
}
setNewGeometry(&availableRect);
// QWidget::setGeometry will reset Qt::WindowMaximized so we have to update it here.
ensureWindowState(Qt::WindowMaximized);
if (wasVisible)
q->setVisible(true);
resizeEnabled = false;
moveEnabled = false;
#ifndef QT_NO_ACTION
setEnabled(MoveAction, moveEnabled);
setEnabled(MaximizeAction, false);
setEnabled(MinimizeAction, true);
setEnabled(RestoreAction, true);
setEnabled(ResizeAction, resizeEnabled);
#endif // QT_NO_ACTION
Q_ASSERT(q->windowState() & Qt::WindowMaximized);
Q_ASSERT(!(q->windowState() & Qt::WindowMinimized));
restoreFocus();
updateMask();
}
/*!
\internal
*/
void QMdiSubWindowPrivate::setActive(bool activate, bool changeFocus)
{
Q_Q(QMdiSubWindow);
if (!parent || !activationEnabled)
return;
if (activate && !isActive && q->isEnabled()) {
isActive = true;
isExplicitlyDeactivated = false;
Qt::WindowStates oldWindowState = q->windowState();
ensureWindowState(Qt::WindowActive);
emit q->aboutToActivate();
#ifndef QT_NO_MENUBAR
if (QMenuBar *mBar = menuBar())
showButtonsInMenuBar(mBar);
#endif
Q_ASSERT(isActive);
emit q->windowStateChanged(oldWindowState, q->windowState());
} else if (!activate && isActive) {
isActive = false;
Qt::WindowStates oldWindowState = q->windowState();
q->overrideWindowState(q->windowState() & ~Qt::WindowActive);
if (changeFocus) {
QWidget *focusWidget = QApplication::focusWidget();
if (focusWidget && (focusWidget == q || q->isAncestorOf(focusWidget)))
focusWidget->clearFocus();
}
if (baseWidget)
baseWidget->overrideWindowState(baseWidget->windowState() & ~Qt::WindowActive);
Q_ASSERT(!isActive);
emit q->windowStateChanged(oldWindowState, q->windowState());
}
if (activate && isActive && q->isEnabled() && !q->hasFocus()
&& !q->isAncestorOf(QApplication::focusWidget())) {
if (changeFocus)
setFocusWidget();
ensureWindowState(Qt::WindowActive);
}
int frameWidth = q->style()->pixelMetric(QStyle::PM_MdiSubWindowFrameWidth, 0, q);
int titleBarHeight = this->titleBarHeight();
QRegion windowDecoration = QRegion(0, 0, q->width(), q->height());
windowDecoration -= QRegion(frameWidth, titleBarHeight, q->width() - 2 * frameWidth,
q->height() - titleBarHeight - frameWidth);
// Make sure we don't use cached style options if we get
// resize events right before activation/deactivation.
if (resizeTimerId != -1) {
q->killTimer(resizeTimerId);
resizeTimerId = -1;
updateDirtyRegions();
}
q->update(windowDecoration);
}
/*!
\internal
*/
void QMdiSubWindowPrivate::processClickedSubControl()
{
Q_Q(QMdiSubWindow);
switch (activeSubControl) {
case QStyle::SC_TitleBarContextHelpButton:
#ifndef QT_NO_WHATSTHIS
QWhatsThis::enterWhatsThisMode();
#endif
break;
case QStyle::SC_TitleBarShadeButton:
q->showShaded();
hoveredSubControl = QStyle::SC_TitleBarUnshadeButton;
break;
case QStyle::SC_TitleBarUnshadeButton:
if (q->isShaded())
hoveredSubControl = QStyle::SC_TitleBarShadeButton;
q->showNormal();
break;
case QStyle::SC_TitleBarMinButton:
#if defined(Q_WS_MAC) && !defined(QT_NO_STYLE_MAC)
if (qobject_cast<QMacStyle *>(q->style())) {
if (q->isMinimized())
q->showNormal();
else
q->showMinimized();
break;
}
#endif
q->showMinimized();
break;
case QStyle::SC_TitleBarNormalButton:
if (q->isShaded())
hoveredSubControl = QStyle::SC_TitleBarMinButton;
q->showNormal();
break;
case QStyle::SC_TitleBarMaxButton:
#if defined(Q_WS_MAC) && !defined(QT_NO_STYLE_MAC)
if (qobject_cast<QMacStyle *>(q->style())) {
if (q->isMaximized())
q->showNormal();
else
q->showMaximized();
break;
}
#endif
q->showMaximized();
break;
case QStyle::SC_TitleBarCloseButton:
q->close();
break;
default:
break;
}
}
/*!
\internal
*/
QRegion QMdiSubWindowPrivate::getRegion(Operation operation) const
{
Q_Q(const QMdiSubWindow);
int width = q->width();
int height = q->height();
int titleBarHeight = this->titleBarHeight();
int frameWidth = q->style()->pixelMetric(QStyle::PM_MdiSubWindowFrameWidth, 0, q);
int cornerConst = titleBarHeight - frameWidth;
int titleBarConst = 2 * titleBarHeight;
if (operation == Move) {
QStyleOptionTitleBar titleBarOptions = this->titleBarOptions();
QRegion move(frameWidth, frameWidth, width - 2 * frameWidth, cornerConst);
// Depending on which window flags are set, activated sub controllers will
// be subtracted from the 'move' region.
for (int i = 0; i < NumSubControls; ++i) {
if (SubControls[i] == QStyle::SC_TitleBarLabel)
continue;
move -= QRegion(q->style()->subControlRect(QStyle::CC_TitleBar, &titleBarOptions,
SubControls[i]));
}
return move;
}
QRegion region;
#if defined(Q_WS_MAC) && !defined(QT_NO_STYLE_MAC)
if (qobject_cast<QMacStyle *>(q->style()))
return region;
#endif
switch (operation) {
case TopResize:
region = QRegion(titleBarHeight, 0, width - titleBarConst, frameWidth);
break;
case BottomResize:
region = QRegion(titleBarHeight, height - frameWidth, width - titleBarConst, frameWidth);
break;
case LeftResize:
region = QRegion(0, titleBarHeight, frameWidth, height - titleBarConst);
break;
case RightResize:
region = QRegion(width - frameWidth, titleBarHeight, frameWidth, height - titleBarConst);
break;
case TopLeftResize:
region = QRegion(0, 0, titleBarHeight, titleBarHeight)
- QRegion(frameWidth, frameWidth, cornerConst, cornerConst);
break;
case TopRightResize:
region = QRegion(width - titleBarHeight, 0, titleBarHeight, titleBarHeight)
- QRegion(width - titleBarHeight, frameWidth, cornerConst, cornerConst);
break;
case BottomLeftResize:
region = QRegion(0, height - titleBarHeight, titleBarHeight, titleBarHeight)
- QRegion(frameWidth, height - titleBarHeight, cornerConst, cornerConst);
break;
case BottomRightResize:
region = QRegion(width - titleBarHeight, height - titleBarHeight, titleBarHeight, titleBarHeight)
- QRegion(width - titleBarHeight, height - titleBarHeight, cornerConst, cornerConst);
break;
default:
break;
}
return region;
}
/*!
\internal
*/
QMdiSubWindowPrivate::Operation QMdiSubWindowPrivate::getOperation(const QPoint &pos) const
{
OperationInfoMap::const_iterator it;
for (it = operationMap.constBegin(); it != operationMap.constEnd(); ++it)
if (it.value().region.contains(pos))
return it.key();
return None;
}
extern QString qt_setWindowTitle_helperHelper(const QString&, const QWidget*);
/*!
\internal
*/
QStyleOptionTitleBar QMdiSubWindowPrivate::titleBarOptions() const
{
Q_Q(const QMdiSubWindow);
QStyleOptionTitleBar titleBarOptions;
titleBarOptions.initFrom(q);
if (activeSubControl != QStyle::SC_None) {
if (hoveredSubControl == activeSubControl) {
titleBarOptions.state |= QStyle::State_Sunken;
titleBarOptions.activeSubControls = activeSubControl;
}
} else if (autoRaise() && hoveredSubControl != QStyle::SC_None
&& hoveredSubControl != QStyle::SC_TitleBarLabel) {
titleBarOptions.state |= QStyle::State_MouseOver;
titleBarOptions.activeSubControls = hoveredSubControl;
} else {
titleBarOptions.state &= ~QStyle::State_MouseOver;
titleBarOptions.activeSubControls = QStyle::SC_None;
}
titleBarOptions.subControls = QStyle::SC_All;
titleBarOptions.titleBarFlags = q->windowFlags();
titleBarOptions.titleBarState = q->windowState();
titleBarOptions.palette = titleBarPalette;
titleBarOptions.icon = menuIcon;
if (isActive) {
titleBarOptions.state |= QStyle::State_Active;
titleBarOptions.titleBarState |= QStyle::State_Active;
titleBarOptions.palette.setCurrentColorGroup(QPalette::Active);
} else {
titleBarOptions.state &= ~QStyle::State_Active;
titleBarOptions.palette.setCurrentColorGroup(QPalette::Inactive);
}
int border = hasBorder(titleBarOptions) ? 4 : 0;
int paintHeight = titleBarHeight(titleBarOptions);
paintHeight -= q->isMinimized() ? 2 * border : border;
titleBarOptions.rect = QRect(border, border, q->width() - 2 * border, paintHeight);
if (!windowTitle.isEmpty()) {
// Set the text here before asking for the width of the title bar label
// in case people uses the actual text to calculate the width.
titleBarOptions.text = windowTitle;
titleBarOptions.fontMetrics = QFontMetrics(font);
int width = q->style()->subControlRect(QStyle::CC_TitleBar, &titleBarOptions,
QStyle::SC_TitleBarLabel, q).width();
// Set elided text if we don't have enough space for the entire title.
titleBarOptions.text = titleBarOptions.fontMetrics.elidedText(windowTitle, Qt::ElideRight, width);
}
return titleBarOptions;
}
/*!
\internal
*/
void QMdiSubWindowPrivate::ensureWindowState(Qt::WindowState state)
{
Q_Q(QMdiSubWindow);
Qt::WindowStates windowStates = q->windowState() | state;
switch (state) {
case Qt::WindowMinimized:
windowStates &= ~Qt::WindowMaximized;
windowStates &= ~Qt::WindowNoState;
break;
case Qt::WindowMaximized:
windowStates &= ~Qt::WindowMinimized;
windowStates &= ~Qt::WindowNoState;
break;
case Qt::WindowNoState:
windowStates &= ~Qt::WindowMinimized;
windowStates &= ~Qt::WindowMaximized;
break;
default:
break;
}
if (baseWidget) {
if (!(baseWidget->windowState() & Qt::WindowActive) && windowStates & Qt::WindowActive)
baseWidget->overrideWindowState(windowStates & ~Qt::WindowActive);
else
baseWidget->overrideWindowState(windowStates);
}
q->overrideWindowState(windowStates);
}
/*!
\internal
*/
int QMdiSubWindowPrivate::titleBarHeight(const QStyleOptionTitleBar &options) const
{
Q_Q(const QMdiSubWindow);
if (!parent || q->windowFlags() & Qt::FramelessWindowHint
|| (q->isMaximized() && !drawTitleBarWhenMaximized())) {
return 0;
}
int height = q->style()->pixelMetric(QStyle::PM_TitleBarHeight, &options, q);
#if defined(Q_WS_MAC) && !defined(QT_NO_STYLE_MAC)
// ### Fix mac style, the +4 pixels hack is not necessary anymore
if (qobject_cast<QMacStyle *>(q->style()))
height -= 4;
#endif
if (hasBorder(options))
height += q->isMinimized() ? 8 : 4;
return height;
}
/*!
\internal
*/
void QMdiSubWindowPrivate::sizeParameters(int *margin, int *minWidth) const
{
Q_Q(const QMdiSubWindow);
Qt::WindowFlags flags = q->windowFlags();
if (!parent || flags & Qt::FramelessWindowHint) {
*margin = 0;
*minWidth = 0;
return;
}
if (q->isMaximized() && !drawTitleBarWhenMaximized())
*margin = 0;
else
*margin = q->style()->pixelMetric(QStyle::PM_MdiSubWindowFrameWidth, 0, q);
QStyleOptionTitleBar opt = this->titleBarOptions();
int tempWidth = 0;
for (int i = 0; i < NumSubControls; ++i) {
if (SubControls[i] == QStyle::SC_TitleBarLabel) {
tempWidth += 30;
continue;
}
QRect rect = q->style()->subControlRect(QStyle::CC_TitleBar, &opt, SubControls[i], q);
if (!rect.isValid())
continue;
tempWidth += rect.width();
}
*minWidth = tempWidth;
}
/*!
\internal
*/
bool QMdiSubWindowPrivate::drawTitleBarWhenMaximized() const
{
Q_Q(const QMdiSubWindow);
if (q->window()->testAttribute(Qt::WA_CanHostQMdiSubWindowTitleBar))
return false;
if (isChildOfTabbedQMdiArea(q))
return false;
#if defined(Q_WS_MAC) && !defined(QT_NO_STYLE_MAC) || defined(Q_WS_WINCE_WM)
return true;
#else
if (q->style()->styleHint(QStyle::SH_Workspace_FillSpaceOnMaximize, 0, q))
return true;
#if defined(QT_NO_MENUBAR) || defined(QT_NO_MAINWINDOW)
return true;
#else
QMainWindow *mainWindow = qobject_cast<QMainWindow *>(q->window());
if (!mainWindow || !qobject_cast<QMenuBar *>(mainWindow->menuWidget())
|| mainWindow->menuWidget()->isHidden())
return true;
return isChildOfQMdiSubWindow(q);
#endif
#endif
}
#ifndef QT_NO_MENUBAR
/*!
\internal
*/
void QMdiSubWindowPrivate::showButtonsInMenuBar(QMenuBar *menuBar)
{
Q_Q(QMdiSubWindow);
Q_ASSERT(q->isMaximized() && !drawTitleBarWhenMaximized());
if (isChildOfTabbedQMdiArea(q))
return;
removeButtonsFromMenuBar();
if (!controlContainer)
controlContainer = new ControlContainer(q);
ignoreWindowTitleChange = true;
controlContainer->showButtonsInMenuBar(menuBar);
ignoreWindowTitleChange = false;
QWidget *topLevelWindow = q->window();
topLevelWindow->setWindowModified(q->isWindowModified());
topLevelWindow->installEventFilter(q);
int buttonHeight = 0;
if (controlContainer->controllerWidget())
buttonHeight = controlContainer->controllerWidget()->height();
else if (controlContainer->systemMenuLabel())
buttonHeight = controlContainer->systemMenuLabel()->height();
// This will rarely happen.
if (menuBar && menuBar->height() < buttonHeight
&& topLevelWindow->layout()) {
// Make sure topLevelWindow->contentsRect returns correct geometry.
// topLevelWidget->updateGeoemtry will not do the trick here since it will post the event.
QEvent event(QEvent::LayoutRequest);
QApplication::sendEvent(topLevelWindow, &event);
}
}
/*!
\internal
*/
void QMdiSubWindowPrivate::removeButtonsFromMenuBar()
{
Q_Q(QMdiSubWindow);
if (!controlContainer || isChildOfTabbedQMdiArea(q))
return;
QMenuBar *currentMenuBar = 0;
#ifndef QT_NO_MAINWINDOW
if (QMainWindow *mainWindow = qobject_cast<QMainWindow *>(q->window())) {
// NB! We can't use menuBar() here because that one will actually create
// a menubar for us if not set. That's not what we want :-)
currentMenuBar = qobject_cast<QMenuBar *>(mainWindow->menuWidget());
}
#endif
ignoreWindowTitleChange = true;
controlContainer->removeButtonsFromMenuBar(currentMenuBar);
ignoreWindowTitleChange = false;
QWidget *topLevelWindow = q->window();
topLevelWindow->removeEventFilter(q);
if (baseWidget && !drawTitleBarWhenMaximized())
topLevelWindow->setWindowModified(false);
originalTitle = QString::null;
}
#endif // QT_NO_MENUBAR
void QMdiSubWindowPrivate::updateWindowTitle(bool isRequestFromChild)
{
Q_Q(QMdiSubWindow);
if (isRequestFromChild && !q->windowTitle().isEmpty() && !lastChildWindowTitle.isEmpty()
&& lastChildWindowTitle != q->windowTitle()) {
return;
}
QWidget *titleWidget = 0;
if (isRequestFromChild)
titleWidget = baseWidget;
else
titleWidget = q;
if (!titleWidget || titleWidget->windowTitle().isEmpty())
return;
ignoreWindowTitleChange = true;
q->setWindowTitle(titleWidget->windowTitle());
if (q->maximizedButtonsWidget())
setNewWindowTitle();
ignoreWindowTitleChange = false;
}
#ifndef QT_NO_RUBBERBAND
void QMdiSubWindowPrivate::enterRubberBandMode()
{
Q_Q(QMdiSubWindow);
if (q->isMaximized())
return;
Q_ASSERT(oldGeometry.isValid());
Q_ASSERT(parent);
if (!rubberBand) {
rubberBand = new QRubberBand(QRubberBand::Rectangle, q->parentWidget());
// For accessibility to identify this special widget.
rubberBand->setObjectName(QLatin1String("qt_rubberband"));
}
QPoint rubberBandPos = q->mapToParent(QPoint(0, 0));
rubberBand->setGeometry(rubberBandPos.x(), rubberBandPos.y(),
oldGeometry.width(), oldGeometry.height());
rubberBand->show();
isInRubberBandMode = true;
q->grabMouse();
}
void QMdiSubWindowPrivate::leaveRubberBandMode()
{
Q_Q(QMdiSubWindow);
Q_ASSERT(rubberBand);
Q_ASSERT(isInRubberBandMode);
q->releaseMouse();
isInRubberBandMode = false;
q->setGeometry(rubberBand->geometry());
rubberBand->hide();
currentOperation = None;
}
#endif // QT_NO_RUBBERBAND
// Taken from the old QWorkspace (::readColors())
QPalette QMdiSubWindowPrivate::desktopPalette() const
{
Q_Q(const QMdiSubWindow);
QPalette newPalette = q->palette();
bool colorsInitialized = false;
#ifdef Q_WS_WIN // ask system properties on windows
#ifndef SPI_GETGRADIENTCAPTIONS
#define SPI_GETGRADIENTCAPTIONS 0x1008
#endif
#ifndef COLOR_GRADIENTACTIVECAPTION
#define COLOR_GRADIENTACTIVECAPTION 27
#endif
#ifndef COLOR_GRADIENTINACTIVECAPTION
#define COLOR_GRADIENTINACTIVECAPTION 28
#endif
if (QApplication::desktopSettingsAware()) {
newPalette.setColor(QPalette::Active, QPalette::Highlight,
colorref2qrgb(GetSysColor(COLOR_ACTIVECAPTION)));
newPalette.setColor(QPalette::Inactive, QPalette::Highlight,
colorref2qrgb(GetSysColor(COLOR_INACTIVECAPTION)));
newPalette.setColor(QPalette::Active, QPalette::HighlightedText,
colorref2qrgb(GetSysColor(COLOR_CAPTIONTEXT)));
newPalette.setColor(QPalette::Inactive, QPalette::HighlightedText,
colorref2qrgb(GetSysColor(COLOR_INACTIVECAPTIONTEXT)));
colorsInitialized = true;
BOOL hasGradient = false;
SystemParametersInfo(SPI_GETGRADIENTCAPTIONS, 0, &hasGradient, 0);
if (hasGradient) {
newPalette.setColor(QPalette::Active, QPalette::Base,
colorref2qrgb(GetSysColor(COLOR_GRADIENTACTIVECAPTION)));
newPalette.setColor(QPalette::Inactive, QPalette::Base,
colorref2qrgb(GetSysColor(COLOR_GRADIENTINACTIVECAPTION)));
} else {
newPalette.setColor(QPalette::Active, QPalette::Base,
newPalette.color(QPalette::Active, QPalette::Highlight));
newPalette.setColor(QPalette::Inactive, QPalette::Base,
newPalette.color(QPalette::Inactive, QPalette::Highlight));
}
}
#endif // Q_WS_WIN
if (!colorsInitialized) {
newPalette.setColor(QPalette::Active, QPalette::Highlight,
newPalette.color(QPalette::Active, QPalette::Highlight));
newPalette.setColor(QPalette::Active, QPalette::Base,
newPalette.color(QPalette::Active, QPalette::Highlight));
newPalette.setColor(QPalette::Inactive, QPalette::Highlight,
newPalette.color(QPalette::Inactive, QPalette::Dark));
newPalette.setColor(QPalette::Inactive, QPalette::Base,
newPalette.color(QPalette::Inactive, QPalette::Dark));
newPalette.setColor(QPalette::Inactive, QPalette::HighlightedText,
newPalette.color(QPalette::Inactive, QPalette::Window));
}
return newPalette;
}
void QMdiSubWindowPrivate::updateActions()
{
Qt::WindowFlags windowFlags = q_func()->windowFlags();
// Hide all
for (int i = 0; i < NumWindowStateActions; ++i)
setVisible(WindowStateAction(i), false);
if (windowFlags & Qt::FramelessWindowHint)
return;
setVisible(StayOnTopAction, true);
setVisible(MoveAction, moveEnabled);
setVisible(ResizeAction, resizeEnabled);
// CloseAction
if (windowFlags & Qt::WindowSystemMenuHint)
setVisible(CloseAction, true);
// RestoreAction
if (windowFlags & (Qt::WindowMinimizeButtonHint | Qt::WindowMaximizeButtonHint))
setVisible(RestoreAction, true);
// MinimizeAction
if (windowFlags & Qt::WindowMinimizeButtonHint)
setVisible(MinimizeAction, true);
// MaximizeAction
if (windowFlags & Qt::WindowMaximizeButtonHint)
setVisible(MaximizeAction, true);
}
void QMdiSubWindowPrivate::setFocusWidget()
{
Q_Q(QMdiSubWindow);
if (!baseWidget) {
q->setFocus();
return;
}
// This will give focus to the next child if possible, otherwise
// do nothing, hence it's not possible to tab between windows with
// just hitting tab (unless Qt::TabFocus is removed from the focus policy).
if (focusInReason == Qt::TabFocusReason) {
q->focusNextChild();
return;
}
// Same as above, but gives focus to the previous child.
if (focusInReason == Qt::BacktabFocusReason) {
q->focusPreviousChild();
return;
}
if (QWidget *focusWidget = baseWidget->focusWidget()) {
if (!focusWidget->hasFocus() && q->isAncestorOf(focusWidget)
&& focusWidget->isVisible() && !q->isMinimized()
&& focusWidget->focusPolicy() != Qt::NoFocus) {
focusWidget->setFocus();
} else {
q->setFocus();
}
return;
}
QWidget *focusWidget = q->nextInFocusChain();
while (focusWidget && focusWidget != q && focusWidget->focusPolicy() == Qt::NoFocus)
focusWidget = focusWidget->nextInFocusChain();
if (focusWidget && q->isAncestorOf(focusWidget))
focusWidget->setFocus();
else if (baseWidget->focusPolicy() != Qt::NoFocus)
baseWidget->setFocus();
else if (!q->hasFocus())
q->setFocus();
}
void QMdiSubWindowPrivate::restoreFocus()
{
if (!restoreFocusWidget)
return;
if (!restoreFocusWidget->hasFocus() && q_func()->isAncestorOf(restoreFocusWidget)
&& restoreFocusWidget->isVisible()
&& restoreFocusWidget->focusPolicy() != Qt::NoFocus) {
restoreFocusWidget->setFocus();
}
restoreFocusWidget = 0;
}
/*!
\internal
### Please add QEvent::WindowFlagsChange event
*/
void QMdiSubWindowPrivate::setWindowFlags(Qt::WindowFlags windowFlags)
{
Q_Q(QMdiSubWindow);
if (!parent) {
q->setWindowFlags(windowFlags);
return;
}
Qt::WindowFlags windowType = windowFlags & Qt::WindowType_Mask;
if (windowType == Qt::Dialog || windowFlags & Qt::MSWindowsFixedSizeDialogHint)
windowFlags |= Qt::WindowTitleHint | Qt::WindowSystemMenuHint;
// Set standard flags if none of the customize flags are set
if (!(windowFlags & CustomizeWindowFlags))
windowFlags |= Qt::WindowTitleHint | Qt::WindowSystemMenuHint | Qt::WindowMinMaxButtonsHint | Qt::WindowCloseButtonHint;
else if (windowFlags & Qt::FramelessWindowHint && windowFlags & Qt::WindowStaysOnTopHint)
windowFlags = Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint;
else if (windowFlags & Qt::FramelessWindowHint)
windowFlags = Qt::FramelessWindowHint;
windowFlags &= ~windowType;
windowFlags |= Qt::SubWindow;
#ifndef QT_NO_ACTION
if (QAction *stayOnTopAction = actions[QMdiSubWindowPrivate::StayOnTopAction]) {
if (windowFlags & Qt::WindowStaysOnTopHint)
stayOnTopAction->setChecked(true);
else
stayOnTopAction->setChecked(false);
}
#endif
#ifndef QT_NO_SIZEGRIP
if ((windowFlags & Qt::FramelessWindowHint) && sizeGrip)
delete sizeGrip;
#endif
q->setWindowFlags(windowFlags);
updateGeometryConstraints();
updateActions();
QSize currentSize = q->size();
if (q->isVisible() && (currentSize.width() < internalMinimumSize.width()
|| currentSize.height() < internalMinimumSize.height())) {
q->resize(currentSize.expandedTo(internalMinimumSize));
}
}
void QMdiSubWindowPrivate::setVisible(WindowStateAction action, bool visible)
{
#ifndef QT_NO_ACTION
if (actions[action])
actions[action]->setVisible(visible);
#endif
Q_Q(QMdiSubWindow);
if (!controlContainer)
controlContainer = new ControlContainer(q);
if (ControllerWidget *ctrlWidget = qobject_cast<ControllerWidget *>
(controlContainer->controllerWidget())) {
ctrlWidget->setControlVisible(action, visible);
}
}
#ifndef QT_NO_ACTION
void QMdiSubWindowPrivate::setEnabled(WindowStateAction action, bool enable)
{
if (actions[action])
actions[action]->setEnabled(enable);
}
#ifndef QT_NO_MENU
void QMdiSubWindowPrivate::addToSystemMenu(WindowStateAction action, const QString &text,
const char *slot)
{
if (!systemMenu)
return;
actions[action] = systemMenu->addAction(text, q_func(), slot);
}
#endif
#endif // QT_NO_ACTION
/*!
\internal
*/
QSize QMdiSubWindowPrivate::iconSize() const
{
Q_Q(const QMdiSubWindow);
if (!parent || q->windowFlags() & Qt::FramelessWindowHint)
return QSize(-1, -1);
return QSize(q->style()->pixelMetric(QStyle::PM_MdiSubWindowMinimizedWidth, 0, q), titleBarHeight());
}
#ifndef QT_NO_SIZEGRIP
/*!
\internal
*/
void QMdiSubWindowPrivate::setSizeGrip(QSizeGrip *newSizeGrip)
{
Q_Q(QMdiSubWindow);
if (!newSizeGrip || sizeGrip || q->windowFlags() & Qt::FramelessWindowHint)
return;
if (layout && layout->indexOf(newSizeGrip) != -1)
return;
newSizeGrip->setFixedSize(newSizeGrip->sizeHint());
bool putSizeGripInLayout = layout ? true : false;
#if defined(Q_WS_MAC) && !defined(QT_NO_STYLE_MAC)
if (qobject_cast<QMacStyle *>(q->style()))
putSizeGripInLayout = false;
#endif
if (putSizeGripInLayout) {
layout->addWidget(newSizeGrip);
layout->setAlignment(newSizeGrip, Qt::AlignBottom | Qt::AlignRight);
} else {
newSizeGrip->setParent(q);
newSizeGrip->move(q->isLeftToRight() ? q->width() - newSizeGrip->width() : 0,
q->height() - newSizeGrip->height());
sizeGrip = newSizeGrip;
}
newSizeGrip->raise();
updateGeometryConstraints();
newSizeGrip->installEventFilter(q);
}
/*!
\internal
*/
void QMdiSubWindowPrivate::setSizeGripVisible(bool visible) const
{
// See if we can find any size grips
QList<QSizeGrip *> sizeGrips = qFindChildren<QSizeGrip *>(q_func());
foreach (QSizeGrip *grip, sizeGrips)
grip->setVisible(visible);
}
#endif // QT_NO_SIZEGRIP
/*!
\internal
*/
void QMdiSubWindowPrivate::updateInternalWindowTitle()
{
Q_Q(QMdiSubWindow);
if (q->isWindowModified()) {
windowTitle = q->windowTitle();
windowTitle.replace(QLatin1String("[*]"), QLatin1String("*"));
} else {
windowTitle = qt_setWindowTitle_helperHelper(q->windowTitle(), q);
}
q->update(0, 0, q->width(), titleBarHeight());
}
/*!
Constructs a new QMdiSubWindow widget. The \a parent and \a
flags arguments are passed to QWidget's constructor.
Instead of using addSubWindow(), it is also simply possible to
use setParent() when you add the subwindow to a QMdiArea.
Note that only \l{QMdiSubWindow}s can be set as children of
QMdiArea; you cannot, for instance, write:
\badcode
QMdiArea mdiArea;
QTextEdit editor(&mdiArea); // invalid child widget
\endcode
\sa QMdiArea::addSubWindow()
*/
QMdiSubWindow::QMdiSubWindow(QWidget *parent, Qt::WindowFlags flags)
: QWidget(*new QMdiSubWindowPrivate, parent, 0)
{
Q_D(QMdiSubWindow);
#ifndef QT_NO_MENU
d->createSystemMenu();
addActions(d->systemMenu->actions());
#endif
d->setWindowFlags(flags);
setBackgroundRole(QPalette::Window);
setAutoFillBackground(true);
setMouseTracking(true);
setLayout(new QVBoxLayout);
setFocusPolicy(Qt::StrongFocus);
layout()->setMargin(0);
d->updateGeometryConstraints();
setAttribute(Qt::WA_Resized, false);
d->titleBarPalette = d->desktopPalette();
d->font = QApplication::font("QWorkspaceTitleBar");
// We don't want the menu icon by default on mac.
#ifndef Q_WS_MAC
if (windowIcon().isNull())
d->menuIcon = style()->standardIcon(QStyle::SP_TitleBarMenuButton, 0, this);
else
d->menuIcon = windowIcon();
#endif
connect(qApp, SIGNAL(focusChanged(QWidget*,QWidget*)),
this, SLOT(_q_processFocusChanged(QWidget*,QWidget*)));
}
/*!
Destroys the subwindow.
\sa QMdiArea::removeSubWindow()
*/
QMdiSubWindow::~QMdiSubWindow()
{
Q_D(QMdiSubWindow);
#ifndef QT_NO_MENUBAR
d->removeButtonsFromMenuBar();
#endif
d->setActive(false);
}
/*!
Sets \a widget as the internal widget of this subwindow. The
internal widget is displayed in the center of the subwindow
beneath the title bar.
QMdiSubWindow takes temporary ownership of \a widget; you do
not have to delete it. Any existing internal widget will be
removed and reparented to the root window.
\sa widget()
*/
void QMdiSubWindow::setWidget(QWidget *widget)
{
Q_D(QMdiSubWindow);
if (!widget) {
d->removeBaseWidget();
return;
}
if (widget == d->baseWidget) {
qWarning("QMdiSubWindow::setWidget: widget is already set");
return;
}
bool wasResized = testAttribute(Qt::WA_Resized);
d->removeBaseWidget();
if (QLayout *layout = this->layout())
layout->addWidget(widget);
else
widget->setParent(this);
#ifndef QT_NO_SIZEGRIP
QSizeGrip *sizeGrip = qFindChild<QSizeGrip *>(widget);
if (sizeGrip)
sizeGrip->installEventFilter(this);
if (d->sizeGrip)
d->sizeGrip->raise();
#endif
d->baseWidget = widget;
d->baseWidget->installEventFilter(this);
d->ignoreWindowTitleChange = true;
bool isWindowModified = this->isWindowModified();
if (windowTitle().isEmpty()) {
d->updateWindowTitle(true);
isWindowModified = d->baseWidget->isWindowModified();
}
if (!this->isWindowModified() && isWindowModified
&& windowTitle().contains(QLatin1String("[*]"))) {
setWindowModified(isWindowModified);
}
d->lastChildWindowTitle = d->baseWidget->windowTitle();
d->ignoreWindowTitleChange = false;
if (windowIcon().isNull() && !d->baseWidget->windowIcon().isNull())
setWindowIcon(d->baseWidget->windowIcon());
d->updateGeometryConstraints();
if (!wasResized && testAttribute(Qt::WA_Resized))
setAttribute(Qt::WA_Resized, false);
}
/*!
Returns the current internal widget.
\sa setWidget()
*/
QWidget *QMdiSubWindow::widget() const
{
return d_func()->baseWidget;
}
/*!
\internal
*/
QWidget *QMdiSubWindow::maximizedButtonsWidget() const
{
Q_D(const QMdiSubWindow);
if (isVisible() && d->controlContainer && isMaximized() && !d->drawTitleBarWhenMaximized()
&& !isChildOfTabbedQMdiArea(this)) {
return d->controlContainer->controllerWidget();
}
return 0;
}
/*!
\internal
*/
QWidget *QMdiSubWindow::maximizedSystemMenuIconWidget() const
{
Q_D(const QMdiSubWindow);
if (isVisible() && d->controlContainer && isMaximized() && !d->drawTitleBarWhenMaximized()
&& !isChildOfTabbedQMdiArea(this)) {
return d->controlContainer->systemMenuLabel();
}
return 0;
}
/*!
Returns true if this window is shaded; otherwise returns false.
A window is shaded if it is collapsed so that only the title bar is
visible.
*/
bool QMdiSubWindow::isShaded() const
{
return d_func()->isShadeMode;
}
/*!
If \a on is true, \a option is enabled on the subwindow; otherwise it is
disabled. See SubWindowOption for the effect of each option.
\sa SubWindowOption, testOption()
*/
void QMdiSubWindow::setOption(SubWindowOption option, bool on)
{
Q_D(QMdiSubWindow);
if (on && !(d->options & option))
d->options |= option;
else if (!on && (d->options & option))
d->options &= ~option;
#ifndef QT_NO_RUBBERBAND
if ((option & (RubberBandResize | RubberBandMove)) && !on && d->isInRubberBandMode)
d->leaveRubberBandMode();
#endif
}
/*!
Returns true if \a option is enabled; otherwise returns false.
\sa SubWindowOption, setOption()
*/
bool QMdiSubWindow::testOption(SubWindowOption option) const
{
return d_func()->options & option;
}
/*!
\property QMdiSubWindow::keyboardSingleStep
\brief sets how far a widget should move or resize when using the
keyboard arrow keys.
When in keyboard-interactive mode, you can use the arrow and page keys to
either move or resize the window. This property controls the arrow keys.
The common way to enter keyboard interactive mode is to enter the
subwindow menu, and select either "resize" or "move".
The default keyboard single step value is 5 pixels.
\sa keyboardPageStep
*/
int QMdiSubWindow::keyboardSingleStep() const
{
return d_func()->keyboardSingleStep;
}
void QMdiSubWindow::setKeyboardSingleStep(int step)
{
// Haven't done any boundary check here since negative step only
// means inverted behavior, which is OK if the user want it.
// A step equal to zero means "do nothing".
d_func()->keyboardSingleStep = step;
}
/*!
\property QMdiSubWindow::keyboardPageStep
\brief sets how far a widget should move or resize when using the
keyboard page keys.
When in keyboard-interactive mode, you can use the arrow and page keys to
either move or resize the window. This property controls the page
keys. The common way to enter keyboard interactive mode is to enter the
subwindow menu, and select either "resize" or "move".
The default keyboard page step value is 20 pixels.
\sa keyboardSingleStep
*/
int QMdiSubWindow::keyboardPageStep() const
{
return d_func()->keyboardPageStep;
}
void QMdiSubWindow::setKeyboardPageStep(int step)
{
// Haven't done any boundary check here since negative step only
// means inverted behavior, which is OK if the user want it.
// A step equal to zero means "do nothing".
d_func()->keyboardPageStep = step;
}
#ifndef QT_NO_MENU
/*!
Sets \a systemMenu as the current system menu for this subwindow.
By default, each QMdiSubWindow has a standard system menu.
QActions for the system menu created by QMdiSubWindow will
automatically be updated depending on the current window state;
e.g., the minimize action will be disabled after the window is
minimized.
QActions added by the user are not updated by QMdiSubWindow.
QMdiSubWindow takes ownership of \a systemMenu; you do not have to
delete it. Any existing menus will be deleted.
\sa systemMenu(), showSystemMenu()
*/
void QMdiSubWindow::setSystemMenu(QMenu *systemMenu)
{
Q_D(QMdiSubWindow);
if (systemMenu && systemMenu == d->systemMenu) {
qWarning("QMdiSubWindow::setSystemMenu: system menu is already set");
return;
}
if (d->systemMenu) {
delete d->systemMenu;
d->systemMenu = 0;
}
if (!systemMenu)
return;
if (systemMenu->parent() != this)
systemMenu->setParent(this);
d->systemMenu = systemMenu;
}
/*!
Returns a pointer to the current system menu, or zero if no system
menu is set. QMdiSubWindow provides a default system menu, but you can
also set the menu with setSystemMenu().
\sa setSystemMenu(), showSystemMenu()
*/
QMenu *QMdiSubWindow::systemMenu() const
{
return d_func()->systemMenu;
}
/*!
Shows the system menu below the system menu icon in the title bar.
\sa setSystemMenu(), systemMenu()
*/
void QMdiSubWindow::showSystemMenu()
{
Q_D(QMdiSubWindow);
if (!d->systemMenu)
return;
QPoint globalPopupPos;
if (QWidget *icon = maximizedSystemMenuIconWidget()) {
if (isLeftToRight())
globalPopupPos = icon->mapToGlobal(QPoint(0, icon->y() + icon->height()));
else
globalPopupPos = icon->mapToGlobal(QPoint(icon->width(), icon->y() + icon->height()));
} else {
if (isLeftToRight())
globalPopupPos = mapToGlobal(contentsRect().topLeft());
else // + QPoint(1, 0) because topRight() == QPoint(left() + width() -1, top())
globalPopupPos = mapToGlobal(contentsRect().topRight()) + QPoint(1, 0);
}
// Adjust x() with -menuwidth in reverse mode.
if (isRightToLeft())
globalPopupPos -= QPoint(d->systemMenu->sizeHint().width(), 0);
d->systemMenu->installEventFilter(this);
d->systemMenu->popup(globalPopupPos);
}
#endif // QT_NO_MENU
/*!
\since 4.4
Returns the area containing this sub-window, or 0 if there is none.
\sa QMdiArea::addSubWindow()
*/
QMdiArea *QMdiSubWindow::mdiArea() const
{
QWidget *parent = parentWidget();
while (parent) {
if (QMdiArea *area = qobject_cast<QMdiArea *>(parent)) {
if (area->viewport() == parentWidget())
return area;
}
parent = parent->parentWidget();
}
return 0;
}
/*!
Calling this function makes the subwindow enter the shaded mode.
When the subwindow is shaded, only the title bar is visible.
Although shading is not supported by all styles, this function will
still show the subwindow as shaded, regardless of whether support
for shading is available. However, when used with styles without
shading support, the user will be unable to return from shaded mode
through the user interface (e.g., through a shade button in the title
bar).
\sa isShaded()
*/
void QMdiSubWindow::showShaded()
{
if (!parent())
return;
Q_D(QMdiSubWindow);
// setMinimizeMode uses this function.
if (!d->isShadeRequestFromMinimizeMode && isShaded())
return;
d->isMaximizeMode = false;
QWidget *currentFocusWidget = QApplication::focusWidget();
if (!d->restoreFocusWidget && isAncestorOf(currentFocusWidget))
d->restoreFocusWidget = currentFocusWidget;
if (!d->isShadeRequestFromMinimizeMode) {
d->isShadeMode = true;
d->ensureWindowState(Qt::WindowMinimized);
}
#ifndef QT_NO_MENUBAR
d->removeButtonsFromMenuBar();
#endif
// showMinimized() will reset Qt::WindowActive, which makes sense
// for top level widgets, but in MDI it makes sense to have an
// active window which is minimized.
if (hasFocus() || isAncestorOf(currentFocusWidget))
d->ensureWindowState(Qt::WindowActive);
#ifndef QT_NO_SIZEGRIP
d->setSizeGripVisible(false);
#endif
if (!d->restoreSize.isValid() || d->isShadeMode) {
d->oldGeometry = geometry();
d->restoreSize.setWidth(d->oldGeometry.width());
d->restoreSize.setHeight(d->oldGeometry.height());
}
// Hide the window before we change the geometry to avoid multiple resize
// events and wrong window state.
const bool wasVisible = isVisible();
if (wasVisible)
setVisible(false);
d->updateGeometryConstraints();
// Update minimum size to internalMinimumSize if set by user.
if (!minimumSize().isNull()) {
d->userMinimumSize = minimumSize();
setMinimumSize(d->internalMinimumSize);
}
resize(d->internalMinimumSize);
// Hide the internal widget if not already hidden by the user.
if (d->baseWidget && !d->baseWidget->isHidden()) {
d->baseWidget->hide();
d->isWidgetHiddenByUs = true;
}
if (wasVisible)
setVisible(true);
d->setFocusWidget();
d->resizeEnabled = false;
d->moveEnabled = true;
d->updateDirtyRegions();
d->updateMask();
#ifndef QT_NO_ACTION
d->setEnabled(QMdiSubWindowPrivate::MinimizeAction, false);
d->setEnabled(QMdiSubWindowPrivate::ResizeAction, d->resizeEnabled);
d->setEnabled(QMdiSubWindowPrivate::MaximizeAction, true);
d->setEnabled(QMdiSubWindowPrivate::RestoreAction, true);
d->setEnabled(QMdiSubWindowPrivate::MoveAction, d->moveEnabled);
#endif
}
/*!
\reimp
*/
bool QMdiSubWindow::eventFilter(QObject *object, QEvent *event)
{
Q_D(QMdiSubWindow);
if (!object)
return QWidget::eventFilter(object, event);
#ifndef QT_NO_MENU
// System menu events.
if (d->systemMenu && d->systemMenu == object) {
if (event->type() == QEvent::MouseButtonDblClick) {
close();
} else if (event->type() == QEvent::MouseMove) {
QMouseEvent *mouseEvent = static_cast<QMouseEvent *>(event);
d->hoveredSubControl = d->getSubControl(mapFromGlobal(mouseEvent->globalPos()));
} else if (event->type() == QEvent::Hide) {
d->systemMenu->removeEventFilter(this);
d->activeSubControl = QStyle::SC_None;
update(QRegion(0, 0, width(), d->titleBarHeight()));
}
return QWidget::eventFilter(object, event);
}
#endif
#ifndef QT_NO_SIZEGRIP
if (object != d->baseWidget && parent() && qobject_cast<QSizeGrip *>(object)) {
if (event->type() != QEvent::MouseButtonPress || !testOption(QMdiSubWindow::RubberBandResize))
return QWidget::eventFilter(object, event);
const QMouseEvent *mouseEvent = static_cast<QMouseEvent *>(event);
d->mousePressPosition = parentWidget()->mapFromGlobal(mouseEvent->globalPos());
d->oldGeometry = geometry();
d->currentOperation = isLeftToRight() ? QMdiSubWindowPrivate::BottomRightResize
: QMdiSubWindowPrivate::BottomLeftResize;
#ifndef QT_NO_RUBBERBAND
d->enterRubberBandMode();
#endif
return true;
}
#endif
if (object != d->baseWidget && event->type() != QEvent::WindowTitleChange)
return QWidget::eventFilter(object, event);
switch (event->type()) {
case QEvent::Show:
d->setActive(true);
break;
case QEvent::ShowToParent:
if (!d->isWidgetHiddenByUs)
show();
break;
case QEvent::WindowStateChange: {
QWindowStateChangeEvent *changeEvent = static_cast<QWindowStateChangeEvent*>(event);
if (changeEvent->isOverride())
break;
Qt::WindowStates oldState = changeEvent->oldState();
Qt::WindowStates newState = d->baseWidget->windowState();
if (!(oldState & Qt::WindowMinimized) && (newState & Qt::WindowMinimized))
showMinimized();
else if (!(oldState & Qt::WindowMaximized) && (newState & Qt::WindowMaximized))
showMaximized();
else if (!(newState & (Qt::WindowMaximized | Qt::WindowMinimized)))
showNormal();
break;
}
case QEvent::Enter:
d->currentOperation = QMdiSubWindowPrivate::None;
d->updateCursor();
break;
case QEvent::LayoutRequest:
d->updateGeometryConstraints();
break;
case QEvent::WindowTitleChange:
if (d->ignoreWindowTitleChange)
break;
if (object == d->baseWidget) {
d->updateWindowTitle(true);
d->lastChildWindowTitle = d->baseWidget->windowTitle();
#ifndef QT_NO_MENUBAR
} else if (maximizedButtonsWidget() && d->controlContainer->menuBar() && d->controlContainer->menuBar()
->cornerWidget(Qt::TopRightCorner) == maximizedButtonsWidget()) {
d->originalTitle = QString::null;
if (d->baseWidget && d->baseWidget->windowTitle() == windowTitle())
d->updateWindowTitle(true);
else
d->updateWindowTitle(false);
#endif
}
break;
case QEvent::ModifiedChange: {
if (object != d->baseWidget)
break;
bool windowModified = d->baseWidget->isWindowModified();
if (!windowModified && d->baseWidget->windowTitle() != windowTitle())
break;
if (windowTitle().contains(QLatin1String("[*]")))
setWindowModified(windowModified);
break;
}
default:
break;
}
return QWidget::eventFilter(object, event);
}
/*!
\reimp
*/
bool QMdiSubWindow::event(QEvent *event)
{
Q_D(QMdiSubWindow);
switch (event->type()) {
case QEvent::StyleChange: {
bool wasShaded = isShaded();
bool wasMinimized = isMinimized();
bool wasMaximized = isMaximized();
ensurePolished();
setContentsMargins(0, 0, 0, 0);
if (wasMinimized || wasMaximized || wasShaded)
showNormal();
d->updateGeometryConstraints();
resize(d->internalMinimumSize.expandedTo(size()));
d->updateMask();
d->updateDirtyRegions();
if (wasShaded)
showShaded();
else if (wasMinimized)
showMinimized();
else if (wasMaximized)
showMaximized();
break;
}
case QEvent::ParentAboutToChange:
d->setActive(false);
break;
case QEvent::ParentChange: {
bool wasResized = testAttribute(Qt::WA_Resized);
#ifndef QT_NO_MENUBAR
d->removeButtonsFromMenuBar();
#endif
d->currentOperation = QMdiSubWindowPrivate::None;
d->activeSubControl = QStyle::SC_None;
d->hoveredSubControl = QStyle::SC_None;
#ifndef QT_NO_RUBBERBAND
if (d->isInRubberBandMode)
d->leaveRubberBandMode();
#endif
d->isShadeMode = false;
d->isMaximizeMode = false;
d->isWidgetHiddenByUs = false;
if (!parent()) {
#if !defined(QT_NO_SIZEGRIP) && defined(Q_WS_MAC) && !defined(QT_NO_STYLE_MAC)
if (qobject_cast<QMacStyle *>(style()))
delete d->sizeGrip;
#endif
setOption(RubberBandResize, false);
setOption(RubberBandMove, false);
} else {
d->setWindowFlags(windowFlags());
}
setContentsMargins(0, 0, 0, 0);
d->updateGeometryConstraints();
d->updateCursor();
d->updateMask();
d->updateDirtyRegions();
d->updateActions();
if (!wasResized && testAttribute(Qt::WA_Resized))
setAttribute(Qt::WA_Resized, false);
break;
}
case QEvent::WindowActivate:
if (d->ignoreNextActivationEvent) {
d->ignoreNextActivationEvent = false;
break;
}
d->isExplicitlyDeactivated = false;
d->setActive(true);
break;
case QEvent::WindowDeactivate:
if (d->ignoreNextActivationEvent) {
d->ignoreNextActivationEvent = false;
break;
}
d->isExplicitlyDeactivated = true;
d->setActive(false);
break;
case QEvent::WindowTitleChange:
if (!d->ignoreWindowTitleChange)
d->updateWindowTitle(false);
d->updateInternalWindowTitle();
break;
case QEvent::ModifiedChange:
if (!windowTitle().contains(QLatin1String("[*]")))
break;
#ifndef QT_NO_MENUBAR
if (maximizedButtonsWidget() && d->controlContainer->menuBar() && d->controlContainer->menuBar()
->cornerWidget(Qt::TopRightCorner) == maximizedButtonsWidget()) {
window()->setWindowModified(isWindowModified());
}
#endif // QT_NO_MENUBAR
d->updateInternalWindowTitle();
break;
case QEvent::LayoutDirectionChange:
d->updateDirtyRegions();
break;
case QEvent::LayoutRequest:
d->updateGeometryConstraints();
break;
case QEvent::WindowIconChange:
d->menuIcon = windowIcon();
if (d->menuIcon.isNull())
d->menuIcon = style()->standardIcon(QStyle::SP_TitleBarMenuButton, 0, this);
if (d->controlContainer)
d->controlContainer->updateWindowIcon(d->menuIcon);
if (!maximizedSystemMenuIconWidget())
update(0, 0, width(), d->titleBarHeight());
break;
case QEvent::PaletteChange:
d->titleBarPalette = d->desktopPalette();
break;
case QEvent::FontChange:
d->font = font();
break;
#ifndef QT_NO_TOOLTIP
case QEvent::ToolTip:
showToolTip(static_cast<QHelpEvent *>(event), this, d->titleBarOptions(),
QStyle::CC_TitleBar, d->hoveredSubControl);
break;
#endif
default:
break;
}
return QWidget::event(event);
}
/*!
\reimp
*/
void QMdiSubWindow::showEvent(QShowEvent *showEvent)
{
Q_D(QMdiSubWindow);
if (!parent()) {
QWidget::showEvent(showEvent);
return;
}
#if !defined(QT_NO_SIZEGRIP) && defined(Q_WS_MAC) && !defined(QT_NO_STYLE_MAC)
if (qobject_cast<QMacStyle *>(style()) && !d->sizeGrip
&& !(windowFlags() & Qt::FramelessWindowHint)) {
d->setSizeGrip(new QSizeGrip(0));
Q_ASSERT(d->sizeGrip);
if (isMinimized())
d->setSizeGripVisible(false);
else
d->setSizeGripVisible(true);
resize(size().expandedTo(d->internalMinimumSize));
}
#endif
d->updateDirtyRegions();
// Show buttons in the menu bar if they're already not there.
// We want to do this when QMdiSubWindow becomes visible after being hidden.
#ifndef QT_NO_MENUBAR
if (d->controlContainer) {
if (QMenuBar *menuBar = d->menuBar()) {
if (menuBar->cornerWidget(Qt::TopRightCorner) != maximizedButtonsWidget())
d->showButtonsInMenuBar(menuBar);
}
}
#endif
d->setActive(true);
}
/*!
\reimp
*/
void QMdiSubWindow::hideEvent(QHideEvent * /*hideEvent*/)
{
#ifndef QT_NO_MENUBAR
d_func()->removeButtonsFromMenuBar();
#endif
}
/*!
\reimp
*/
void QMdiSubWindow::changeEvent(QEvent *changeEvent)
{
if (!parent()) {
QWidget::changeEvent(changeEvent);
return;
}
if (changeEvent->type() != QEvent::WindowStateChange) {
QWidget::changeEvent(changeEvent);
return;
}
QWindowStateChangeEvent *event = static_cast<QWindowStateChangeEvent *>(changeEvent);
if (event->isOverride()) {
event->ignore();
return;
}
Qt::WindowStates oldState = event->oldState();
Qt::WindowStates newState = windowState();
if (oldState == newState) {
changeEvent->ignore();
return;
}
// QWidget ensures that the widget is visible _after_ setWindowState(),
// but we need to ensure that the widget is visible _before_
// setWindowState() returns.
Q_D(QMdiSubWindow);
if (!isVisible()) {
d->ensureWindowState(Qt::WindowNoState);
setVisible(true);
}
if (!d->oldGeometry.isValid())
d->oldGeometry = geometry();
if ((oldState & Qt::WindowActive) && (newState & Qt::WindowActive))
d->currentOperation = QMdiSubWindowPrivate::None;
if (!(oldState & Qt::WindowMinimized) && (newState & Qt::WindowMinimized))
d->setMinimizeMode();
else if (!(oldState & Qt::WindowMaximized) && (newState & Qt::WindowMaximized))
d->setMaximizeMode();
else if (!(newState & (Qt::WindowMaximized | Qt::WindowMinimized)))
d->setNormalMode();
if (d->isActive)
d->ensureWindowState(Qt::WindowActive);
emit windowStateChanged(oldState, windowState());
}
/*!
\reimp
*/
void QMdiSubWindow::closeEvent(QCloseEvent *closeEvent)
{
Q_D(QMdiSubWindow);
bool acceptClose = true;
if (d->baseWidget)
acceptClose = d->baseWidget->close();
if (!acceptClose) {
closeEvent->ignore();
return;
}
#ifndef QT_NO_MENUBAR
d->removeButtonsFromMenuBar();
#endif
d->setActive(false);
if (parentWidget() && testAttribute(Qt::WA_DeleteOnClose)) {
QChildEvent childRemoved(QEvent::ChildRemoved, this);
QApplication::sendEvent(parentWidget(), &childRemoved);
}
closeEvent->accept();
}
/*!
\reimp
*/
void QMdiSubWindow::leaveEvent(QEvent * /*leaveEvent*/)
{
Q_D(QMdiSubWindow);
if (d->hoveredSubControl != QStyle::SC_None) {
d->hoveredSubControl = QStyle::SC_None;
update(QRegion(0, 0, width(), d->titleBarHeight()));
}
}
/*!
\reimp
*/
void QMdiSubWindow::resizeEvent(QResizeEvent *resizeEvent)
{
Q_D(QMdiSubWindow);
#ifndef QT_NO_SIZEGRIP
if (d->sizeGrip) {
d->sizeGrip->move(isLeftToRight() ? width() - d->sizeGrip->width() : 0,
height() - d->sizeGrip->height());
}
#endif
if (!parent()) {
QWidget::resizeEvent(resizeEvent);
return;
}
if (d->isMaximizeMode)
d->ensureWindowState(Qt::WindowMaximized);
d->updateMask();
if (!isVisible())
return;
if (d->resizeTimerId <= 0)
d->cachedStyleOptions = d->titleBarOptions();
else
killTimer(d->resizeTimerId);
d->resizeTimerId = startTimer(200);
}
/*!
\reimp
*/
void QMdiSubWindow::timerEvent(QTimerEvent *timerEvent)
{
Q_D(QMdiSubWindow);
if (timerEvent->timerId() == d->resizeTimerId) {
killTimer(d->resizeTimerId);
d->resizeTimerId = -1;
d->updateDirtyRegions();
}
}
/*!
\reimp
*/
void QMdiSubWindow::moveEvent(QMoveEvent *moveEvent)
{
if (!parent()) {
QWidget::moveEvent(moveEvent);
return;
}
Q_D(QMdiSubWindow);
if (d->isMaximizeMode)
d->ensureWindowState(Qt::WindowMaximized);
}
/*!
\reimp
*/
void QMdiSubWindow::paintEvent(QPaintEvent *paintEvent)
{
if (!parent() || (windowFlags() & Qt::FramelessWindowHint)) {
QWidget::paintEvent(paintEvent);
return;
}
Q_D(QMdiSubWindow);
if (isMaximized() && !d->drawTitleBarWhenMaximized())
return;
if (d->resizeTimerId != -1) {
// Only update the style option rect and the window title.
int border = d->hasBorder(d->cachedStyleOptions) ? 4 : 0;
int titleBarHeight = d->titleBarHeight(d->cachedStyleOptions);
titleBarHeight -= isMinimized() ? 2 * border : border;
d->cachedStyleOptions.rect = QRect(border, border, width() - 2 * border, titleBarHeight);
if (!d->windowTitle.isEmpty()) {
int width = style()->subControlRect(QStyle::CC_TitleBar, &d->cachedStyleOptions,
QStyle::SC_TitleBarLabel, this).width();
d->cachedStyleOptions.text = d->cachedStyleOptions.fontMetrics
.elidedText(d->windowTitle, Qt::ElideRight, width);
}
} else {
// Force full update.
d->cachedStyleOptions = d->titleBarOptions();
}
QStylePainter painter(this);
if (!d->windowTitle.isEmpty())
painter.setFont(d->font);
painter.drawComplexControl(QStyle::CC_TitleBar, d->cachedStyleOptions);
if (isMinimized() && !d->hasBorder(d->cachedStyleOptions))
return;
QStyleOptionFrame frameOptions;
frameOptions.initFrom(this);
frameOptions.lineWidth = style()->pixelMetric(QStyle::PM_MdiSubWindowFrameWidth, 0, this);
if (d->isActive)
frameOptions.state |= QStyle::State_Active;
else
frameOptions.state &= ~QStyle::State_Active;
// ### Ensure that we do not require setting the cliprect for 4.4
if (!isMinimized() && !d->hasBorder(d->cachedStyleOptions))
painter.setClipRect(rect().adjusted(0, d->titleBarHeight(d->cachedStyleOptions), 0, 0));
if (!isMinimized() || d->hasBorder(d->cachedStyleOptions))
painter.drawPrimitive(QStyle::PE_FrameWindow, frameOptions);
}
/*!
\reimp
*/
void QMdiSubWindow::mousePressEvent(QMouseEvent *mouseEvent)
{
if (!parent()) {
QWidget::mousePressEvent(mouseEvent);
return;
}
Q_D(QMdiSubWindow);
if (d->isInInteractiveMode)
d->leaveInteractiveMode();
#ifndef QT_NO_RUBBERBAND
if (d->isInRubberBandMode)
d->leaveRubberBandMode();
#endif
if (mouseEvent->button() != Qt::LeftButton) {
mouseEvent->ignore();
return;
}
if (d->currentOperation != QMdiSubWindowPrivate::None) {
d->updateCursor();
d->mousePressPosition = mapToParent(mouseEvent->pos());
if (d->resizeEnabled || d->moveEnabled)
d->oldGeometry = geometry();
#ifndef QT_NO_RUBBERBAND
if ((testOption(QMdiSubWindow::RubberBandResize) && d->isResizeOperation())
|| (testOption(QMdiSubWindow::RubberBandMove) && d->isMoveOperation())) {
d->enterRubberBandMode();
}
#endif
return;
}
d->activeSubControl = d->hoveredSubControl;
#ifndef QT_NO_MENU
if (d->activeSubControl == QStyle::SC_TitleBarSysMenu)
showSystemMenu();
else
#endif
update(QRegion(0, 0, width(), d->titleBarHeight()));
}
/*!
\reimp
*/
void QMdiSubWindow::mouseDoubleClickEvent(QMouseEvent *mouseEvent)
{
if (!parent()) {
QWidget::mouseDoubleClickEvent(mouseEvent);
return;
}
if (mouseEvent->button() != Qt::LeftButton) {
mouseEvent->ignore();
return;
}
Q_D(QMdiSubWindow);
if (!d->isMoveOperation()) {
#ifndef QT_NO_MENU
if (d->hoveredSubControl == QStyle::SC_TitleBarSysMenu)
close();
#endif
return;
}
Qt::WindowFlags flags = windowFlags();
if (isMinimized()) {
if ((isShaded() && (flags & Qt::WindowShadeButtonHint))
|| (flags & Qt::WindowMinimizeButtonHint)) {
showNormal();
}
return;
}
if (isMaximized()) {
if (flags & Qt::WindowMaximizeButtonHint)
showNormal();
return;
}
if (flags & Qt::WindowShadeButtonHint)
showShaded();
else if (flags & Qt::WindowMaximizeButtonHint)
showMaximized();
}
/*!
\reimp
*/
void QMdiSubWindow::mouseReleaseEvent(QMouseEvent *mouseEvent)
{
if (!parent()) {
QWidget::mouseReleaseEvent(mouseEvent);
return;
}
if (mouseEvent->button() != Qt::LeftButton) {
mouseEvent->ignore();
return;
}
Q_D(QMdiSubWindow);
if (d->currentOperation != QMdiSubWindowPrivate::None) {
#ifndef QT_NO_RUBBERBAND
if (d->isInRubberBandMode && !d->isInInteractiveMode)
d->leaveRubberBandMode();
#endif
if (d->resizeEnabled || d->moveEnabled)
d->oldGeometry = geometry();
}
d->currentOperation = d->getOperation(mouseEvent->pos());
d->updateCursor();
d->hoveredSubControl = d->getSubControl(mouseEvent->pos());
if (d->activeSubControl != QStyle::SC_None
&& d->activeSubControl == d->hoveredSubControl) {
d->processClickedSubControl();
}
d->activeSubControl = QStyle::SC_None;
update(QRegion(0, 0, width(), d->titleBarHeight()));
}
/*!
\reimp
*/
void QMdiSubWindow::mouseMoveEvent(QMouseEvent *mouseEvent)
{
if (!parent()) {
QWidget::mouseMoveEvent(mouseEvent);
return;
}
Q_D(QMdiSubWindow);
// No update needed if we're in a move/resize operation.
if (!d->isMoveOperation() && !d->isResizeOperation()) {
// Find previous and current hover region.
const QStyleOptionTitleBar options = d->titleBarOptions();
QStyle::SubControl oldHover = d->hoveredSubControl;
d->hoveredSubControl = d->getSubControl(mouseEvent->pos());
QRegion hoverRegion;
if (isHoverControl(oldHover) && oldHover != d->hoveredSubControl)
hoverRegion += style()->subControlRect(QStyle::CC_TitleBar, &options, oldHover, this);
if (isHoverControl(d->hoveredSubControl) && d->hoveredSubControl != oldHover) {
hoverRegion += style()->subControlRect(QStyle::CC_TitleBar, &options,
d->hoveredSubControl, this);
}
#if defined(Q_WS_MAC) && !defined(QT_NO_STYLE_MAC)
if (qobject_cast<QMacStyle *>(style()) && !hoverRegion.isEmpty())
hoverRegion += QRegion(0, 0, width(), d->titleBarHeight(options));
#endif
if (!hoverRegion.isEmpty())
update(hoverRegion);
}
if ((mouseEvent->buttons() & Qt::LeftButton) || d->isInInteractiveMode) {
if ((d->isResizeOperation() && d->resizeEnabled) || (d->isMoveOperation() && d->moveEnabled))
d->setNewGeometry(mapToParent(mouseEvent->pos()));
return;
}
// Do not resize/move if not allowed.
d->currentOperation = d->getOperation(mouseEvent->pos());
if ((d->isResizeOperation() && !d->resizeEnabled) || (d->isMoveOperation() && !d->moveEnabled))
d->currentOperation = QMdiSubWindowPrivate::None;
d->updateCursor();
}
/*!
\reimp
*/
void QMdiSubWindow::keyPressEvent(QKeyEvent *keyEvent)
{
Q_D(QMdiSubWindow);
if (!d->isInInteractiveMode || !parent()) {
keyEvent->ignore();
return;
}
QPoint delta;
switch (keyEvent->key()) {
case Qt::Key_Right:
if (keyEvent->modifiers() & Qt::ShiftModifier)
delta = QPoint(d->keyboardPageStep, 0);
else
delta = QPoint(d->keyboardSingleStep, 0);
break;
case Qt::Key_Up:
if (keyEvent->modifiers() & Qt::ShiftModifier)
delta = QPoint(0, -d->keyboardPageStep);
else
delta = QPoint(0, -d->keyboardSingleStep);
break;
case Qt::Key_Left:
if (keyEvent->modifiers() & Qt::ShiftModifier)
delta = QPoint(-d->keyboardPageStep, 0);
else
delta = QPoint(-d->keyboardSingleStep, 0);
break;
case Qt::Key_Down:
if (keyEvent->modifiers() & Qt::ShiftModifier)
delta = QPoint(0, d->keyboardPageStep);
else
delta = QPoint(0, d->keyboardSingleStep);
break;
case Qt::Key_Escape:
case Qt::Key_Return:
case Qt::Key_Enter:
d->leaveInteractiveMode();
return;
default:
keyEvent->ignore();
return;
}
#ifndef QT_NO_CURSOR
QPoint newPosition = parentWidget()->mapFromGlobal(cursor().pos() + delta);
QRect oldGeometry =
#ifndef QT_NO_RUBBERBAND
d->isInRubberBandMode ? d->rubberBand->geometry() :
#endif
geometry();
d->setNewGeometry(newPosition);
QRect currentGeometry =
#ifndef QT_NO_RUBBERBAND
d->isInRubberBandMode ? d->rubberBand->geometry() :
#endif
geometry();
if (currentGeometry == oldGeometry)
return;
// Update cursor position
QPoint actualDelta;
if (d->isMoveOperation()) {
actualDelta = QPoint(currentGeometry.x() - oldGeometry.x(),
currentGeometry.y() - oldGeometry.y());
} else {
int dx = isLeftToRight() ? currentGeometry.width() - oldGeometry.width()
: currentGeometry.x() - oldGeometry.x();
actualDelta = QPoint(dx, currentGeometry.height() - oldGeometry.height());
}
// Adjust in case we weren't able to move as long as wanted.
if (actualDelta != delta)
newPosition += (actualDelta - delta);
cursor().setPos(parentWidget()->mapToGlobal(newPosition));
#endif
}
#ifndef QT_NO_CONTEXTMENU
/*!
\reimp
*/
void QMdiSubWindow::contextMenuEvent(QContextMenuEvent *contextMenuEvent)
{
Q_D(QMdiSubWindow);
if (!d->systemMenu) {
contextMenuEvent->ignore();
return;
}
if (d->hoveredSubControl == QStyle::SC_TitleBarSysMenu
|| d->getRegion(QMdiSubWindowPrivate::Move).contains(contextMenuEvent->pos())) {
d->systemMenu->exec(contextMenuEvent->globalPos());
} else {
contextMenuEvent->ignore();
}
}
#endif // QT_NO_CONTEXTMENU
/*!
\reimp
*/
void QMdiSubWindow::focusInEvent(QFocusEvent *focusInEvent)
{
d_func()->focusInReason = focusInEvent->reason();
}
/*!
\reimp
*/
void QMdiSubWindow::focusOutEvent(QFocusEvent * /*focusOutEvent*/)
{
// To avoid update() in QWidget::focusOutEvent.
}
/*!
\reimp
*/
void QMdiSubWindow::childEvent(QChildEvent *childEvent)
{
if (childEvent->type() != QEvent::ChildPolished)
return;
#ifndef QT_NO_SIZEGRIP
if (QSizeGrip *sizeGrip = qobject_cast<QSizeGrip *>(childEvent->child()))
d_func()->setSizeGrip(sizeGrip);
#endif
}
/*!
\reimp
*/
QSize QMdiSubWindow::sizeHint() const
{
Q_D(const QMdiSubWindow);
int margin, minWidth;
d->sizeParameters(&margin, &minWidth);
QSize size(2 * margin, d->titleBarHeight() + margin);
if (d->baseWidget && d->baseWidget->sizeHint().isValid())
size += d->baseWidget->sizeHint();
return size.expandedTo(minimumSizeHint());
}
/*!
\reimp
*/
QSize QMdiSubWindow::minimumSizeHint() const
{
Q_D(const QMdiSubWindow);
if (isVisible())
ensurePolished();
// Minimized window.
if (parent() && isMinimized() && !isShaded())
return d->iconSize();
// Calculate window decoration.
int margin, minWidth;
d->sizeParameters(&margin, &minWidth);
int decorationHeight = margin + d->titleBarHeight();
int minHeight = decorationHeight;
// Shaded window.
if (parent() && isShaded())
return QSize(qMax(minWidth, width()), d->titleBarHeight());
// Content
if (layout()) {
QSize minLayoutSize = layout()->minimumSize();
if (minLayoutSize.isValid()) {
minWidth = qMax(minWidth, minLayoutSize.width() + 2 * margin);
minHeight += minLayoutSize.height();
}
} else if (d->baseWidget && d->baseWidget->isVisible()) {
QSize minBaseWidgetSize = d->baseWidget->minimumSizeHint();
if (minBaseWidgetSize.isValid()) {
minWidth = qMax(minWidth, minBaseWidgetSize.width() + 2 * margin);
minHeight += minBaseWidgetSize.height();
}
}
#ifndef QT_NO_SIZEGRIP
// SizeGrip
int sizeGripHeight = 0;
if (d->sizeGrip && d->sizeGrip->isVisibleTo(const_cast<QMdiSubWindow *>(this)))
sizeGripHeight = d->sizeGrip->height();
#if defined(Q_WS_MAC) && !defined(QT_NO_STYLE_MAC)
else if (parent() && qobject_cast<QMacStyle *>(style()) && !d->sizeGrip)
sizeGripHeight = style()->pixelMetric(QStyle::PM_SizeGripSize, 0, this);
#endif
minHeight = qMax(minHeight, decorationHeight + sizeGripHeight);
#endif
return QSize(minWidth, minHeight).expandedTo(QApplication::globalStrut());
}
QT_END_NAMESPACE
#include "moc_qmdisubwindow.cpp"
#include "qmdisubwindow.moc"
#endif //QT_NO_MDIAREA