/**************************************************************************** | |
** | |
** 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$ | |
** | |
****************************************************************************/ | |
#include "qworkspace.h" | |
#ifndef QT_NO_WORKSPACE | |
#include "qapplication.h" | |
#include "qbitmap.h" | |
#include "qcursor.h" | |
#include "qdesktopwidget.h" | |
#include "qevent.h" | |
#include "qhash.h" | |
#include "qicon.h" | |
#include "qimage.h" | |
#include "qlabel.h" | |
#include "qlayout.h" | |
#include "qmenubar.h" | |
#include "qmenu.h" | |
#include "qpainter.h" | |
#include "qpointer.h" | |
#include "qscrollbar.h" | |
#include "qstyle.h" | |
#include "qstyleoption.h" | |
#include "qelapsedtimer.h" | |
#include "qtooltip.h" | |
#include "qdebug.h" | |
#include <private/qwidget_p.h> | |
#include <private/qwidgetresizehandler_p.h> | |
#include <private/qlayoutengine_p.h> | |
QT_BEGIN_NAMESPACE | |
class QWorkspaceTitleBarPrivate; | |
/************************************************************** | |
* QMDIControl | |
* | |
* Used for displaying MDI controls in a maximized MDI window | |
* | |
*/ | |
class QMDIControl : public QWidget | |
{ | |
Q_OBJECT | |
signals: | |
void _q_minimize(); | |
void _q_restore(); | |
void _q_close(); | |
public: | |
QMDIControl(QWidget *widget); | |
private: | |
QSize sizeHint() const; | |
void paintEvent(QPaintEvent *event); | |
void mousePressEvent(QMouseEvent *event); | |
void mouseReleaseEvent(QMouseEvent *event); | |
void mouseMoveEvent(QMouseEvent *event); | |
void leaveEvent(QEvent *event); | |
bool event(QEvent *event); | |
void initStyleOption(QStyleOptionComplex *option) const; | |
QStyle::SubControl activeControl; //control locked by pressing and holding the mouse | |
QStyle::SubControl hoverControl; //previously active hover control, used for tracking repaints | |
}; | |
bool QMDIControl::event(QEvent *event) | |
{ | |
if (event->type() == QEvent::ToolTip) { | |
QStyleOptionComplex opt; | |
initStyleOption(&opt); | |
#ifndef QT_NO_TOOLTIP | |
QHelpEvent *helpEvent = static_cast<QHelpEvent *>(event); | |
QStyle::SubControl ctrl = style()->hitTestComplexControl(QStyle::CC_MdiControls, &opt, | |
helpEvent->pos(), this); | |
if (ctrl == QStyle::SC_MdiCloseButton) | |
QToolTip::showText(helpEvent->globalPos(), QWorkspace::tr("Close"), this); | |
else if (ctrl == QStyle::SC_MdiMinButton) | |
QToolTip::showText(helpEvent->globalPos(), QWorkspace::tr("Minimize"), this); | |
else if (ctrl == QStyle::SC_MdiNormalButton) | |
QToolTip::showText(helpEvent->globalPos(), QWorkspace::tr("Restore Down"), this); | |
else | |
QToolTip::hideText(); | |
#endif // QT_NO_TOOLTIP | |
} | |
return QWidget::event(event); | |
} | |
void QMDIControl::initStyleOption(QStyleOptionComplex *option) const | |
{ | |
option->initFrom(this); | |
option->subControls = QStyle::SC_All; | |
option->activeSubControls = QStyle::SC_None; | |
} | |
QMDIControl::QMDIControl(QWidget *widget) | |
: QWidget(widget), activeControl(QStyle::SC_None), | |
hoverControl(QStyle::SC_None) | |
{ | |
setObjectName(QLatin1String("qt_maxcontrols")); | |
setFocusPolicy(Qt::NoFocus); | |
setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum); | |
setMouseTracking(true); | |
} | |
QSize QMDIControl::sizeHint() const | |
{ | |
ensurePolished(); | |
QStyleOptionComplex opt; | |
initStyleOption(&opt); | |
QSize size(48, 16); | |
return style()->sizeFromContents(QStyle::CT_MdiControls, &opt, size, this); | |
} | |
void QMDIControl::mousePressEvent(QMouseEvent *event) | |
{ | |
if (event->button() != Qt::LeftButton) { | |
event->ignore(); | |
return; | |
} | |
QStyleOptionComplex opt; | |
initStyleOption(&opt); | |
QStyle::SubControl ctrl = style()->hitTestComplexControl(QStyle::CC_MdiControls, &opt, | |
event->pos(), this); | |
activeControl = ctrl; | |
update(); | |
} | |
void QMDIControl::mouseReleaseEvent(QMouseEvent *event) | |
{ | |
if (event->button() != Qt::LeftButton) { | |
event->ignore(); | |
return; | |
} | |
QStyleOptionTitleBar opt; | |
initStyleOption(&opt); | |
QStyle::SubControl under_mouse = style()->hitTestComplexControl(QStyle::CC_MdiControls, &opt, | |
event->pos(), this); | |
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(); | |
} | |
void QMDIControl::leaveEvent(QEvent * /*event*/) | |
{ | |
hoverControl = QStyle::SC_None; | |
update(); | |
} | |
void QMDIControl::mouseMoveEvent(QMouseEvent *event) | |
{ | |
QStyleOptionTitleBar opt; | |
initStyleOption(&opt); | |
QStyle::SubControl under_mouse = style()->hitTestComplexControl(QStyle::CC_MdiControls, &opt, | |
event->pos(), this); | |
//test if hover state changes | |
if (hoverControl != under_mouse) { | |
hoverControl = under_mouse; | |
update(); | |
} | |
} | |
void QMDIControl::paintEvent(QPaintEvent *) | |
{ | |
QPainter p(this); | |
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; | |
} | |
style()->drawComplexControl(QStyle::CC_MdiControls, &opt, &p, this); | |
} | |
class QWorkspaceTitleBar : public QWidget | |
{ | |
Q_OBJECT | |
Q_DECLARE_PRIVATE(QWorkspaceTitleBar) | |
Q_PROPERTY(bool autoRaise READ autoRaise WRITE setAutoRaise) | |
Q_PROPERTY(bool movable READ isMovable WRITE setMovable) | |
public: | |
QWorkspaceTitleBar (QWidget *w, QWidget *parent, Qt::WindowFlags f = 0); | |
~QWorkspaceTitleBar(); | |
bool isActive() const; | |
bool usesActiveColor() const; | |
bool isMovable() const; | |
void setMovable(bool); | |
bool autoRaise() const; | |
void setAutoRaise(bool); | |
QWidget *window() const; | |
bool isTool() const; | |
QSize sizeHint() const; | |
void initStyleOption(QStyleOptionTitleBar *option) const; | |
public slots: | |
void setActive(bool); | |
signals: | |
void doActivate(); | |
void doNormal(); | |
void doClose(); | |
void doMaximize(); | |
void doMinimize(); | |
void doShade(); | |
void showOperationMenu(); | |
void popupOperationMenu(const QPoint&); | |
void doubleClicked(); | |
protected: | |
bool event(QEvent *); | |
#ifndef QT_NO_CONTEXTMENU | |
void contextMenuEvent(QContextMenuEvent *); | |
#endif | |
void mousePressEvent(QMouseEvent *); | |
void mouseDoubleClickEvent(QMouseEvent *); | |
void mouseReleaseEvent(QMouseEvent *); | |
void mouseMoveEvent(QMouseEvent *); | |
void enterEvent(QEvent *e); | |
void leaveEvent(QEvent *e); | |
void paintEvent(QPaintEvent *p); | |
private: | |
Q_DISABLE_COPY(QWorkspaceTitleBar) | |
}; | |
class QWorkspaceTitleBarPrivate : public QWidgetPrivate | |
{ | |
Q_DECLARE_PUBLIC(QWorkspaceTitleBar) | |
public: | |
QWorkspaceTitleBarPrivate() | |
: | |
lastControl(QStyle::SC_None), | |
#ifndef QT_NO_TOOLTIP | |
toolTip(0), | |
#endif | |
act(0), window(0), movable(1), pressed(0), autoraise(0), moving(0) | |
{ | |
} | |
Qt::WindowFlags flags; | |
QStyle::SubControl buttonDown; | |
QStyle::SubControl lastControl; | |
QPoint moveOffset; | |
#ifndef QT_NO_TOOLTIP | |
QToolTip *toolTip; | |
#endif | |
bool act :1; | |
QPointer<QWidget> window; | |
bool movable :1; | |
bool pressed :1; | |
bool autoraise :1; | |
bool moving : 1; | |
int titleBarState() const; | |
void readColors(); | |
}; | |
inline int QWorkspaceTitleBarPrivate::titleBarState() const | |
{ | |
Q_Q(const QWorkspaceTitleBar); | |
uint state = window ? window->windowState() : static_cast<Qt::WindowStates>(Qt::WindowNoState); | |
state |= uint((act && q->isActiveWindow()) ? QStyle::State_Active : QStyle::State_None); | |
return (int)state; | |
} | |
void QWorkspaceTitleBar::initStyleOption(QStyleOptionTitleBar *option) const | |
{ | |
Q_D(const QWorkspaceTitleBar); | |
option->initFrom(this); | |
//################ | |
if (d->window && (d->flags & Qt::WindowTitleHint)) { | |
option->text = d->window->windowTitle(); | |
QIcon icon = d->window->windowIcon(); | |
QSize s = icon.actualSize(QSize(64, 64)); | |
option->icon = icon.pixmap(s); | |
} | |
option->subControls = QStyle::SC_All; | |
option->activeSubControls = QStyle::SC_None; | |
option->titleBarState = d->titleBarState(); | |
option->titleBarFlags = d->flags; | |
option->state &= ~QStyle::State_MouseOver; | |
} | |
QWorkspaceTitleBar::QWorkspaceTitleBar(QWidget *w, QWidget *parent, Qt::WindowFlags f) | |
: QWidget(*new QWorkspaceTitleBarPrivate, parent, Qt::FramelessWindowHint) | |
{ | |
Q_D(QWorkspaceTitleBar); | |
if (f == 0 && w) | |
f = w->windowFlags(); | |
d->flags = f; | |
d->window = w; | |
d->buttonDown = QStyle::SC_None; | |
d->act = 0; | |
if (w) { | |
if (w->maximumSize() != QSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX)) | |
d->flags &= ~Qt::WindowMaximizeButtonHint; | |
setWindowTitle(w->windowTitle()); | |
} | |
d->readColors(); | |
setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed)); | |
setMouseTracking(true); | |
setAutoRaise(style()->styleHint(QStyle::SH_TitleBar_AutoRaise, 0, this)); | |
} | |
QWorkspaceTitleBar::~QWorkspaceTitleBar() | |
{ | |
} | |
#ifdef Q_WS_WIN | |
static inline QRgb colorref2qrgb(COLORREF col) | |
{ | |
return qRgb(GetRValue(col),GetGValue(col),GetBValue(col)); | |
} | |
#endif | |
void QWorkspaceTitleBarPrivate::readColors() | |
{ | |
Q_Q(QWorkspaceTitleBar); | |
QPalette pal = 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()) { | |
pal.setColor(QPalette::Active, QPalette::Highlight, colorref2qrgb(GetSysColor(COLOR_ACTIVECAPTION))); | |
pal.setColor(QPalette::Inactive, QPalette::Highlight, colorref2qrgb(GetSysColor(COLOR_INACTIVECAPTION))); | |
pal.setColor(QPalette::Active, QPalette::HighlightedText, colorref2qrgb(GetSysColor(COLOR_CAPTIONTEXT))); | |
pal.setColor(QPalette::Inactive, QPalette::HighlightedText, colorref2qrgb(GetSysColor(COLOR_INACTIVECAPTIONTEXT))); | |
colorsInitialized = true; | |
BOOL gradient = false; | |
SystemParametersInfo(SPI_GETGRADIENTCAPTIONS, 0, &gradient, 0); | |
if (gradient) { | |
pal.setColor(QPalette::Active, QPalette::Base, colorref2qrgb(GetSysColor(COLOR_GRADIENTACTIVECAPTION))); | |
pal.setColor(QPalette::Inactive, QPalette::Base, colorref2qrgb(GetSysColor(COLOR_GRADIENTINACTIVECAPTION))); | |
} else { | |
pal.setColor(QPalette::Active, QPalette::Base, pal.color(QPalette::Active, QPalette::Highlight)); | |
pal.setColor(QPalette::Inactive, QPalette::Base, pal.color(QPalette::Inactive, QPalette::Highlight)); | |
} | |
} | |
#endif // Q_WS_WIN | |
if (!colorsInitialized) { | |
pal.setColor(QPalette::Active, QPalette::Highlight, | |
pal.color(QPalette::Active, QPalette::Highlight)); | |
pal.setColor(QPalette::Active, QPalette::Base, | |
pal.color(QPalette::Active, QPalette::Highlight)); | |
pal.setColor(QPalette::Inactive, QPalette::Highlight, | |
pal.color(QPalette::Inactive, QPalette::Dark)); | |
pal.setColor(QPalette::Inactive, QPalette::Base, | |
pal.color(QPalette::Inactive, QPalette::Dark)); | |
pal.setColor(QPalette::Inactive, QPalette::HighlightedText, | |
pal.color(QPalette::Inactive, QPalette::Window)); | |
} | |
q->setPalette(pal); | |
q->setActive(act); | |
} | |
void QWorkspaceTitleBar::mousePressEvent(QMouseEvent *e) | |
{ | |
Q_D(QWorkspaceTitleBar); | |
if (!d->act) | |
emit doActivate(); | |
if (e->button() == Qt::LeftButton) { | |
if (style()->styleHint(QStyle::SH_TitleBar_NoBorder, 0, 0) | |
&& !rect().adjusted(5, 5, -5, 0).contains(e->pos())) { | |
// propagate border events to the QWidgetResizeHandler | |
e->ignore(); | |
return; | |
} | |
d->pressed = true; | |
QStyleOptionTitleBar opt; | |
initStyleOption(&opt); | |
QStyle::SubControl ctrl = style()->hitTestComplexControl(QStyle::CC_TitleBar, &opt, | |
e->pos(), this); | |
switch (ctrl) { | |
case QStyle::SC_TitleBarSysMenu: | |
if (d->flags & Qt::WindowSystemMenuHint) { | |
d->buttonDown = QStyle::SC_None; | |
static QElapsedTimer *t = 0; | |
static QWorkspaceTitleBar *tc = 0; | |
if (!t) | |
t = new QElapsedTimer; | |
if (tc != this || t->elapsed() > QApplication::doubleClickInterval()) { | |
emit showOperationMenu(); | |
t->start(); | |
tc = this; | |
} else { | |
tc = 0; | |
emit doClose(); | |
return; | |
} | |
} | |
break; | |
case QStyle::SC_TitleBarShadeButton: | |
case QStyle::SC_TitleBarUnshadeButton: | |
if (d->flags & Qt::WindowShadeButtonHint) | |
d->buttonDown = ctrl; | |
break; | |
case QStyle::SC_TitleBarNormalButton: | |
d->buttonDown = ctrl; | |
break; | |
case QStyle::SC_TitleBarMinButton: | |
if (d->flags & Qt::WindowMinimizeButtonHint) | |
d->buttonDown = ctrl; | |
break; | |
case QStyle::SC_TitleBarMaxButton: | |
if (d->flags & Qt::WindowMaximizeButtonHint) | |
d->buttonDown = ctrl; | |
break; | |
case QStyle::SC_TitleBarCloseButton: | |
if (d->flags & Qt::WindowSystemMenuHint) | |
d->buttonDown = ctrl; | |
break; | |
case QStyle::SC_TitleBarLabel: | |
d->buttonDown = ctrl; | |
d->moveOffset = mapToParent(e->pos()); | |
break; | |
default: | |
break; | |
} | |
update(); | |
} else { | |
d->pressed = false; | |
} | |
} | |
#ifndef QT_NO_CONTEXTMENU | |
void QWorkspaceTitleBar::contextMenuEvent(QContextMenuEvent *e) | |
{ | |
QStyleOptionTitleBar opt; | |
initStyleOption(&opt); | |
QStyle::SubControl ctrl = style()->hitTestComplexControl(QStyle::CC_TitleBar, &opt, e->pos(), | |
this); | |
if(ctrl == QStyle::SC_TitleBarLabel || ctrl == QStyle::SC_TitleBarSysMenu) { | |
e->accept(); | |
emit popupOperationMenu(e->globalPos()); | |
} else { | |
e->ignore(); | |
} | |
} | |
#endif // QT_NO_CONTEXTMENU | |
void QWorkspaceTitleBar::mouseReleaseEvent(QMouseEvent *e) | |
{ | |
Q_D(QWorkspaceTitleBar); | |
if (!d->window) { | |
// could have been deleted as part of a double click event on the sysmenu | |
return; | |
} | |
if (e->button() == Qt::LeftButton && d->pressed) { | |
if (style()->styleHint(QStyle::SH_TitleBar_NoBorder, 0, 0) | |
&& !rect().adjusted(5, 5, -5, 0).contains(e->pos())) { | |
// propagate border events to the QWidgetResizeHandler | |
e->ignore(); | |
d->buttonDown = QStyle::SC_None; | |
d->pressed = false; | |
return; | |
} | |
e->accept(); | |
QStyleOptionTitleBar opt; | |
initStyleOption(&opt); | |
QStyle::SubControl ctrl = style()->hitTestComplexControl(QStyle::CC_TitleBar, &opt, | |
e->pos(), this); | |
if (d->pressed) { | |
update(); | |
d->pressed = false; | |
d->moving = false; | |
} | |
if (ctrl == d->buttonDown) { | |
d->buttonDown = QStyle::SC_None; | |
switch(ctrl) { | |
case QStyle::SC_TitleBarShadeButton: | |
case QStyle::SC_TitleBarUnshadeButton: | |
if(d->flags & Qt::WindowShadeButtonHint) | |
emit doShade(); | |
break; | |
case QStyle::SC_TitleBarNormalButton: | |
if(d->flags & Qt::WindowMinMaxButtonsHint) | |
emit doNormal(); | |
break; | |
case QStyle::SC_TitleBarMinButton: | |
if(d->flags & Qt::WindowMinimizeButtonHint) { | |
if (d->window && d->window->isMinimized()) | |
emit doNormal(); | |
else | |
emit doMinimize(); | |
} | |
break; | |
case QStyle::SC_TitleBarMaxButton: | |
if(d->flags & Qt::WindowMaximizeButtonHint) { | |
if(d->window && d->window->isMaximized()) | |
emit doNormal(); | |
else | |
emit doMaximize(); | |
} | |
break; | |
case QStyle::SC_TitleBarCloseButton: | |
if(d->flags & Qt::WindowSystemMenuHint) { | |
d->buttonDown = QStyle::SC_None; | |
emit doClose(); | |
return; | |
} | |
break; | |
default: | |
break; | |
} | |
} | |
} else { | |
e->ignore(); | |
} | |
} | |
void QWorkspaceTitleBar::mouseMoveEvent(QMouseEvent *e) | |
{ | |
Q_D(QWorkspaceTitleBar); | |
e->ignore(); | |
if ((e->buttons() & Qt::LeftButton) && style()->styleHint(QStyle::SH_TitleBar_NoBorder, 0, 0) | |
&& !rect().adjusted(5, 5, -5, 0).contains(e->pos()) && !d->pressed) { | |
// propagate border events to the QWidgetResizeHandler | |
return; | |
} | |
QStyleOptionTitleBar opt; | |
initStyleOption(&opt); | |
QStyle::SubControl under_mouse = style()->hitTestComplexControl(QStyle::CC_TitleBar, &opt, | |
e->pos(), this); | |
if(under_mouse != d->lastControl) { | |
d->lastControl = under_mouse; | |
update(); | |
} | |
switch (d->buttonDown) { | |
case QStyle::SC_None: | |
break; | |
case QStyle::SC_TitleBarSysMenu: | |
break; | |
case QStyle::SC_TitleBarLabel: | |
if (d->buttonDown == QStyle::SC_TitleBarLabel && d->movable && d->pressed) { | |
if (d->moving || (d->moveOffset - mapToParent(e->pos())).manhattanLength() >= 4) { | |
d->moving = true; | |
QPoint p = mapFromGlobal(e->globalPos()); | |
QWidget *parent = d->window ? d->window->parentWidget() : 0; | |
if(parent && parent->inherits("QWorkspaceChild")) { | |
QWidget *workspace = parent->parentWidget(); | |
p = workspace->mapFromGlobal(e->globalPos()); | |
if (!workspace->rect().contains(p)) { | |
if (p.x() < 0) | |
p.rx() = 0; | |
if (p.y() < 0) | |
p.ry() = 0; | |
if (p.x() > workspace->width()) | |
p.rx() = workspace->width(); | |
if (p.y() > workspace->height()) | |
p.ry() = workspace->height(); | |
} | |
} | |
QPoint pp = p - d->moveOffset; | |
if (!parentWidget()->isMaximized()) | |
parentWidget()->move(pp); | |
} | |
} | |
e->accept(); | |
break; | |
default: | |
break; | |
} | |
} | |
bool QWorkspaceTitleBar::isTool() const | |
{ | |
Q_D(const QWorkspaceTitleBar); | |
return (d->flags & Qt::WindowType_Mask) == Qt::Tool; | |
} | |
// from qwidget.cpp | |
extern QString qt_setWindowTitle_helperHelper(const QString &, const QWidget*); | |
void QWorkspaceTitleBar::paintEvent(QPaintEvent *) | |
{ | |
Q_D(QWorkspaceTitleBar); | |
QStyleOptionTitleBar opt; | |
initStyleOption(&opt); | |
opt.subControls = QStyle::SC_TitleBarLabel; | |
opt.activeSubControls = d->buttonDown; | |
if (d->window && (d->flags & Qt::WindowTitleHint)) { | |
QString title = qt_setWindowTitle_helperHelper(opt.text, d->window); | |
int maxw = style()->subControlRect(QStyle::CC_TitleBar, &opt, QStyle::SC_TitleBarLabel, | |
this).width(); | |
opt.text = fontMetrics().elidedText(title, Qt::ElideRight, maxw); | |
} | |
if (d->flags & Qt::WindowSystemMenuHint) { | |
opt.subControls |= QStyle::SC_TitleBarSysMenu | QStyle::SC_TitleBarCloseButton; | |
if (d->window && (d->flags & Qt::WindowShadeButtonHint)) { | |
if (d->window->isMinimized()) | |
opt.subControls |= QStyle::SC_TitleBarUnshadeButton; | |
else | |
opt.subControls |= QStyle::SC_TitleBarShadeButton; | |
} | |
if (d->window && (d->flags & Qt::WindowMinMaxButtonsHint)) { | |
if(d->window && d->window->isMinimized()) | |
opt.subControls |= QStyle::SC_TitleBarNormalButton; | |
else | |
opt.subControls |= QStyle::SC_TitleBarMinButton; | |
} | |
if (d->window && (d->flags & Qt::WindowMaximizeButtonHint) && !d->window->isMaximized()) | |
opt.subControls |= QStyle::SC_TitleBarMaxButton; | |
} | |
QStyle::SubControl under_mouse = QStyle::SC_None; | |
under_mouse = style()->hitTestComplexControl(QStyle::CC_TitleBar, &opt, | |
mapFromGlobal(QCursor::pos()), this); | |
if ((d->buttonDown == under_mouse) && d->pressed) { | |
opt.state |= QStyle::State_Sunken; | |
} else if( autoRaise() && under_mouse != QStyle::SC_None && !d->pressed) { | |
opt.activeSubControls = under_mouse; | |
opt.state |= QStyle::State_MouseOver; | |
} | |
opt.palette.setCurrentColorGroup(usesActiveColor() ? QPalette::Active : QPalette::Inactive); | |
QPainter p(this); | |
style()->drawComplexControl(QStyle::CC_TitleBar, &opt, &p, this); | |
} | |
void QWorkspaceTitleBar::mouseDoubleClickEvent(QMouseEvent *e) | |
{ | |
Q_D(QWorkspaceTitleBar); | |
if (e->button() != Qt::LeftButton) { | |
e->ignore(); | |
return; | |
} | |
e->accept(); | |
QStyleOptionTitleBar opt; | |
initStyleOption(&opt); | |
switch (style()->hitTestComplexControl(QStyle::CC_TitleBar, &opt, e->pos(), this)) { | |
case QStyle::SC_TitleBarLabel: | |
emit doubleClicked(); | |
break; | |
case QStyle::SC_TitleBarSysMenu: | |
if (d->flags & Qt::WindowSystemMenuHint) | |
emit doClose(); | |
break; | |
default: | |
break; | |
} | |
} | |
void QWorkspaceTitleBar::leaveEvent(QEvent *) | |
{ | |
Q_D(QWorkspaceTitleBar); | |
d->lastControl = QStyle::SC_None; | |
if(autoRaise() && !d->pressed) | |
update(); | |
} | |
void QWorkspaceTitleBar::enterEvent(QEvent *) | |
{ | |
Q_D(QWorkspaceTitleBar); | |
if(autoRaise() && !d->pressed) | |
update(); | |
QEvent e(QEvent::Leave); | |
QApplication::sendEvent(parentWidget(), &e); | |
} | |
void QWorkspaceTitleBar::setActive(bool active) | |
{ | |
Q_D(QWorkspaceTitleBar); | |
if (d->act == active) | |
return ; | |
d->act = active; | |
update(); | |
} | |
bool QWorkspaceTitleBar::isActive() const | |
{ | |
Q_D(const QWorkspaceTitleBar); | |
return d->act; | |
} | |
bool QWorkspaceTitleBar::usesActiveColor() const | |
{ | |
return (isActive() && isActiveWindow()) || | |
(!window() && QWidget::window()->isActiveWindow()); | |
} | |
QWidget *QWorkspaceTitleBar::window() const | |
{ | |
Q_D(const QWorkspaceTitleBar); | |
return d->window; | |
} | |
bool QWorkspaceTitleBar::event(QEvent *e) | |
{ | |
Q_D(QWorkspaceTitleBar); | |
if (e->type() == QEvent::ApplicationPaletteChange) { | |
d->readColors(); | |
} else if (e->type() == QEvent::WindowActivate | |
|| e->type() == QEvent::WindowDeactivate) { | |
if (d->act) | |
update(); | |
} | |
return QWidget::event(e); | |
} | |
void QWorkspaceTitleBar::setMovable(bool b) | |
{ | |
Q_D(QWorkspaceTitleBar); | |
d->movable = b; | |
} | |
bool QWorkspaceTitleBar::isMovable() const | |
{ | |
Q_D(const QWorkspaceTitleBar); | |
return d->movable; | |
} | |
void QWorkspaceTitleBar::setAutoRaise(bool b) | |
{ | |
Q_D(QWorkspaceTitleBar); | |
d->autoraise = b; | |
} | |
bool QWorkspaceTitleBar::autoRaise() const | |
{ | |
Q_D(const QWorkspaceTitleBar); | |
return d->autoraise; | |
} | |
QSize QWorkspaceTitleBar::sizeHint() const | |
{ | |
ensurePolished(); | |
QStyleOptionTitleBar opt; | |
initStyleOption(&opt); | |
QRect menur = style()->subControlRect(QStyle::CC_TitleBar, &opt, | |
QStyle::SC_TitleBarSysMenu, this); | |
return QSize(menur.width(), style()->pixelMetric(QStyle::PM_TitleBarHeight, &opt, this)); | |
} | |
/*! | |
\class QWorkspace | |
\obsolete | |
\brief The QWorkspace widget provides a workspace window that can be | |
used in an MDI application. | |
This class is deprecated. Use QMdiArea instead. | |
Multiple Document Interface (MDI) applications are typically | |
composed of a main window containing a menu bar, a toolbar, and | |
a central QWorkspace widget. The workspace itself is used to display | |
a number of child windows, each of which is a widget. | |
The workspace itself is an ordinary Qt widget. It has a standard | |
constructor that takes a parent widget. | |
Workspaces can be placed in any layout, but are typically given | |
as the central widget in a QMainWindow: | |
\snippet doc/src/snippets/code/src_gui_widgets_qworkspace.cpp 0 | |
Child windows (MDI windows) are standard Qt widgets that are | |
inserted into the workspace with addWindow(). As with top-level | |
widgets, you can call functions such as show(), hide(), | |
showMaximized(), and setWindowTitle() on a child window to change | |
its appearance within the workspace. You can also provide widget | |
flags to determine the layout of the decoration or the behavior of | |
the widget itself. | |
To change or retrieve the geometry of a child window, you must | |
operate on its parentWidget(). The parentWidget() provides | |
access to the decorated frame that contains the child window | |
widget. When a child window is maximised, its decorated frame | |
is hidden. If the top-level widget contains a menu bar, it will display | |
the maximised window's operations menu to the left of the menu | |
entries, and the window's controls to the right. | |
A child window becomes active when it gets the keyboard focus, | |
or when setFocus() is called. The user can activate a window by moving | |
focus in the usual ways, for example by clicking a window or by pressing | |
Tab. The workspace emits a signal windowActivated() when the active | |
window changes, and the function activeWindow() returns a pointer to the | |
active child window, or 0 if no window is active. | |
The convenience function windowList() returns a list of all child | |
windows. This information could be used in a popup menu | |
containing a list of windows, for example. This feature is also | |
available as part of the \l{Window Menu} Solution. | |
QWorkspace provides two built-in layout strategies for child | |
windows: cascade() and tile(). Both are slots so you can easily | |
connect menu entries to them. | |
\table | |
\row \o \inlineimage mdi-cascade.png | |
\o \inlineimage mdi-tile.png | |
\endtable | |
If you want your users to be able to work with child windows | |
larger than the visible workspace area, set the scrollBarsEnabled | |
property to true. | |
\sa QDockWidget, {MDI Example} | |
*/ | |
class QWorkspaceChild : public QWidget | |
{ | |
Q_OBJECT | |
friend class QWorkspacePrivate; | |
friend class QWorkspace; | |
friend class QWorkspaceTitleBar; | |
public: | |
QWorkspaceChild(QWidget* window, QWorkspace* parent=0, Qt::WindowFlags flags = 0); | |
~QWorkspaceChild(); | |
void setActive(bool); | |
bool isActive() const; | |
void adjustToFullscreen(); | |
QWidget* windowWidget() const; | |
QWidget* iconWidget() const; | |
void doResize(); | |
void doMove(); | |
QSize sizeHint() const; | |
QSize minimumSizeHint() const; | |
QSize baseSize() const; | |
int frameWidth() const; | |
void show(); | |
bool isWindowOrIconVisible() const; | |
signals: | |
void showOperationMenu(); | |
void popupOperationMenu(const QPoint&); | |
public slots: | |
void activate(); | |
void showMinimized(); | |
void showMaximized(); | |
void showNormal(); | |
void showShaded(); | |
void internalRaise(); | |
void titleBarDoubleClicked(); | |
protected: | |
void enterEvent(QEvent *); | |
void leaveEvent(QEvent *); | |
void childEvent(QChildEvent*); | |
void resizeEvent(QResizeEvent *); | |
void moveEvent(QMoveEvent *); | |
bool eventFilter(QObject *, QEvent *); | |
void paintEvent(QPaintEvent *); | |
void changeEvent(QEvent *); | |
private: | |
void updateMask(); | |
Q_DISABLE_COPY(QWorkspaceChild) | |
QWidget *childWidget; | |
QWidgetResizeHandler *widgetResizeHandler; | |
QWorkspaceTitleBar *titlebar; | |
QPointer<QWorkspaceTitleBar> iconw; | |
QSize windowSize; | |
QSize shadeRestore; | |
QSize shadeRestoreMin; | |
bool act :1; | |
bool shademode :1; | |
}; | |
int QWorkspaceChild::frameWidth() const | |
{ | |
return contentsRect().left(); | |
} | |
class QWorkspacePrivate : public QWidgetPrivate { | |
Q_DECLARE_PUBLIC(QWorkspace) | |
public: | |
QWorkspaceChild* active; | |
QList<QWorkspaceChild *> windows; | |
QList<QWorkspaceChild *> focus; | |
QList<QWidget *> icons; | |
QWorkspaceChild* maxWindow; | |
QRect maxRestore; | |
QPointer<QMDIControl> maxcontrols; | |
QPointer<QMenuBar> maxmenubar; | |
QHash<int, const char*> shortcutMap; | |
int px; | |
int py; | |
QWidget *becomeActive; | |
QPointer<QLabel> maxtools; | |
QString topTitle; | |
QMenu *popup, *toolPopup; | |
enum WSActs { RestoreAct, MoveAct, ResizeAct, MinimizeAct, MaximizeAct, CloseAct, StaysOnTopAct, ShadeAct, NCountAct }; | |
QAction *actions[NCountAct]; | |
QScrollBar *vbar, *hbar; | |
QWidget *corner; | |
int yoffset, xoffset; | |
QBrush background; | |
void init(); | |
void insertIcon(QWidget* w); | |
void removeIcon(QWidget* w); | |
void place(QWidget*); | |
QWorkspaceChild* findChild(QWidget* w); | |
void showMaximizeControls(); | |
void hideMaximizeControls(); | |
void activateWindow(QWidget* w, bool change_focus = true); | |
void hideChild(QWorkspaceChild *c); | |
void showWindow(QWidget* w); | |
void maximizeWindow(QWidget* w); | |
void minimizeWindow(QWidget* w); | |
void normalizeWindow(QWidget* w); | |
QRect updateWorkspace(); | |
private: | |
void _q_normalizeActiveWindow(); | |
void _q_minimizeActiveWindow(); | |
void _q_showOperationMenu(); | |
void _q_popupOperationMenu(const QPoint&); | |
void _q_operationMenuActivated(QAction *); | |
void _q_scrollBarChanged(); | |
void _q_updateActions(); | |
bool inTitleChange; | |
}; | |
static bool isChildOf(QWidget * child, QWidget * parent) | |
{ | |
if (!parent || !child) | |
return false; | |
QWidget * w = child; | |
while(w && w != parent) | |
w = w->parentWidget(); | |
return w != 0; | |
} | |
/*! | |
Constructs a workspace with the given \a parent. | |
*/ | |
QWorkspace::QWorkspace(QWidget *parent) | |
: QWidget(*new QWorkspacePrivate, parent, 0) | |
{ | |
Q_D(QWorkspace); | |
d->init(); | |
} | |
#ifdef QT3_SUPPORT | |
/*! | |
Use one of the constructors that doesn't take the \a name | |
argument and then use setObjectName() instead. | |
*/ | |
QWorkspace::QWorkspace(QWidget *parent, const char *name) | |
: QWidget(*new QWorkspacePrivate, parent, 0) | |
{ | |
Q_D(QWorkspace); | |
setObjectName(QString::fromAscii(name)); | |
d->init(); | |
} | |
#endif // QT3_SUPPORT | |
/*! | |
\internal | |
*/ | |
void | |
QWorkspacePrivate::init() | |
{ | |
Q_Q(QWorkspace); | |
maxcontrols = 0; | |
active = 0; | |
maxWindow = 0; | |
maxtools = 0; | |
px = 0; | |
py = 0; | |
becomeActive = 0; | |
popup = new QMenu(q); | |
toolPopup = new QMenu(q); | |
popup->setObjectName(QLatin1String("qt_internal_mdi_popup")); | |
toolPopup->setObjectName(QLatin1String("qt_internal_mdi_tool_popup")); | |
actions[QWorkspacePrivate::RestoreAct] = new QAction(QIcon(q->style()->standardPixmap(QStyle::SP_TitleBarNormalButton, 0, q)), | |
QWorkspace::tr("&Restore"), q); | |
actions[QWorkspacePrivate::MoveAct] = new QAction(QWorkspace::tr("&Move"), q); | |
actions[QWorkspacePrivate::ResizeAct] = new QAction(QWorkspace::tr("&Size"), q); | |
actions[QWorkspacePrivate::MinimizeAct] = new QAction(QIcon(q->style()->standardPixmap(QStyle::SP_TitleBarMinButton, 0, q)), | |
QWorkspace::tr("Mi&nimize"), q); | |
actions[QWorkspacePrivate::MaximizeAct] = new QAction(QIcon(q->style()->standardPixmap(QStyle::SP_TitleBarMaxButton, 0, q)), | |
QWorkspace::tr("Ma&ximize"), q); | |
actions[QWorkspacePrivate::CloseAct] = new QAction(QIcon(q->style()->standardPixmap(QStyle::SP_TitleBarCloseButton, 0, q)), | |
QWorkspace::tr("&Close") | |
#ifndef QT_NO_SHORTCUT | |
+QLatin1Char('\t')+(QString)QKeySequence(Qt::CTRL+Qt::Key_F4) | |
#endif | |
,q); | |
QObject::connect(actions[QWorkspacePrivate::CloseAct], SIGNAL(triggered()), q, SLOT(closeActiveWindow())); | |
actions[QWorkspacePrivate::StaysOnTopAct] = new QAction(QWorkspace::tr("Stay on &Top"), q); | |
actions[QWorkspacePrivate::StaysOnTopAct]->setChecked(true); | |
actions[QWorkspacePrivate::ShadeAct] = new QAction(QIcon(q->style()->standardPixmap(QStyle::SP_TitleBarShadeButton, 0, q)), | |
QWorkspace::tr("Sh&ade"), q); | |
QObject::connect(popup, SIGNAL(aboutToShow()), q, SLOT(_q_updateActions())); | |
QObject::connect(popup, SIGNAL(triggered(QAction*)), q, SLOT(_q_operationMenuActivated(QAction*))); | |
popup->addAction(actions[QWorkspacePrivate::RestoreAct]); | |
popup->addAction(actions[QWorkspacePrivate::MoveAct]); | |
popup->addAction(actions[QWorkspacePrivate::ResizeAct]); | |
popup->addAction(actions[QWorkspacePrivate::MinimizeAct]); | |
popup->addAction(actions[QWorkspacePrivate::MaximizeAct]); | |
popup->addSeparator(); | |
popup->addAction(actions[QWorkspacePrivate::CloseAct]); | |
QObject::connect(toolPopup, SIGNAL(aboutToShow()), q, SLOT(_q_updateActions())); | |
QObject::connect(toolPopup, SIGNAL(triggered(QAction*)), q, SLOT(_q_operationMenuActivated(QAction*))); | |
toolPopup->addAction(actions[QWorkspacePrivate::MoveAct]); | |
toolPopup->addAction(actions[QWorkspacePrivate::ResizeAct]); | |
toolPopup->addAction(actions[QWorkspacePrivate::StaysOnTopAct]); | |
toolPopup->addSeparator(); | |
toolPopup->addAction(actions[QWorkspacePrivate::ShadeAct]); | |
toolPopup->addAction(actions[QWorkspacePrivate::CloseAct]); | |
#ifndef QT_NO_SHORTCUT | |
// Set up shortcut bindings (id -> slot), most used first | |
QList <QKeySequence> shortcuts = QKeySequence::keyBindings(QKeySequence::NextChild); | |
foreach (const QKeySequence &seq, shortcuts) | |
shortcutMap.insert(q->grabShortcut(seq), "activateNextWindow"); | |
shortcuts = QKeySequence::keyBindings(QKeySequence::PreviousChild); | |
foreach (const QKeySequence &seq, shortcuts) | |
shortcutMap.insert(q->grabShortcut(seq), "activatePreviousWindow"); | |
shortcuts = QKeySequence::keyBindings(QKeySequence::Close); | |
foreach (const QKeySequence &seq, shortcuts) | |
shortcutMap.insert(q->grabShortcut(seq), "closeActiveWindow"); | |
shortcutMap.insert(q->grabShortcut(QKeySequence(QLatin1String("ALT+-"))), "_q_showOperationMenu"); | |
#endif // QT_NO_SHORTCUT | |
q->setBackgroundRole(QPalette::Dark); | |
q->setAutoFillBackground(true); | |
q->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding)); | |
hbar = vbar = 0; | |
corner = 0; | |
xoffset = yoffset = 0; | |
q->window()->installEventFilter(q); | |
inTitleChange = false; | |
updateWorkspace(); | |
} | |
/*! | |
Destroys the workspace and frees any allocated resources. | |
*/ | |
QWorkspace::~QWorkspace() | |
{ | |
} | |
/*! \reimp */ | |
QSize QWorkspace::sizeHint() const | |
{ | |
QSize s(QApplication::desktop()->size()); | |
return QSize(s.width()*2/3, s.height()*2/3); | |
} | |
#ifdef QT3_SUPPORT | |
/*! | |
Sets the background color to \a c. | |
Use setBackground() instead. | |
*/ | |
void QWorkspace::setPaletteBackgroundColor(const QColor & c) | |
{ | |
setBackground(c); | |
} | |
/*! | |
Sets the background pixmap to \a pm. | |
Use setBackground() instead. | |
*/ | |
void QWorkspace::setPaletteBackgroundPixmap(const QPixmap & pm) | |
{ | |
setBackground(pm); | |
} | |
#endif // QT3_SUPPORT | |
/*! | |
\property QWorkspace::background | |
\brief the workspace's background | |
*/ | |
QBrush QWorkspace::background() const | |
{ | |
Q_D(const QWorkspace); | |
if (d->background.style() == Qt::NoBrush) | |
return palette().dark(); | |
return d->background; | |
} | |
void QWorkspace::setBackground(const QBrush &background) | |
{ | |
Q_D(QWorkspace); | |
d->background = background; | |
setAttribute(Qt::WA_OpaquePaintEvent, background.style() == Qt::NoBrush); | |
update(); | |
} | |
/*! | |
Adds widget \a w as new sub window to the workspace. If \a flags | |
are non-zero, they will override the flags set on the widget. | |
Returns the widget used for the window frame. | |
To remove the widget \a w from the workspace, simply call | |
setParent() with the new parent (or 0 to make it a stand-alone | |
window). | |
*/ | |
QWidget * QWorkspace::addWindow(QWidget *w, Qt::WindowFlags flags) | |
{ | |
Q_D(QWorkspace); | |
if (!w) | |
return 0; | |
w->setAutoFillBackground(true); | |
QWidgetPrivate::adjustFlags(flags); | |
#if 0 | |
bool wasMaximized = w->isMaximized(); | |
bool wasMinimized = w->isMinimized(); | |
#endif | |
bool hasSize = w->testAttribute(Qt::WA_Resized); | |
int x = w->x(); | |
int y = w->y(); | |
bool hasPos = w->testAttribute(Qt::WA_Moved); | |
QSize s = w->size().expandedTo(qSmartMinSize(w)); | |
if (!hasSize && w->sizeHint().isValid()) | |
w->adjustSize(); | |
QWorkspaceChild* child = new QWorkspaceChild(w, this, flags); | |
child->setObjectName(QLatin1String("qt_workspacechild")); | |
child->installEventFilter(this); | |
connect(child, SIGNAL(popupOperationMenu(QPoint)), | |
this, SLOT(_q_popupOperationMenu(QPoint))); | |
connect(child, SIGNAL(showOperationMenu()), | |
this, SLOT(_q_showOperationMenu())); | |
d->windows.append(child); | |
if (child->isVisibleTo(this)) | |
d->focus.append(child); | |
child->internalRaise(); | |
if (!hasPos) | |
d->place(child); | |
if (!hasSize) | |
child->adjustSize(); | |
if (hasPos) | |
child->move(x, y); | |
return child; | |
#if 0 | |
if (wasMaximized) | |
w->showMaximized(); | |
else if (wasMinimized) | |
w->showMinimized(); | |
else if (!hasBeenHidden) | |
d->activateWindow(w); | |
d->updateWorkspace(); | |
return child; | |
#endif | |
} | |
/*! \reimp */ | |
void QWorkspace::childEvent(QChildEvent * e) | |
{ | |
Q_D(QWorkspace); | |
if (e->removed()) { | |
if (d->windows.removeAll(static_cast<QWorkspaceChild*>(e->child()))) { | |
d->focus.removeAll(static_cast<QWorkspaceChild*>(e->child())); | |
if (d->maxWindow == e->child()) | |
d->maxWindow = 0; | |
d->updateWorkspace(); | |
} | |
} | |
} | |
/*! \reimp */ | |
#ifndef QT_NO_WHEELEVENT | |
void QWorkspace::wheelEvent(QWheelEvent *e) | |
{ | |
Q_D(QWorkspace); | |
if (!scrollBarsEnabled()) | |
return; | |
// the scroll bars are children of the workspace, so if we receive | |
// a wheel event we redirect to the scroll bars using a direct event | |
// call, /not/ using sendEvent() because if the scroll bar ignores the | |
// event QApplication::sendEvent() will propagate the event to the parent widget, | |
// which is us, who /just/ sent it. | |
if (d->vbar && d->vbar->isVisible() && !(e->modifiers() & Qt::AltModifier)) | |
d->vbar->event(e); | |
else if (d->hbar && d->hbar->isVisible()) | |
d->hbar->event(e); | |
} | |
#endif | |
void QWorkspacePrivate::activateWindow(QWidget* w, bool change_focus) | |
{ | |
Q_Q(QWorkspace); | |
if (!w) { | |
active = 0; | |
emit q->windowActivated(0); | |
return; | |
} | |
if (!q->isVisible()) { | |
becomeActive = w; | |
return; | |
} | |
if (active && active->windowWidget() == w) { | |
if (!isChildOf(q->focusWidget(), w)) // child window does not have focus | |
active->setActive(true); | |
return; | |
} | |
active = 0; | |
// First deactivate all other workspace clients | |
QList<QWorkspaceChild *>::Iterator it(windows.begin()); | |
while (it != windows.end()) { | |
QWorkspaceChild* c = *it; | |
++it; | |
if (c->windowWidget() == w) | |
active = c; | |
else | |
c->setActive(false); | |
} | |
if (!active) | |
return; | |
// Then activate the new one, so the focus is stored correctly | |
active->setActive(true); | |
if (!active) | |
return; | |
if (maxWindow && maxWindow != active && active->windowWidget() && | |
(active->windowWidget()->windowFlags() & Qt::WindowMaximizeButtonHint)) | |
active->showMaximized(); | |
active->internalRaise(); | |
if (change_focus) { | |
int from = focus.indexOf(active); | |
if (from >= 0) | |
focus.move(from, focus.size() - 1); | |
} | |
updateWorkspace(); | |
emit q->windowActivated(w); | |
} | |
/*! | |
Returns a pointer to the widget corresponding to the active child | |
window, or 0 if no window is active. | |
\sa setActiveWindow() | |
*/ | |
QWidget* QWorkspace::activeWindow() const | |
{ | |
Q_D(const QWorkspace); | |
return d->active? d->active->windowWidget() : 0; | |
} | |
/*! | |
Makes the child window that contains \a w the active child window. | |
\sa activeWindow() | |
*/ | |
void QWorkspace::setActiveWindow(QWidget *w) | |
{ | |
Q_D(QWorkspace); | |
d->activateWindow(w, true); | |
if (w && w->isMinimized()) | |
w->setWindowState(w->windowState() & ~Qt::WindowMinimized); | |
} | |
void QWorkspacePrivate::place(QWidget *w) | |
{ | |
Q_Q(QWorkspace); | |
QList<QWidget *> widgets; | |
for (QList<QWorkspaceChild *>::Iterator it(windows.begin()); it != windows.end(); ++it) | |
if (*it != w) | |
widgets.append(*it); | |
int overlap, minOverlap = 0; | |
int possible; | |
QRect r1(0, 0, 0, 0); | |
QRect r2(0, 0, 0, 0); | |
QRect maxRect = q->rect(); | |
int x = maxRect.left(), y = maxRect.top(); | |
QPoint wpos(maxRect.left(), maxRect.top()); | |
bool firstPass = true; | |
do { | |
if (y + w->height() > maxRect.bottom()) { | |
overlap = -1; | |
} else if(x + w->width() > maxRect.right()) { | |
overlap = -2; | |
} else { | |
overlap = 0; | |
r1.setRect(x, y, w->width(), w->height()); | |
QWidget *l; | |
QList<QWidget *>::Iterator it(widgets.begin()); | |
while (it != widgets.end()) { | |
l = *it; | |
++it; | |
if (maxWindow == l) | |
r2 = QStyle::visualRect(q->layoutDirection(), maxRect, maxRestore); | |
else | |
r2 = QStyle::visualRect(q->layoutDirection(), maxRect, | |
QRect(l->x(), l->y(), l->width(), l->height())); | |
if (r2.intersects(r1)) { | |
r2.setCoords(qMax(r1.left(), r2.left()), | |
qMax(r1.top(), r2.top()), | |
qMin(r1.right(), r2.right()), | |
qMin(r1.bottom(), r2.bottom()) | |
); | |
overlap += (r2.right() - r2.left()) * | |
(r2.bottom() - r2.top()); | |
} | |
} | |
} | |
if (overlap == 0) { | |
wpos = QPoint(x, y); | |
break; | |
} | |
if (firstPass) { | |
firstPass = false; | |
minOverlap = overlap; | |
} else if (overlap >= 0 && overlap < minOverlap) { | |
minOverlap = overlap; | |
wpos = QPoint(x, y); | |
} | |
if (overlap > 0) { | |
possible = maxRect.right(); | |
if (possible - w->width() > x) possible -= w->width(); | |
QWidget *l; | |
QList<QWidget *>::Iterator it(widgets.begin()); | |
while (it != widgets.end()) { | |
l = *it; | |
++it; | |
if (maxWindow == l) | |
r2 = QStyle::visualRect(q->layoutDirection(), maxRect, maxRestore); | |
else | |
r2 = QStyle::visualRect(q->layoutDirection(), maxRect, | |
QRect(l->x(), l->y(), l->width(), l->height())); | |
if((y < r2.bottom()) && (r2.top() < w->height() + y)) { | |
if(r2.right() > x) | |
possible = possible < r2.right() ? | |
possible : r2.right(); | |
if(r2.left() - w->width() > x) | |
possible = possible < r2.left() - w->width() ? | |
possible : r2.left() - w->width(); | |
} | |
} | |
x = possible; | |
} else if (overlap == -2) { | |
x = maxRect.left(); | |
possible = maxRect.bottom(); | |
if (possible - w->height() > y) possible -= w->height(); | |
QWidget *l; | |
QList<QWidget *>::Iterator it(widgets.begin()); | |
while (it != widgets.end()) { | |
l = *it; | |
++it; | |
if (maxWindow == l) | |
r2 = QStyle::visualRect(q->layoutDirection(), maxRect, maxRestore); | |
else | |
r2 = QStyle::visualRect(q->layoutDirection(), maxRect, | |
QRect(l->x(), l->y(), l->width(), l->height())); | |
if(r2.bottom() > y) | |
possible = possible < r2.bottom() ? | |
possible : r2.bottom(); | |
if(r2.top() - w->height() > y) | |
possible = possible < r2.top() - w->height() ? | |
possible : r2.top() - w->height(); | |
} | |
y = possible; | |
} | |
} | |
while(overlap != 0 && overlap != -1); | |
QRect resultRect = w->geometry(); | |
resultRect.moveTo(wpos); | |
w->setGeometry(QStyle::visualRect(q->layoutDirection(), maxRect, resultRect)); | |
updateWorkspace(); | |
} | |
void QWorkspacePrivate::insertIcon(QWidget* w) | |
{ | |
Q_Q(QWorkspace); | |
if (!w || icons.contains(w)) | |
return; | |
icons.append(w); | |
if (w->parentWidget() != q) { | |
w->setParent(q, 0); | |
w->move(0,0); | |
} | |
QRect cr = updateWorkspace(); | |
int x = 0; | |
int y = cr.height() - w->height(); | |
QList<QWidget *>::Iterator it(icons.begin()); | |
while (it != icons.end()) { | |
QWidget* i = *it; | |
++it; | |
if (x > 0 && x + i->width() > cr.width()){ | |
x = 0; | |
y -= i->height(); | |
} | |
if (i != w && | |
i->geometry().intersects(QRect(x, y, w->width(), w->height()))) | |
x += i->width(); | |
} | |
w->move(x, y); | |
if (q->isVisibleTo(q->parentWidget())) { | |
w->show(); | |
w->lower(); | |
} | |
updateWorkspace(); | |
} | |
void QWorkspacePrivate::removeIcon(QWidget* w) | |
{ | |
if (icons.removeAll(w)) | |
w->hide(); | |
} | |
/*! \reimp */ | |
void QWorkspace::resizeEvent(QResizeEvent *) | |
{ | |
Q_D(QWorkspace); | |
if (d->maxWindow) { | |
d->maxWindow->adjustToFullscreen(); | |
if (d->maxWindow->windowWidget()) | |
d->maxWindow->windowWidget()->overrideWindowState(Qt::WindowMaximized); | |
} | |
d->updateWorkspace(); | |
} | |
/*! \reimp */ | |
void QWorkspace::showEvent(QShowEvent *e) | |
{ | |
Q_D(QWorkspace); | |
if (d->maxWindow) | |
d->showMaximizeControls(); | |
QWidget::showEvent(e); | |
if (d->becomeActive) { | |
d->activateWindow(d->becomeActive); | |
d->becomeActive = 0; | |
} else if (d->windows.count() > 0 && !d->active) { | |
d->activateWindow(d->windows.first()->windowWidget()); | |
} | |
// // force a frame repaint - this is a workaround for what seems to be a bug | |
// // introduced when changing the QWidget::show() implementation. Might be | |
// // a windows bug as well though. | |
// for (int i = 0; i < d->windows.count(); ++i) { | |
// QWorkspaceChild* c = d->windows.at(i); | |
// c->update(c->rect()); | |
// } | |
d->updateWorkspace(); | |
} | |
/*! \reimp */ | |
void QWorkspace::hideEvent(QHideEvent *) | |
{ | |
Q_D(QWorkspace); | |
if (!isVisible()) | |
d->hideMaximizeControls(); | |
} | |
/*! \reimp */ | |
void QWorkspace::paintEvent(QPaintEvent *) | |
{ | |
Q_D(QWorkspace); | |
if (d->background.style() != Qt::NoBrush) { | |
QPainter p(this); | |
p.fillRect(0, 0, width(), height(), d->background); | |
} | |
} | |
void QWorkspacePrivate::minimizeWindow(QWidget* w) | |
{ | |
QWorkspaceChild* c = findChild(w); | |
if (!w || !(w->windowFlags() & Qt::WindowMinimizeButtonHint)) | |
return; | |
if (c) { | |
bool wasMax = false; | |
if (c == maxWindow) { | |
wasMax = true; | |
maxWindow = 0; | |
hideMaximizeControls(); | |
for (QList<QWorkspaceChild *>::Iterator it(windows.begin()); it != windows.end(); ++it) { | |
QWorkspaceChild* c = *it; | |
if (c->titlebar) | |
c->titlebar->setMovable(true); | |
c->widgetResizeHandler->setActive(true); | |
} | |
} | |
c->hide(); | |
if (wasMax) | |
c->setGeometry(maxRestore); | |
if (!focus.contains(c)) | |
focus.append(c); | |
insertIcon(c->iconWidget()); | |
if (!maxWindow) | |
activateWindow(w); | |
updateWorkspace(); | |
w->overrideWindowState(Qt::WindowMinimized); | |
c->overrideWindowState(Qt::WindowMinimized); | |
} | |
} | |
void QWorkspacePrivate::normalizeWindow(QWidget* w) | |
{ | |
Q_Q(QWorkspace); | |
QWorkspaceChild* c = findChild(w); | |
if (!w) | |
return; | |
if (c) { | |
w->overrideWindowState(Qt::WindowNoState); | |
hideMaximizeControls(); | |
if (!maxmenubar || q->style()->styleHint(QStyle::SH_Workspace_FillSpaceOnMaximize, 0, q) || !maxWindow) { | |
if (w->minimumSize() != w->maximumSize()) | |
c->widgetResizeHandler->setActive(true); | |
if (c->titlebar) | |
c->titlebar->setMovable(true); | |
} | |
w->overrideWindowState(Qt::WindowNoState); | |
c->overrideWindowState(Qt::WindowNoState); | |
if (c == maxWindow) { | |
c->setGeometry(maxRestore); | |
maxWindow = 0; | |
} else { | |
if (c->iconw) | |
removeIcon(c->iconw->parentWidget()); | |
c->show(); | |
} | |
hideMaximizeControls(); | |
for (QList<QWorkspaceChild *>::Iterator it(windows.begin()); it != windows.end(); ++it) { | |
QWorkspaceChild* c = *it; | |
if (c->titlebar) | |
c->titlebar->setMovable(true); | |
if (c->childWidget && c->childWidget->minimumSize() != c->childWidget->maximumSize()) | |
c->widgetResizeHandler->setActive(true); | |
} | |
activateWindow(w, true); | |
updateWorkspace(); | |
} | |
} | |
void QWorkspacePrivate::maximizeWindow(QWidget* w) | |
{ | |
Q_Q(QWorkspace); | |
QWorkspaceChild* c = findChild(w); | |
if (!w || !(w->windowFlags() & Qt::WindowMaximizeButtonHint)) | |
return; | |
if (!c || c == maxWindow) | |
return; | |
bool updatesEnabled = q->updatesEnabled(); | |
q->setUpdatesEnabled(false); | |
if (c->iconw && icons.contains(c->iconw->parentWidget())) | |
normalizeWindow(w); | |
QRect r(c->geometry()); | |
QWorkspaceChild *oldMaxWindow = maxWindow; | |
maxWindow = c; | |
showMaximizeControls(); | |
c->adjustToFullscreen(); | |
c->show(); | |
c->internalRaise(); | |
if (oldMaxWindow != c) { | |
if (oldMaxWindow) { | |
oldMaxWindow->setGeometry(maxRestore); | |
oldMaxWindow->overrideWindowState(Qt::WindowNoState); | |
if(oldMaxWindow->windowWidget()) | |
oldMaxWindow->windowWidget()->overrideWindowState(Qt::WindowNoState); | |
} | |
maxRestore = r; | |
} | |
activateWindow(w); | |
if(!maxmenubar || q->style()->styleHint(QStyle::SH_Workspace_FillSpaceOnMaximize, 0, q)) { | |
if (!active && becomeActive) { | |
active = (QWorkspaceChild*)becomeActive->parentWidget(); | |
active->setActive(true); | |
becomeActive = 0; | |
emit q->windowActivated(active->windowWidget()); | |
} | |
c->widgetResizeHandler->setActive(false); | |
if (c->titlebar) | |
c->titlebar->setMovable(false); | |
} | |
updateWorkspace(); | |
w->overrideWindowState(Qt::WindowMaximized); | |
c->overrideWindowState(Qt::WindowMaximized); | |
q->setUpdatesEnabled(updatesEnabled); | |
} | |
void QWorkspacePrivate::showWindow(QWidget* w) | |
{ | |
if (w->isMinimized() && (w->windowFlags() & Qt::WindowMinimizeButtonHint)) | |
minimizeWindow(w); | |
else if ((maxWindow || w->isMaximized()) && w->windowFlags() & Qt::WindowMaximizeButtonHint) | |
maximizeWindow(w); | |
else if (w->windowFlags() & Qt::WindowMaximizeButtonHint) | |
normalizeWindow(w); | |
else | |
w->parentWidget()->show(); | |
if (maxWindow) | |
maxWindow->internalRaise(); | |
updateWorkspace(); | |
} | |
QWorkspaceChild* QWorkspacePrivate::findChild(QWidget* w) | |
{ | |
QList<QWorkspaceChild *>::Iterator it(windows.begin()); | |
while (it != windows.end()) { | |
QWorkspaceChild* c = *it; | |
++it; | |
if (c->windowWidget() == w) | |
return c; | |
} | |
return 0; | |
} | |
/*! | |
Returns a list of all visible or minimized child windows. If \a | |
order is CreationOrder (the default), the windows are listed in | |
the order in which they were inserted into the workspace. If \a | |
order is StackingOrder, the windows are listed in their stacking | |
order, with the topmost window as the last item in the list. | |
*/ | |
QWidgetList QWorkspace::windowList(WindowOrder order) const | |
{ | |
Q_D(const QWorkspace); | |
QWidgetList windows; | |
if (order == StackingOrder) { | |
QObjectList cl = children(); | |
for (int i = 0; i < cl.size(); ++i) { | |
QWorkspaceChild *c = qobject_cast<QWorkspaceChild*>(cl.at(i)); | |
if (c && c->isWindowOrIconVisible()) | |
windows.append(c->windowWidget()); | |
} | |
} else { | |
QList<QWorkspaceChild *>::ConstIterator it(d->windows.begin()); | |
while (it != d->windows.end()) { | |
QWorkspaceChild* c = *it; | |
++it; | |
if (c && c->isWindowOrIconVisible()) | |
windows.append(c->windowWidget()); | |
} | |
} | |
return windows; | |
} | |
/*! \reimp */ | |
bool QWorkspace::event(QEvent *e) | |
{ | |
#ifndef QT_NO_SHORTCUT | |
Q_D(QWorkspace); | |
if (e->type() == QEvent::Shortcut) { | |
QShortcutEvent *se = static_cast<QShortcutEvent *>(e); | |
const char *theSlot = d->shortcutMap.value(se->shortcutId(), 0); | |
if (theSlot) | |
QMetaObject::invokeMethod(this, theSlot); | |
} else | |
#endif | |
if (e->type() == QEvent::FocusIn || e->type() == QEvent::FocusOut){ | |
return true; | |
} | |
return QWidget::event(e); | |
} | |
/*! \reimp */ | |
bool QWorkspace::eventFilter(QObject *o, QEvent * e) | |
{ | |
Q_D(QWorkspace); | |
static QElapsedTimer* t = 0; | |
static QWorkspace* tc = 0; | |
if (o == d->maxtools) { | |
switch (e->type()) { | |
case QEvent::MouseButtonPress: | |
{ | |
QMenuBar* b = (QMenuBar*)o->parent(); | |
if (!t) | |
t = new QElapsedTimer; | |
if (tc != this || t->elapsed() > QApplication::doubleClickInterval()) { | |
if (isRightToLeft()) { | |
QPoint p = b->mapToGlobal(QPoint(b->x() + b->width(), b->y() + b->height())); | |
p.rx() -= d->popup->sizeHint().width(); | |
d->_q_popupOperationMenu(p); | |
} else { | |
d->_q_popupOperationMenu(b->mapToGlobal(QPoint(b->x(), b->y() + b->height()))); | |
} | |
t->start(); | |
tc = this; | |
} else { | |
tc = 0; | |
closeActiveWindow(); | |
} | |
return true; | |
} | |
default: | |
break; | |
} | |
return QWidget::eventFilter(o, e); | |
} | |
switch (e->type()) { | |
case QEvent::HideToParent: | |
break; | |
case QEvent::ShowToParent: | |
if (QWorkspaceChild *c = qobject_cast<QWorkspaceChild*>(o)) | |
if (!d->focus.contains(c)) | |
d->focus.append(c); | |
d->updateWorkspace(); | |
break; | |
case QEvent::WindowTitleChange: | |
if (!d->inTitleChange) { | |
if (o == window()) | |
d->topTitle = window()->windowTitle(); | |
if (d->maxWindow && d->maxWindow->windowWidget() && d->topTitle.size()) { | |
d->inTitleChange = true; | |
window()->setWindowTitle(tr("%1 - [%2]") | |
.arg(d->topTitle).arg(d->maxWindow->windowWidget()->windowTitle())); | |
d->inTitleChange = false; | |
} | |
} | |
break; | |
case QEvent::ModifiedChange: | |
if (o == d->maxWindow) | |
window()->setWindowModified(d->maxWindow->isWindowModified()); | |
break; | |
case QEvent::Close: | |
if (o == window()) | |
{ | |
QList<QWorkspaceChild *>::Iterator it(d->windows.begin()); | |
while (it != d->windows.end()) { | |
QWorkspaceChild* c = *it; | |
++it; | |
if (c->shademode) | |
c->showShaded(); | |
} | |
} else if (qobject_cast<QWorkspaceChild*>(o)) { | |
d->popup->hide(); | |
} | |
d->updateWorkspace(); | |
break; | |
default: | |
break; | |
} | |
return QWidget::eventFilter(o, e); | |
} | |
static QMenuBar *findMenuBar(QWidget *w) | |
{ | |
// don't search recursively to avoid finding a menu bar of a | |
// mainwindow that happens to be a workspace window (like | |
// a mainwindow in designer) | |
QList<QObject *> children = w->children(); | |
for (int i = 0; i < children.count(); ++i) { | |
QMenuBar *bar = qobject_cast<QMenuBar *>(children.at(i)); | |
if (bar) | |
return bar; | |
} | |
return 0; | |
} | |
void QWorkspacePrivate::showMaximizeControls() | |
{ | |
Q_Q(QWorkspace); | |
Q_ASSERT(maxWindow); | |
// merge windowtitle and modified state | |
if (!topTitle.size()) | |
topTitle = q->window()->windowTitle(); | |
if (maxWindow->windowWidget()) { | |
QString docTitle = maxWindow->windowWidget()->windowTitle(); | |
if (topTitle.size() && docTitle.size()) { | |
inTitleChange = true; | |
q->window()->setWindowTitle(QWorkspace::tr("%1 - [%2]").arg(topTitle).arg(docTitle)); | |
inTitleChange = false; | |
} | |
q->window()->setWindowModified(maxWindow->windowWidget()->isWindowModified()); | |
} | |
if (!q->style()->styleHint(QStyle::SH_Workspace_FillSpaceOnMaximize, 0, q)) { | |
QMenuBar* b = 0; | |
// Do a breadth-first search first on every parent, | |
QWidget* w = q->parentWidget(); | |
while (w) { | |
b = findMenuBar(w); | |
if (b) | |
break; | |
w = w->parentWidget(); | |
} | |
// last attempt. | |
if (!b) | |
b = findMenuBar(q->window()); | |
if (!b) | |
return; | |
if (!maxcontrols) { | |
maxmenubar = b; | |
maxcontrols = new QMDIControl(b); | |
QObject::connect(maxcontrols, SIGNAL(_q_minimize()), | |
q, SLOT(_q_minimizeActiveWindow())); | |
QObject::connect(maxcontrols, SIGNAL(_q_restore()), | |
q, SLOT(_q_normalizeActiveWindow())); | |
QObject::connect(maxcontrols, SIGNAL(_q_close()), | |
q, SLOT(closeActiveWindow())); | |
} | |
b->setCornerWidget(maxcontrols); | |
if (b->isVisible()) | |
maxcontrols->show(); | |
if (!active && becomeActive) { | |
active = (QWorkspaceChild*)becomeActive->parentWidget(); | |
active->setActive(true); | |
becomeActive = 0; | |
emit q->windowActivated(active->windowWidget()); | |
} | |
if (active) { | |
if (!maxtools) { | |
maxtools = new QLabel(q->window()); | |
maxtools->setObjectName(QLatin1String("qt_maxtools")); | |
maxtools->installEventFilter(q); | |
} | |
if (active->windowWidget() && !active->windowWidget()->windowIcon().isNull()) { | |
QIcon icon = active->windowWidget()->windowIcon(); | |
int iconSize = maxcontrols->size().height(); | |
maxtools->setPixmap(icon.pixmap(QSize(iconSize, iconSize))); | |
} else { | |
QPixmap pm = q->style()->standardPixmap(QStyle::SP_TitleBarMenuButton, 0, q); | |
if (pm.isNull()) { | |
pm = QPixmap(14,14); | |
pm.fill(Qt::black); | |
} | |
maxtools->setPixmap(pm); | |
} | |
b->setCornerWidget(maxtools, Qt::TopLeftCorner); | |
if (b->isVisible()) | |
maxtools->show(); | |
} | |
} | |
} | |
void QWorkspacePrivate::hideMaximizeControls() | |
{ | |
Q_Q(QWorkspace); | |
if (maxmenubar && !q->style()->styleHint(QStyle::SH_Workspace_FillSpaceOnMaximize, 0, q)) { | |
if (maxmenubar) { | |
maxmenubar->setCornerWidget(0, Qt::TopLeftCorner); | |
maxmenubar->setCornerWidget(0, Qt::TopRightCorner); | |
} | |
if (maxcontrols) { | |
maxcontrols->deleteLater(); | |
maxcontrols = 0; | |
} | |
if (maxtools) { | |
maxtools->deleteLater(); | |
maxtools = 0; | |
} | |
} | |
//unmerge the title bar/modification state | |
if (topTitle.size()) { | |
inTitleChange = true; | |
q->window()->setWindowTitle(topTitle); | |
inTitleChange = false; | |
} | |
q->window()->setWindowModified(false); | |
} | |
/*! | |
Closes the child window that is currently active. | |
\sa closeAllWindows() | |
*/ | |
void QWorkspace::closeActiveWindow() | |
{ | |
Q_D(QWorkspace); | |
if (d->maxWindow && d->maxWindow->windowWidget()) | |
d->maxWindow->windowWidget()->close(); | |
else if (d->active && d->active->windowWidget()) | |
d->active->windowWidget()->close(); | |
d->updateWorkspace(); | |
} | |
/*! | |
Closes all child windows. | |
If any child window fails to accept the close event, the remaining windows | |
will remain open. | |
\sa closeActiveWindow() | |
*/ | |
void QWorkspace::closeAllWindows() | |
{ | |
Q_D(QWorkspace); | |
bool did_close = true; | |
QList<QWorkspaceChild *>::const_iterator it = d->windows.constBegin(); | |
while (it != d->windows.constEnd() && did_close) { | |
QWorkspaceChild *c = *it; | |
++it; | |
if (c->windowWidget() && !c->windowWidget()->isHidden()) | |
did_close = c->windowWidget()->close(); | |
} | |
} | |
void QWorkspacePrivate::_q_normalizeActiveWindow() | |
{ | |
if (maxWindow) | |
maxWindow->showNormal(); | |
else if (active) | |
active->showNormal(); | |
} | |
void QWorkspacePrivate::_q_minimizeActiveWindow() | |
{ | |
if (maxWindow) | |
maxWindow->showMinimized(); | |
else if (active) | |
active->showMinimized(); | |
} | |
void QWorkspacePrivate::_q_showOperationMenu() | |
{ | |
Q_Q(QWorkspace); | |
if (!active || !active->windowWidget()) | |
return; | |
Q_ASSERT((active->windowWidget()->windowFlags() & Qt::WindowSystemMenuHint)); | |
QPoint p; | |
QMenu *popup = (active->titlebar && active->titlebar->isTool()) ? toolPopup : this->popup; | |
if (q->isRightToLeft()) { | |
p = QPoint(active->windowWidget()->mapToGlobal(QPoint(active->windowWidget()->width(),0))); | |
p.rx() -= popup->sizeHint().width(); | |
} else { | |
p = QPoint(active->windowWidget()->mapToGlobal(QPoint(0,0))); | |
} | |
if (!active->isVisible()) { | |
p = active->iconWidget()->mapToGlobal(QPoint(0,0)); | |
p.ry() -= popup->sizeHint().height(); | |
} | |
_q_popupOperationMenu(p); | |
} | |
void QWorkspacePrivate::_q_popupOperationMenu(const QPoint& p) | |
{ | |
if (!active || !active->windowWidget() || !(active->windowWidget()->windowFlags() & Qt::WindowSystemMenuHint)) | |
return; | |
if (active->titlebar && active->titlebar->isTool()) | |
toolPopup->popup(p); | |
else | |
popup->popup(p); | |
} | |
void QWorkspacePrivate::_q_updateActions() | |
{ | |
Q_Q(QWorkspace); | |
for (int i = 1; i < NCountAct-1; i++) { | |
bool enable = active != 0; | |
actions[i]->setEnabled(enable); | |
} | |
if (!active || !active->windowWidget()) | |
return; | |
QWidget *windowWidget = active->windowWidget(); | |
bool canResize = windowWidget->maximumSize() != windowWidget->minimumSize(); | |
actions[QWorkspacePrivate::ResizeAct]->setEnabled(canResize); | |
actions[QWorkspacePrivate::MinimizeAct]->setEnabled((windowWidget->windowFlags() & Qt::WindowMinimizeButtonHint)); | |
actions[QWorkspacePrivate::MaximizeAct]->setEnabled((windowWidget->windowFlags() & Qt::WindowMaximizeButtonHint) && canResize); | |
if (active == maxWindow) { | |
actions[QWorkspacePrivate::MoveAct]->setEnabled(false); | |
actions[QWorkspacePrivate::ResizeAct]->setEnabled(false); | |
actions[QWorkspacePrivate::MaximizeAct]->setEnabled(false); | |
actions[QWorkspacePrivate::RestoreAct]->setEnabled(true); | |
} else if (active->isVisible()){ | |
actions[QWorkspacePrivate::RestoreAct]->setEnabled(false); | |
} else { | |
actions[QWorkspacePrivate::MoveAct]->setEnabled(false); | |
actions[QWorkspacePrivate::ResizeAct]->setEnabled(false); | |
actions[QWorkspacePrivate::MinimizeAct]->setEnabled(false); | |
actions[QWorkspacePrivate::RestoreAct]->setEnabled(true); | |
} | |
if (active->shademode) { | |
actions[QWorkspacePrivate::ShadeAct]->setIcon( | |
QIcon(q->style()->standardPixmap(QStyle::SP_TitleBarUnshadeButton, 0, q))); | |
actions[QWorkspacePrivate::ShadeAct]->setText(QWorkspace::tr("&Unshade")); | |
} else { | |
actions[QWorkspacePrivate::ShadeAct]->setIcon( | |
QIcon(q->style()->standardPixmap(QStyle::SP_TitleBarShadeButton, 0, q))); | |
actions[QWorkspacePrivate::ShadeAct]->setText(QWorkspace::tr("Sh&ade")); | |
} | |
actions[QWorkspacePrivate::StaysOnTopAct]->setEnabled(!active->shademode && canResize); | |
actions[QWorkspacePrivate::StaysOnTopAct]->setChecked( | |
(active->windowWidget()->windowFlags() & Qt::WindowStaysOnTopHint)); | |
} | |
void QWorkspacePrivate::_q_operationMenuActivated(QAction *action) | |
{ | |
if (!active) | |
return; | |
if(action == actions[QWorkspacePrivate::RestoreAct]) { | |
active->showNormal(); | |
} else if(action == actions[QWorkspacePrivate::MoveAct]) { | |
active->doMove(); | |
} else if(action == actions[QWorkspacePrivate::ResizeAct]) { | |
if (active->shademode) | |
active->showShaded(); | |
active->doResize(); | |
} else if(action == actions[QWorkspacePrivate::MinimizeAct]) { | |
active->showMinimized(); | |
} else if(action == actions[QWorkspacePrivate::MaximizeAct]) { | |
active->showMaximized(); | |
} else if(action == actions[QWorkspacePrivate::ShadeAct]) { | |
active->showShaded(); | |
} else if(action == actions[QWorkspacePrivate::StaysOnTopAct]) { | |
if(QWidget* w = active->windowWidget()) { | |
if ((w->windowFlags() & Qt::WindowStaysOnTopHint)) { | |
w->overrideWindowFlags(w->windowFlags() & ~Qt::WindowStaysOnTopHint); | |
} else { | |
w->overrideWindowFlags(w->windowFlags() | Qt::WindowStaysOnTopHint); | |
w->parentWidget()->raise(); | |
} | |
} | |
} | |
} | |
void QWorkspacePrivate::hideChild(QWorkspaceChild *c) | |
{ | |
Q_Q(QWorkspace); | |
// bool updatesEnabled = q->updatesEnabled(); | |
// q->setUpdatesEnabled(false); | |
focus.removeAll(c); | |
QRect restore; | |
if (maxWindow == c) | |
restore = maxRestore; | |
if (active == c) { | |
q->setFocus(); | |
q->activatePreviousWindow(); | |
} | |
if (active == c) | |
activateWindow(0); | |
if (maxWindow == c) { | |
hideMaximizeControls(); | |
maxWindow = 0; | |
} | |
c->hide(); | |
if (!restore.isEmpty()) | |
c->setGeometry(restore); | |
// q->setUpdatesEnabled(updatesEnabled); | |
} | |
/*! | |
Gives the input focus to the next window in the list of child | |
windows. | |
\sa activatePreviousWindow() | |
*/ | |
void QWorkspace::activateNextWindow() | |
{ | |
Q_D(QWorkspace); | |
if (d->focus.isEmpty()) | |
return; | |
if (!d->active) { | |
if (d->focus.first()) | |
d->activateWindow(d->focus.first()->windowWidget(), false); | |
return; | |
} | |
int a = d->focus.indexOf(d->active) + 1; | |
a = a % d->focus.count(); | |
if (d->focus.at(a)) | |
d->activateWindow(d->focus.at(a)->windowWidget(), false); | |
else | |
d->activateWindow(0); | |
} | |
/*! | |
Gives the input focus to the previous window in the list of child | |
windows. | |
\sa activateNextWindow() | |
*/ | |
void QWorkspace::activatePreviousWindow() | |
{ | |
Q_D(QWorkspace); | |
if (d->focus.isEmpty()) | |
return; | |
if (!d->active) { | |
if (d->focus.last()) | |
d->activateWindow(d->focus.first()->windowWidget(), false); | |
else | |
d->activateWindow(0); | |
return; | |
} | |
int a = d->focus.indexOf(d->active) - 1; | |
if (a < 0) | |
a = d->focus.count()-1; | |
if (d->focus.at(a)) | |
d->activateWindow(d->focus.at(a)->windowWidget(), false); | |
else | |
d->activateWindow(0); | |
} | |
/*! | |
\fn void QWorkspace::windowActivated(QWidget* w) | |
This signal is emitted when the child window \a w becomes active. | |
Note that \a w can be 0, and that more than one signal may be | |
emitted for a single activation event. | |
\sa activeWindow(), windowList() | |
*/ | |
/*! | |
Arranges all the child windows in a cascade pattern. | |
\sa tile(), arrangeIcons() | |
*/ | |
void QWorkspace::cascade() | |
{ | |
Q_D(QWorkspace); | |
blockSignals(true); | |
if (d->maxWindow) | |
d->maxWindow->showNormal(); | |
if (d->vbar) { | |
d->vbar->blockSignals(true); | |
d->vbar->setValue(0); | |
d->vbar->blockSignals(false); | |
d->hbar->blockSignals(true); | |
d->hbar->setValue(0); | |
d->hbar->blockSignals(false); | |
d->_q_scrollBarChanged(); | |
} | |
const int xoffset = 13; | |
const int yoffset = 20; | |
// make a list of all relevant mdi clients | |
QList<QWorkspaceChild *> widgets; | |
QList<QWorkspaceChild *>::Iterator it(d->windows.begin()); | |
QWorkspaceChild* wc = 0; | |
for (it = d->focus.begin(); it != d->focus.end(); ++it) { | |
wc = *it; | |
if (wc->windowWidget()->isVisibleTo(this) && !(wc->titlebar && wc->titlebar->isTool())) | |
widgets.append(wc); | |
} | |
int x = 0; | |
int y = 0; | |
it = widgets.begin(); | |
while (it != widgets.end()) { | |
QWorkspaceChild *child = *it; | |
++it; | |
QSize prefSize = child->windowWidget()->sizeHint().expandedTo(qSmartMinSize(child->windowWidget())); | |
if (!prefSize.isValid()) | |
prefSize = child->windowWidget()->size(); | |
prefSize = prefSize.expandedTo(qSmartMinSize(child->windowWidget())); | |
if (prefSize.isValid()) | |
prefSize += QSize(child->baseSize().width(), child->baseSize().height()); | |
int w = prefSize.width(); | |
int h = prefSize.height(); | |
child->showNormal(); | |
if (y + h > height()) | |
y = 0; | |
if (x + w > width()) | |
x = 0; | |
child->setGeometry(x, y, w, h); | |
x += xoffset; | |
y += yoffset; | |
child->internalRaise(); | |
} | |
d->updateWorkspace(); | |
blockSignals(false); | |
} | |
/*! | |
Arranges all child windows in a tile pattern. | |
\sa cascade(), arrangeIcons() | |
*/ | |
void QWorkspace::tile() | |
{ | |
Q_D(QWorkspace); | |
blockSignals(true); | |
QWidget *oldActive = d->active ? d->active->windowWidget() : 0; | |
if (d->maxWindow) | |
d->maxWindow->showNormal(); | |
if (d->vbar) { | |
d->vbar->blockSignals(true); | |
d->vbar->setValue(0); | |
d->vbar->blockSignals(false); | |
d->hbar->blockSignals(true); | |
d->hbar->setValue(0); | |
d->hbar->blockSignals(false); | |
d->_q_scrollBarChanged(); | |
} | |
int rows = 1; | |
int cols = 1; | |
int n = 0; | |
QWorkspaceChild* c; | |
QList<QWorkspaceChild *>::Iterator it(d->windows.begin()); | |
while (it != d->windows.end()) { | |
c = *it; | |
++it; | |
if (!c->windowWidget()->isHidden() | |
&& !(c->windowWidget()->windowFlags() & Qt::WindowStaysOnTopHint) | |
&& !c->iconw) | |
n++; | |
} | |
while (rows * cols < n) { | |
if (cols <= rows) | |
cols++; | |
else | |
rows++; | |
} | |
int add = cols * rows - n; | |
bool* used = new bool[cols*rows]; | |
for (int i = 0; i < rows*cols; i++) | |
used[i] = false; | |
int row = 0; | |
int col = 0; | |
int w = width() / cols; | |
int h = height() / rows; | |
it = d->windows.begin(); | |
while (it != d->windows.end()) { | |
c = *it; | |
++it; | |
if (c->iconw || c->windowWidget()->isHidden() || (c->titlebar && c->titlebar->isTool())) | |
continue; | |
if (!row && !col) { | |
w -= c->baseSize().width(); | |
h -= c->baseSize().height(); | |
} | |
if ((c->windowWidget()->windowFlags() & Qt::WindowStaysOnTopHint)) { | |
QPoint p = c->pos(); | |
if (p.x()+c->width() < 0) | |
p.setX(0); | |
if (p.x() > width()) | |
p.setX(width() - c->width()); | |
if (p.y() + 10 < 0) | |
p.setY(0); | |
if (p.y() > height()) | |
p.setY(height() - c->height()); | |
if (p != c->pos()) | |
c->QWidget::move(p); | |
} else { | |
c->showNormal(); | |
used[row*cols+col] = true; | |
QSize sz(w, h); | |
QSize bsize(c->baseSize()); | |
sz = sz.expandedTo(c->windowWidget()->minimumSize()).boundedTo(c->windowWidget()->maximumSize()); | |
sz += bsize; | |
if ( add ) { | |
if (sz.height() == h + bsize.height()) // no relevant constrains | |
sz.rheight() *= 2; | |
used[(row+1)*cols+col] = true; | |
add--; | |
} | |
c->setGeometry(col*w + col*bsize.width(), row*h + row*bsize.height(), sz.width(), sz.height()); | |
while(row < rows && col < cols && used[row*cols+col]) { | |
col++; | |
if (col == cols) { | |
col = 0; | |
row++; | |
} | |
} | |
} | |
} | |
delete [] used; | |
d->activateWindow(oldActive); | |
d->updateWorkspace(); | |
blockSignals(false); | |
} | |
/*! | |
Arranges all iconified windows at the bottom of the workspace. | |
\sa cascade(), tile() | |
*/ | |
void QWorkspace::arrangeIcons() | |
{ | |
Q_D(QWorkspace); | |
QRect cr = d->updateWorkspace(); | |
int x = 0; | |
int y = -1; | |
QList<QWidget *>::Iterator it(d->icons.begin()); | |
while (it != d->icons.end()) { | |
QWidget* i = *it; | |
if (y == -1) | |
y = cr.height() - i->height(); | |
if (x > 0 && x + i->width() > cr.width()) { | |
x = 0; | |
y -= i->height(); | |
} | |
i->move(x, y); | |
x += i->width(); | |
++it; | |
} | |
d->updateWorkspace(); | |
} | |
QWorkspaceChild::QWorkspaceChild(QWidget* window, QWorkspace *parent, Qt::WindowFlags flags) | |
: QWidget(parent, | |
Qt::FramelessWindowHint | Qt::SubWindow) | |
{ | |
setAttribute(Qt::WA_DeleteOnClose); | |
setAttribute(Qt::WA_NoMousePropagation); | |
setMouseTracking(true); | |
act = false; | |
iconw = 0; | |
shademode = false; | |
titlebar = 0; | |
setAutoFillBackground(true); | |
setBackgroundRole(QPalette::Window); | |
if (window) { | |
flags |= (window->windowFlags() & Qt::MSWindowsOwnDC); | |
if (flags) | |
window->setParent(this, flags & ~Qt::WindowType_Mask); | |
else | |
window->setParent(this); | |
} | |
if (window && (flags & (Qt::WindowTitleHint | |
| Qt::WindowSystemMenuHint | |
| Qt::WindowMinimizeButtonHint | |
| Qt::WindowMaximizeButtonHint | |
| Qt::WindowContextHelpButtonHint))) { | |
titlebar = new QWorkspaceTitleBar(window, this, flags); | |
connect(titlebar, SIGNAL(doActivate()), | |
this, SLOT(activate())); | |
connect(titlebar, SIGNAL(doClose()), | |
window, SLOT(close())); | |
connect(titlebar, SIGNAL(doMinimize()), | |
this, SLOT(showMinimized())); | |
connect(titlebar, SIGNAL(doNormal()), | |
this, SLOT(showNormal())); | |
connect(titlebar, SIGNAL(doMaximize()), | |
this, SLOT(showMaximized())); | |
connect(titlebar, SIGNAL(popupOperationMenu(QPoint)), | |
this, SIGNAL(popupOperationMenu(QPoint))); | |
connect(titlebar, SIGNAL(showOperationMenu()), | |
this, SIGNAL(showOperationMenu())); | |
connect(titlebar, SIGNAL(doShade()), | |
this, SLOT(showShaded())); | |
connect(titlebar, SIGNAL(doubleClicked()), | |
this, SLOT(titleBarDoubleClicked())); | |
} | |
setMinimumSize(128, 0); | |
int fw = style()->pixelMetric(QStyle::PM_MdiSubWindowFrameWidth, 0, this); | |
setContentsMargins(fw, fw, fw, fw); | |
childWidget = window; | |
if (!childWidget) | |
return; | |
setWindowTitle(childWidget->windowTitle()); | |
QPoint p; | |
QSize s; | |
QSize cs; | |
bool hasBeenResized = childWidget->testAttribute(Qt::WA_Resized); | |
if (!hasBeenResized) | |
cs = childWidget->sizeHint().expandedTo(childWidget->minimumSizeHint()).expandedTo(childWidget->minimumSize()).boundedTo(childWidget->maximumSize()); | |
else | |
cs = childWidget->size(); | |
windowSize = cs; | |
int th = titlebar ? titlebar->sizeHint().height() : 0; | |
if (titlebar) { | |
if (!childWidget->windowIcon().isNull()) | |
titlebar->setWindowIcon(childWidget->windowIcon()); | |
if (style()->styleHint(QStyle::SH_TitleBar_NoBorder, 0, titlebar)) | |
th -= contentsRect().y(); | |
p = QPoint(contentsRect().x(), | |
th + contentsRect().y()); | |
s = QSize(cs.width() + 2*frameWidth(), | |
cs.height() + 2*frameWidth() + th); | |
} else { | |
p = QPoint(contentsRect().x(), contentsRect().y()); | |
s = QSize(cs.width() + 2*frameWidth(), | |
cs.height() + 2*frameWidth()); | |
} | |
childWidget->move(p); | |
resize(s); | |
childWidget->installEventFilter(this); | |
widgetResizeHandler = new QWidgetResizeHandler(this, window); | |
widgetResizeHandler->setSizeProtection(!parent->scrollBarsEnabled()); | |
widgetResizeHandler->setFrameWidth(frameWidth()); | |
connect(widgetResizeHandler, SIGNAL(activate()), | |
this, SLOT(activate())); | |
if (!style()->styleHint(QStyle::SH_TitleBar_NoBorder, 0, titlebar)) | |
widgetResizeHandler->setExtraHeight(th + contentsRect().y() - 2*frameWidth()); | |
else | |
widgetResizeHandler->setExtraHeight(th + contentsRect().y() - frameWidth()); | |
if (childWidget->minimumSize() == childWidget->maximumSize()) | |
widgetResizeHandler->setActive(QWidgetResizeHandler::Resize, false); | |
setBaseSize(baseSize()); | |
} | |
QWorkspaceChild::~QWorkspaceChild() | |
{ | |
QWorkspace *workspace = qobject_cast<QWorkspace*>(parentWidget()); | |
if (iconw) { | |
if (workspace) | |
workspace->d_func()->removeIcon(iconw->parentWidget()); | |
delete iconw->parentWidget(); | |
} | |
if (workspace) { | |
workspace->d_func()->focus.removeAll(this); | |
if (workspace->d_func()->active == this) | |
workspace->activatePreviousWindow(); | |
if (workspace->d_func()->active == this) | |
workspace->d_func()->activateWindow(0); | |
if (workspace->d_func()->maxWindow == this) { | |
workspace->d_func()->hideMaximizeControls(); | |
workspace->d_func()->maxWindow = 0; | |
} | |
} | |
} | |
void QWorkspaceChild::moveEvent(QMoveEvent *) | |
{ | |
((QWorkspace*)parentWidget())->d_func()->updateWorkspace(); | |
} | |
void QWorkspaceChild::resizeEvent(QResizeEvent *) | |
{ | |
bool wasMax = isMaximized(); | |
QRect r = contentsRect(); | |
QRect cr; | |
updateMask(); | |
if (titlebar) { | |
int th = titlebar->sizeHint().height(); | |
QRect tbrect(0, 0, width(), th); | |
if (!style()->styleHint(QStyle::SH_TitleBar_NoBorder, 0, titlebar)) | |
tbrect = QRect(r.x(), r.y(), r.width(), th); | |
titlebar->setGeometry(tbrect); | |
if (style()->styleHint(QStyle::SH_TitleBar_NoBorder, 0, titlebar)) | |
th -= frameWidth(); | |
cr = QRect(r.x(), r.y() + th + (shademode ? (frameWidth() * 3) : 0), | |
r.width(), r.height() - th); | |
} else { | |
cr = r; | |
} | |
if (!childWidget) | |
return; | |
bool doContentsResize = (windowSize == childWidget->size() | |
|| !(childWidget->testAttribute(Qt::WA_Resized) && childWidget->testAttribute(Qt::WA_PendingResizeEvent)) | |
||childWidget->isMaximized()); | |
windowSize = cr.size(); | |
childWidget->move(cr.topLeft()); | |
if (doContentsResize) | |
childWidget->resize(cr.size()); | |
((QWorkspace*)parentWidget())->d_func()->updateWorkspace(); | |
if (wasMax) { | |
overrideWindowState(Qt::WindowMaximized); | |
childWidget->overrideWindowState(Qt::WindowMaximized); | |
} | |
} | |
QSize QWorkspaceChild::baseSize() const | |
{ | |
int th = titlebar ? titlebar->sizeHint().height() : 0; | |
if (style()->styleHint(QStyle::SH_TitleBar_NoBorder, 0, titlebar)) | |
th -= frameWidth(); | |
return QSize(2*frameWidth(), 2*frameWidth() + th); | |
} | |
QSize QWorkspaceChild::sizeHint() const | |
{ | |
if (!childWidget) | |
return QWidget::sizeHint() + baseSize(); | |
QSize prefSize = windowWidget()->sizeHint().expandedTo(windowWidget()->minimumSizeHint()); | |
prefSize = prefSize.expandedTo(windowWidget()->minimumSize()).boundedTo(windowWidget()->maximumSize()); | |
prefSize += baseSize(); | |
return prefSize; | |
} | |
QSize QWorkspaceChild::minimumSizeHint() const | |
{ | |
if (!childWidget) | |
return QWidget::minimumSizeHint() + baseSize(); | |
QSize s = childWidget->minimumSize(); | |
if (s.isEmpty()) | |
s = childWidget->minimumSizeHint(); | |
return s + baseSize(); | |
} | |
void QWorkspaceChild::activate() | |
{ | |
((QWorkspace*)parentWidget())->d_func()->activateWindow(windowWidget()); | |
} | |
bool QWorkspaceChild::eventFilter(QObject * o, QEvent * e) | |
{ | |
if (!isActive() | |
&& (e->type() == QEvent::MouseButtonPress || e->type() == QEvent::FocusIn)) { | |
if (iconw) { | |
((QWorkspace*)parentWidget())->d_func()->normalizeWindow(windowWidget()); | |
if (iconw) { | |
((QWorkspace*)parentWidget())->d_func()->removeIcon(iconw->parentWidget()); | |
delete iconw->parentWidget(); | |
iconw = 0; | |
} | |
} | |
activate(); | |
} | |
// for all widgets except the window, that's the only thing we | |
// process, and if we have no childWidget we skip totally | |
if (o != childWidget || childWidget == 0) | |
return false; | |
switch (e->type()) { | |
case QEvent::ShowToParent: | |
if (((QWorkspace*)parentWidget())->d_func()->focus.indexOf(this) < 0) | |
((QWorkspace*)parentWidget())->d_func()->focus.append(this); | |
if (windowWidget() && (windowWidget()->windowFlags() & Qt::WindowStaysOnTopHint)) { | |
internalRaise(); | |
show(); | |
} | |
((QWorkspace*)parentWidget())->d_func()->showWindow(windowWidget()); | |
break; | |
case QEvent::WindowStateChange: { | |
if (static_cast<QWindowStateChangeEvent*>(e)->isOverride()) | |
break; | |
Qt::WindowStates state = windowWidget()->windowState(); | |
if (state & Qt::WindowMinimized) { | |
((QWorkspace*)parentWidget())->d_func()->minimizeWindow(windowWidget()); | |
} else if (state & Qt::WindowMaximized) { | |
if (windowWidget()->maximumSize().isValid() && | |
(windowWidget()->maximumWidth() < parentWidget()->width() || | |
windowWidget()->maximumHeight() < parentWidget()->height())) { | |
windowWidget()->resize(windowWidget()->maximumSize()); | |
windowWidget()->overrideWindowState(Qt::WindowNoState); | |
if (titlebar) | |
titlebar->update(); | |
break; | |
} | |
if ((windowWidget()->windowFlags() & Qt::WindowMaximizeButtonHint)) | |
((QWorkspace*)parentWidget())->d_func()->maximizeWindow(windowWidget()); | |
else | |
((QWorkspace*)parentWidget())->d_func()->normalizeWindow(windowWidget()); | |
} else { | |
((QWorkspace*)parentWidget())->d_func()->normalizeWindow(windowWidget()); | |
if (iconw) { | |
((QWorkspace*)parentWidget())->d_func()->removeIcon(iconw->parentWidget()); | |
delete iconw->parentWidget(); | |
} | |
} | |
} break; | |
case QEvent::HideToParent: | |
{ | |
QWidget * w = iconw; | |
if (w && (w = w->parentWidget())) { | |
((QWorkspace*)parentWidget())->d_func()->removeIcon(w); | |
delete w; | |
} | |
((QWorkspace*)parentWidget())->d_func()->hideChild(this); | |
} break; | |
case QEvent::WindowIconChange: | |
{ | |
QWorkspace* ws = (QWorkspace*)parentWidget(); | |
if (ws->d_func()->maxtools && ws->d_func()->maxWindow == this) { | |
int iconSize = ws->d_func()->maxtools->size().height(); | |
ws->d_func()->maxtools->setPixmap(childWidget->windowIcon().pixmap(QSize(iconSize, iconSize))); | |
} | |
} | |
// fall through | |
case QEvent::WindowTitleChange: | |
setWindowTitle(windowWidget()->windowTitle()); | |
if (titlebar) | |
titlebar->update(); | |
if (iconw) | |
iconw->update(); | |
break; | |
case QEvent::ModifiedChange: | |
setWindowModified(windowWidget()->isWindowModified()); | |
if (titlebar) | |
titlebar->update(); | |
if (iconw) | |
iconw->update(); | |
break; | |
case QEvent::Resize: | |
{ | |
QResizeEvent* re = (QResizeEvent*)e; | |
if (re->size() != windowSize && !shademode) { | |
resize(re->size() + baseSize()); | |
childWidget->update(); //workaround | |
} | |
} | |
break; | |
case QEvent::WindowDeactivate: | |
if (titlebar && titlebar->isActive()) { | |
update(); | |
} | |
break; | |
case QEvent::WindowActivate: | |
if (titlebar && titlebar->isActive()) { | |
update(); | |
} | |
break; | |
default: | |
break; | |
} | |
return QWidget::eventFilter(o, e); | |
} | |
void QWorkspaceChild::childEvent(QChildEvent* e) | |
{ | |
if (e->type() == QEvent::ChildRemoved && e->child() == childWidget) { | |
childWidget = 0; | |
if (iconw) { | |
((QWorkspace*)parentWidget())->d_func()->removeIcon(iconw->parentWidget()); | |
delete iconw->parentWidget(); | |
} | |
close(); | |
} | |
} | |
void QWorkspaceChild::doResize() | |
{ | |
widgetResizeHandler->doResize(); | |
} | |
void QWorkspaceChild::doMove() | |
{ | |
widgetResizeHandler->doMove(); | |
} | |
void QWorkspaceChild::enterEvent(QEvent *) | |
{ | |
} | |
void QWorkspaceChild::leaveEvent(QEvent *) | |
{ | |
#ifndef QT_NO_CURSOR | |
if (!widgetResizeHandler->isButtonDown()) | |
setCursor(Qt::ArrowCursor); | |
#endif | |
} | |
void QWorkspaceChild::paintEvent(QPaintEvent *) | |
{ | |
QPainter p(this); | |
QStyleOptionFrame opt; | |
opt.rect = rect(); | |
opt.palette = palette(); | |
opt.state = QStyle::State_None; | |
opt.lineWidth = style()->pixelMetric(QStyle::PM_MdiSubWindowFrameWidth, 0, this); | |
opt.midLineWidth = 1; | |
if (titlebar && titlebar->isActive() && isActiveWindow()) | |
opt.state |= QStyle::State_Active; | |
style()->drawPrimitive(QStyle::PE_FrameWindow, &opt, &p, this); | |
} | |
void QWorkspaceChild::changeEvent(QEvent *ev) | |
{ | |
if(ev->type() == QEvent::StyleChange) { | |
resizeEvent(0); | |
if (iconw) { | |
QFrame *frame = qobject_cast<QFrame*>(iconw->parentWidget()); | |
Q_ASSERT(frame); | |
if (!style()->styleHint(QStyle::SH_TitleBar_NoBorder, 0, titlebar)) { | |
frame->setFrameStyle(QFrame::StyledPanel | QFrame::Raised); | |
frame->resize(196+2*frame->frameWidth(), 20 + 2*frame->frameWidth()); | |
} else { | |
frame->resize(196, 20); | |
} | |
} | |
updateMask(); | |
} | |
QWidget::changeEvent(ev); | |
} | |
void QWorkspaceChild::setActive(bool b) | |
{ | |
if (!childWidget) | |
return; | |
bool hasFocus = isChildOf(window()->focusWidget(), this); | |
if (act == b && (act == hasFocus)) | |
return; | |
act = b; | |
if (titlebar) | |
titlebar->setActive(act); | |
if (iconw) | |
iconw->setActive(act); | |
update(); | |
QList<QWidget*> wl = qFindChildren<QWidget*>(childWidget); | |
if (act) { | |
for (int i = 0; i < wl.size(); ++i) { | |
QWidget *w = wl.at(i); | |
w->removeEventFilter(this); | |
} | |
if (!hasFocus) { | |
QWidget *lastfocusw = childWidget->focusWidget(); | |
if (lastfocusw && lastfocusw->focusPolicy() != Qt::NoFocus) { | |
lastfocusw->setFocus(); | |
} else if (childWidget->focusPolicy() != Qt::NoFocus) { | |
childWidget->setFocus(); | |
} else { | |
// find something, anything, that accepts focus, and use that. | |
for (int i = 0; i < wl.size(); ++i) { | |
QWidget *w = wl.at(i); | |
if(w->focusPolicy() != Qt::NoFocus) { | |
w->setFocus(); | |
hasFocus = true; | |
break; | |
} | |
} | |
if (!hasFocus) | |
setFocus(); | |
} | |
} | |
} else { | |
for (int i = 0; i < wl.size(); ++i) { | |
QWidget *w = wl.at(i); | |
w->removeEventFilter(this); | |
w->installEventFilter(this); | |
} | |
} | |
} | |
bool QWorkspaceChild::isActive() const | |
{ | |
return act; | |
} | |
QWidget* QWorkspaceChild::windowWidget() const | |
{ | |
return childWidget; | |
} | |
bool QWorkspaceChild::isWindowOrIconVisible() const | |
{ | |
return childWidget && (!isHidden() || (iconw && !iconw->isHidden())); | |
} | |
void QWorkspaceChild::updateMask() | |
{ | |
QStyleOptionTitleBar titleBarOptions; | |
titleBarOptions.rect = rect(); | |
titleBarOptions.titleBarFlags = windowFlags(); | |
titleBarOptions.titleBarState = windowState(); | |
QStyleHintReturnMask frameMask; | |
if (style()->styleHint(QStyle::SH_WindowFrame_Mask, &titleBarOptions, this, &frameMask)) { | |
setMask(frameMask.region); | |
} else if (!mask().isEmpty()) { | |
clearMask(); | |
} | |
if (iconw) { | |
QFrame *frame = qobject_cast<QFrame *>(iconw->parentWidget()); | |
Q_ASSERT(frame); | |
titleBarOptions.rect = frame->rect(); | |
titleBarOptions.titleBarFlags = frame->windowFlags(); | |
titleBarOptions.titleBarState = frame->windowState() | Qt::WindowMinimized; | |
if (style()->styleHint(QStyle::SH_WindowFrame_Mask, &titleBarOptions, frame, &frameMask)) { | |
frame->setMask(frameMask.region); | |
} else if (!frame->mask().isEmpty()) { | |
frame->clearMask(); | |
} | |
} | |
} | |
QWidget* QWorkspaceChild::iconWidget() const | |
{ | |
if (!iconw) { | |
QWorkspaceChild* that = (QWorkspaceChild*) this; | |
QFrame* frame = new QFrame(that, Qt::Window); | |
QVBoxLayout *vbox = new QVBoxLayout(frame); | |
vbox->setMargin(0); | |
QWorkspaceTitleBar *tb = new QWorkspaceTitleBar(windowWidget(), frame); | |
vbox->addWidget(tb); | |
tb->setObjectName(QLatin1String("_workspacechild_icon_")); | |
QStyleOptionTitleBar opt; | |
tb->initStyleOption(&opt); | |
int th = style()->pixelMetric(QStyle::PM_TitleBarHeight, &opt, tb); | |
int iconSize = style()->pixelMetric(QStyle::PM_MdiSubWindowMinimizedWidth, 0, this); | |
if (!style()->styleHint(QStyle::SH_TitleBar_NoBorder, 0, titlebar)) { | |
frame->setFrameStyle(QFrame::StyledPanel | QFrame::Raised); | |
frame->resize(iconSize+2*frame->frameWidth(), th+2*frame->frameWidth()); | |
} else { | |
frame->resize(iconSize, th); | |
} | |
that->iconw = tb; | |
that->updateMask(); | |
iconw->setActive(isActive()); | |
connect(iconw, SIGNAL(doActivate()), | |
this, SLOT(activate())); | |
connect(iconw, SIGNAL(doClose()), | |
windowWidget(), SLOT(close())); | |
connect(iconw, SIGNAL(doNormal()), | |
this, SLOT(showNormal())); | |
connect(iconw, SIGNAL(doMaximize()), | |
this, SLOT(showMaximized())); | |
connect(iconw, SIGNAL(popupOperationMenu(QPoint)), | |
this, SIGNAL(popupOperationMenu(QPoint))); | |
connect(iconw, SIGNAL(showOperationMenu()), | |
this, SIGNAL(showOperationMenu())); | |
connect(iconw, SIGNAL(doubleClicked()), | |
this, SLOT(titleBarDoubleClicked())); | |
} | |
if (windowWidget()) { | |
iconw->setWindowTitle(windowWidget()->windowTitle()); | |
} | |
return iconw->parentWidget(); | |
} | |
void QWorkspaceChild::showMinimized() | |
{ | |
windowWidget()->setWindowState(Qt::WindowMinimized | (windowWidget()->windowState() & ~Qt::WindowMaximized)); | |
} | |
void QWorkspaceChild::showMaximized() | |
{ | |
windowWidget()->setWindowState(Qt::WindowMaximized | (windowWidget()->windowState() & ~Qt::WindowMinimized)); | |
} | |
void QWorkspaceChild::showNormal() | |
{ | |
windowWidget()->setWindowState(windowWidget()->windowState() & ~(Qt::WindowMinimized|Qt::WindowMaximized)); | |
} | |
void QWorkspaceChild::showShaded() | |
{ | |
if (!titlebar) | |
return; | |
((QWorkspace*)parentWidget())->d_func()->activateWindow(windowWidget()); | |
QWidget* w = windowWidget(); | |
if (shademode) { | |
w->overrideWindowState(Qt::WindowNoState); | |
overrideWindowState(Qt::WindowNoState); | |
shademode = false; | |
resize(shadeRestore.expandedTo(minimumSizeHint())); | |
setMinimumSize(shadeRestoreMin); | |
style()->polish(this); | |
} else { | |
shadeRestore = size(); | |
shadeRestoreMin = minimumSize(); | |
setMinimumHeight(0); | |
shademode = true; | |
w->overrideWindowState(Qt::WindowMinimized); | |
overrideWindowState(Qt::WindowMinimized); | |
if (style()->styleHint(QStyle::SH_TitleBar_NoBorder, 0, titlebar)) | |
resize(width(), titlebar->height()); | |
else | |
resize(width(), titlebar->height() + 2*frameWidth() + 1); | |
style()->polish(this); | |
} | |
titlebar->update(); | |
} | |
void QWorkspaceChild::titleBarDoubleClicked() | |
{ | |
if (!windowWidget()) | |
return; | |
if (iconw) | |
showNormal(); | |
else if (windowWidget()->windowFlags() & Qt::WindowShadeButtonHint) | |
showShaded(); | |
else if (windowWidget()->windowFlags() & Qt::WindowMaximizeButtonHint) | |
showMaximized(); | |
} | |
void QWorkspaceChild::adjustToFullscreen() | |
{ | |
if (!childWidget) | |
return; | |
if(!((QWorkspace*)parentWidget())->d_func()->maxmenubar || style()->styleHint(QStyle::SH_Workspace_FillSpaceOnMaximize, 0, this)) { | |
setGeometry(parentWidget()->rect()); | |
} else { | |
int fw = style()->pixelMetric(QStyle::PM_MdiSubWindowFrameWidth, 0, this); | |
bool noBorder = style()->styleHint(QStyle::SH_TitleBar_NoBorder, 0, titlebar); | |
int th = titlebar ? titlebar->sizeHint().height() : 0; | |
int w = parentWidget()->width() + 2*fw; | |
int h = parentWidget()->height() + (noBorder ? fw : 2*fw) + th; | |
w = qMax(w, childWidget->minimumWidth()); | |
h = qMax(h, childWidget->minimumHeight()); | |
setGeometry(-fw, (noBorder ? 0 : -fw) - th, w, h); | |
} | |
childWidget->overrideWindowState(Qt::WindowMaximized); | |
overrideWindowState(Qt::WindowMaximized); | |
} | |
void QWorkspaceChild::internalRaise() | |
{ | |
QWidget *stackUnderWidget = 0; | |
if (!windowWidget() || (windowWidget()->windowFlags() & Qt::WindowStaysOnTopHint) == 0) { | |
QList<QWorkspaceChild *>::Iterator it(((QWorkspace*)parent())->d_func()->windows.begin()); | |
while (it != ((QWorkspace*)parent())->d_func()->windows.end()) { | |
QWorkspaceChild* c = *it; | |
++it; | |
if (c->windowWidget() && | |
!c->windowWidget()->isHidden() && | |
(c->windowWidget()->windowFlags() & Qt::WindowStaysOnTopHint)) { | |
if (stackUnderWidget) | |
c->stackUnder(stackUnderWidget); | |
else | |
c->raise(); | |
stackUnderWidget = c; | |
} | |
} | |
} | |
if (stackUnderWidget) { | |
if (iconw) | |
iconw->parentWidget()->stackUnder(stackUnderWidget); | |
stackUnder(stackUnderWidget); | |
} else { | |
if (iconw) | |
iconw->parentWidget()->raise(); | |
raise(); | |
} | |
} | |
void QWorkspaceChild::show() | |
{ | |
if (childWidget && childWidget->isHidden()) | |
childWidget->show(); | |
QWidget::show(); | |
} | |
bool QWorkspace::scrollBarsEnabled() const | |
{ | |
Q_D(const QWorkspace); | |
return d->vbar != 0; | |
} | |
/*! | |
\property QWorkspace::scrollBarsEnabled | |
\brief whether the workspace provides scroll bars | |
If this property is true, the workspace will provide scroll bars if any | |
of the child windows extend beyond the edges of the visible | |
workspace. The workspace area will automatically increase to | |
contain child windows if they are resized beyond the right or | |
bottom edges of the visible area. | |
If this property is false (the default), resizing child windows | |
out of the visible area of the workspace is not permitted, although | |
it is still possible to position them partially outside the visible area. | |
*/ | |
void QWorkspace::setScrollBarsEnabled(bool enable) | |
{ | |
Q_D(QWorkspace); | |
if ((d->vbar != 0) == enable) | |
return; | |
d->xoffset = d->yoffset = 0; | |
if (enable) { | |
d->vbar = new QScrollBar(Qt::Vertical, this); | |
d->vbar->setObjectName(QLatin1String("vertical scrollbar")); | |
connect(d->vbar, SIGNAL(valueChanged(int)), this, SLOT(_q_scrollBarChanged())); | |
d->hbar = new QScrollBar(Qt::Horizontal, this); | |
d->hbar->setObjectName(QLatin1String("horizontal scrollbar")); | |
connect(d->hbar, SIGNAL(valueChanged(int)), this, SLOT(_q_scrollBarChanged())); | |
d->corner = new QWidget(this); | |
d->corner->setBackgroundRole(QPalette::Window); | |
d->corner->setObjectName(QLatin1String("qt_corner")); | |
d->updateWorkspace(); | |
} else { | |
delete d->vbar; | |
delete d->hbar; | |
delete d->corner; | |
d->vbar = d->hbar = 0; | |
d->corner = 0; | |
} | |
QList<QWorkspaceChild *>::Iterator it(d->windows.begin()); | |
while (it != d->windows.end()) { | |
QWorkspaceChild *child = *it; | |
++it; | |
child->widgetResizeHandler->setSizeProtection(!enable); | |
} | |
} | |
QRect QWorkspacePrivate::updateWorkspace() | |
{ | |
Q_Q(QWorkspace); | |
QRect cr(q->rect()); | |
if (q->scrollBarsEnabled() && !maxWindow) { | |
corner->raise(); | |
vbar->raise(); | |
hbar->raise(); | |
if (maxWindow) | |
maxWindow->internalRaise(); | |
QRect r(0, 0, 0, 0); | |
QList<QWorkspaceChild *>::Iterator it(windows.begin()); | |
while (it != windows.end()) { | |
QWorkspaceChild *child = *it; | |
++it; | |
if (!child->isHidden()) | |
r = r.unite(child->geometry()); | |
} | |
vbar->blockSignals(true); | |
hbar->blockSignals(true); | |
int hsbExt = hbar->sizeHint().height(); | |
int vsbExt = vbar->sizeHint().width(); | |
bool showv = yoffset || yoffset + r.bottom() - q->height() + 1 > 0 || yoffset + r.top() < 0; | |
bool showh = xoffset || xoffset + r.right() - q->width() + 1 > 0 || xoffset + r.left() < 0; | |
if (showh && !showv) | |
showv = yoffset + r.bottom() - q->height() + hsbExt + 1 > 0; | |
if (showv && !showh) | |
showh = xoffset + r.right() - q->width() + vsbExt + 1 > 0; | |
if (!showh) | |
hsbExt = 0; | |
if (!showv) | |
vsbExt = 0; | |
if (showv) { | |
vbar->setSingleStep(qMax(q->height() / 12, 30)); | |
vbar->setPageStep(q->height() - hsbExt); | |
vbar->setMinimum(qMin(0, yoffset + qMin(0, r.top()))); | |
vbar->setMaximum(qMax(0, yoffset + qMax(0, r.bottom() - q->height() + hsbExt + 1))); | |
vbar->setGeometry(q->width() - vsbExt, 0, vsbExt, q->height() - hsbExt); | |
vbar->setValue(yoffset); | |
vbar->show(); | |
} else { | |
vbar->hide(); | |
} | |
if (showh) { | |
hbar->setSingleStep(qMax(q->width() / 12, 30)); | |
hbar->setPageStep(q->width() - vsbExt); | |
hbar->setMinimum(qMin(0, xoffset + qMin(0, r.left()))); | |
hbar->setMaximum(qMax(0, xoffset + qMax(0, r.right() - q->width() + vsbExt + 1))); | |
hbar->setGeometry(0, q->height() - hsbExt, q->width() - vsbExt, hsbExt); | |
hbar->setValue(xoffset); | |
hbar->show(); | |
} else { | |
hbar->hide(); | |
} | |
if (showh && showv) { | |
corner->setGeometry(q->width() - vsbExt, q->height() - hsbExt, vsbExt, hsbExt); | |
corner->show(); | |
} else { | |
corner->hide(); | |
} | |
vbar->blockSignals(false); | |
hbar->blockSignals(false); | |
cr.setRect(0, 0, q->width() - vsbExt, q->height() - hsbExt); | |
} | |
QList<QWidget *>::Iterator ii(icons.begin()); | |
while (ii != icons.end()) { | |
QWidget* w = *ii; | |
++ii; | |
int x = w->x(); | |
int y = w->y(); | |
bool m = false; | |
if (x+w->width() > cr.width()) { | |
m = true; | |
x = cr.width() - w->width(); | |
} | |
if (y+w->height() > cr.height()) { | |
y = cr.height() - w->height(); | |
m = true; | |
} | |
if (m) { | |
if (QWorkspaceChild *child = qobject_cast<QWorkspaceChild*>(w)) | |
child->move(x, y); | |
else | |
w->move(x, y); | |
} | |
} | |
return cr; | |
} | |
void QWorkspacePrivate::_q_scrollBarChanged() | |
{ | |
int ver = yoffset - vbar->value(); | |
int hor = xoffset - hbar->value(); | |
yoffset = vbar->value(); | |
xoffset = hbar->value(); | |
QList<QWorkspaceChild *>::Iterator it(windows.begin()); | |
while (it != windows.end()) { | |
QWorkspaceChild *child = *it; | |
++it; | |
// we do not use move() due to the reimplementation in QWorkspaceChild | |
child->setGeometry(child->x() + hor, child->y() + ver, child->width(), child->height()); | |
} | |
updateWorkspace(); | |
} | |
/*! | |
\enum QWorkspace::WindowOrder | |
Specifies the order in which child windows are returned from windowList(). | |
\value CreationOrder The windows are returned in the order of their creation | |
\value StackingOrder The windows are returned in the order of their stacking | |
*/ | |
/*!\reimp */ | |
void QWorkspace::changeEvent(QEvent *ev) | |
{ | |
Q_D(QWorkspace); | |
if(ev->type() == QEvent::StyleChange) { | |
if (isVisible() && d->maxWindow && d->maxmenubar) { | |
if(style()->styleHint(QStyle::SH_Workspace_FillSpaceOnMaximize, 0, this)) { | |
d->hideMaximizeControls(); //hide any visible maximized controls | |
d->showMaximizeControls(); //updates the modification state as well | |
} | |
} | |
} | |
QWidget::changeEvent(ev); | |
} | |
QT_END_NAMESPACE | |
#include "moc_qworkspace.cpp" | |
#include "qworkspace.moc" | |
#endif // QT_NO_WORKSPACE |