/**************************************************************************** | |
** | |
** Copyright (C) 2011 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$ | |
** GNU Lesser General Public License Usage | |
** 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. | |
** | |
** GNU General Public License Usage | |
** Alternatively, this file may be used under the terms of the GNU General | |
** Public License version 3.0 as published by the Free Software Foundation | |
** and appearing in the file LICENSE.GPL included in the packaging of this | |
** file. Please review the following information to ensure the GNU General | |
** Public License version 3.0 requirements will be met: | |
** http://www.gnu.org/copyleft/gpl.html. | |
** | |
** Other Usage | |
** Alternatively, this file may be used in accordance with the terms and | |
** conditions contained in a signed written agreement between you and Nokia. | |
** | |
** | |
** | |
** | |
** | |
** $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 |