diff options
author | Lars Knoll <lars.knoll@nokia.com> | 2009-03-23 09:18:55 (GMT) |
---|---|---|
committer | Simon Hausmann <simon.hausmann@nokia.com> | 2009-03-23 09:18:55 (GMT) |
commit | e5fcad302d86d316390c6b0f62759a067313e8a9 (patch) | |
tree | c2afbf6f1066b6ce261f14341cf6d310e5595bc1 /src/gui/widgets/qworkspace.cpp | |
download | Qt-e5fcad302d86d316390c6b0f62759a067313e8a9.zip Qt-e5fcad302d86d316390c6b0f62759a067313e8a9.tar.gz Qt-e5fcad302d86d316390c6b0f62759a067313e8a9.tar.bz2 |
Long live Qt 4.5!
Diffstat (limited to 'src/gui/widgets/qworkspace.cpp')
-rw-r--r-- | src/gui/widgets/qworkspace.cpp | 3382 |
1 files changed, 3382 insertions, 0 deletions
diff --git a/src/gui/widgets/qworkspace.cpp b/src/gui/widgets/qworkspace.cpp new file mode 100644 index 0000000..5221deb --- /dev/null +++ b/src/gui/widgets/qworkspace.cpp @@ -0,0 +1,3382 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qworkspace.h" +#ifndef QT_NO_WORKSPACE +#include "qapplication.h" +#include "qbitmap.h" +#include "qcursor.h" +#include "qdatetime.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 "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")); + else if (ctrl == QStyle::SC_MdiMinButton) + QToolTip::showText(helpEvent->globalPos(), QWorkspace::tr("Minimize")); + else if (ctrl == QStyle::SC_MdiNormalButton) + QToolTip::showText(helpEvent->globalPos(), QWorkspace::tr("Restore Down")); + 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))); + if (QSysInfo::WindowsVersion != QSysInfo::WV_95 && QSysInfo::WindowsVersion != QSysInfo::WV_NT) { + colorsInitialized = true; + BOOL gradient; + QT_WA({ + SystemParametersInfo(SPI_GETGRADIENTCAPTIONS, 0, &gradient, 0); + } , { + SystemParametersInfoA(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 QTime *t = 0; + static QWorkspaceTitleBar *tc = 0; + if (!t) + t = new QTime; + 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. + \ingroup 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 QTime* 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 QTime; + 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 |