source: trunk/src/gui/widgets/qworkspace.cpp@ 147

Last change on this file since 147 was 2, checked in by Dmitry A. Kuminov, 16 years ago

Initially imported qt-all-opensource-src-4.5.1 from Trolltech.

File size: 102.9 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4** Contact: Qt Software Information ([email protected])
5**
6** This file is part of the QtGui module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial Usage
10** Licensees holding valid Qt Commercial licenses may use this file in
11** accordance with the Qt Commercial License Agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and Nokia.
14**
15** GNU Lesser General Public License Usage
16** Alternatively, this file may be used under the terms of the GNU Lesser
17** General Public License version 2.1 as published by the Free Software
18** Foundation and appearing in the file LICENSE.LGPL included in the
19** packaging of this file. Please review the following information to
20** ensure the GNU Lesser General Public License version 2.1 requirements
21** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
22**
23** In addition, as a special exception, Nokia gives you certain
24** additional rights. These rights are described in the Nokia Qt LGPL
25** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
26** package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you are unsure which license is appropriate for your use, please
37** contact the sales department at [email protected].
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include "qworkspace.h"
43#ifndef QT_NO_WORKSPACE
44#include "qapplication.h"
45#include "qbitmap.h"
46#include "qcursor.h"
47#include "qdatetime.h"
48#include "qdesktopwidget.h"
49#include "qevent.h"
50#include "qhash.h"
51#include "qicon.h"
52#include "qimage.h"
53#include "qlabel.h"
54#include "qlayout.h"
55#include "qmenubar.h"
56#include "qmenu.h"
57#include "qpainter.h"
58#include "qpointer.h"
59#include "qscrollbar.h"
60#include "qstyle.h"
61#include "qstyleoption.h"
62#include "qtooltip.h"
63#include "qdebug.h"
64#include <private/qwidget_p.h>
65#include <private/qwidgetresizehandler_p.h>
66#include <private/qlayoutengine_p.h>
67
68QT_BEGIN_NAMESPACE
69
70class QWorkspaceTitleBarPrivate;
71
72
73/**************************************************************
74* QMDIControl
75*
76* Used for displaying MDI controls in a maximized MDI window
77*
78*/
79class QMDIControl : public QWidget
80{
81 Q_OBJECT
82signals:
83 void _q_minimize();
84 void _q_restore();
85 void _q_close();
86
87public:
88 QMDIControl(QWidget *widget);
89
90private:
91 QSize sizeHint() const;
92 void paintEvent(QPaintEvent *event);
93 void mousePressEvent(QMouseEvent *event);
94 void mouseReleaseEvent(QMouseEvent *event);
95 void mouseMoveEvent(QMouseEvent *event);
96 void leaveEvent(QEvent *event);
97 bool event(QEvent *event);
98 void initStyleOption(QStyleOptionComplex *option) const;
99 QStyle::SubControl activeControl; //control locked by pressing and holding the mouse
100 QStyle::SubControl hoverControl; //previously active hover control, used for tracking repaints
101};
102
103bool QMDIControl::event(QEvent *event)
104{
105 if (event->type() == QEvent::ToolTip) {
106 QStyleOptionComplex opt;
107 initStyleOption(&opt);
108#ifndef QT_NO_TOOLTIP
109 QHelpEvent *helpEvent = static_cast<QHelpEvent *>(event);
110 QStyle::SubControl ctrl = style()->hitTestComplexControl(QStyle::CC_MdiControls, &opt,
111 helpEvent->pos(), this);
112 if (ctrl == QStyle::SC_MdiCloseButton)
113 QToolTip::showText(helpEvent->globalPos(), QWorkspace::tr("Close"));
114 else if (ctrl == QStyle::SC_MdiMinButton)
115 QToolTip::showText(helpEvent->globalPos(), QWorkspace::tr("Minimize"));
116 else if (ctrl == QStyle::SC_MdiNormalButton)
117 QToolTip::showText(helpEvent->globalPos(), QWorkspace::tr("Restore Down"));
118 else
119 QToolTip::hideText();
120#endif // QT_NO_TOOLTIP
121 }
122 return QWidget::event(event);
123}
124
125void QMDIControl::initStyleOption(QStyleOptionComplex *option) const
126{
127 option->initFrom(this);
128 option->subControls = QStyle::SC_All;
129 option->activeSubControls = QStyle::SC_None;
130}
131
132QMDIControl::QMDIControl(QWidget *widget)
133 : QWidget(widget), activeControl(QStyle::SC_None),
134 hoverControl(QStyle::SC_None)
135{
136 setObjectName(QLatin1String("qt_maxcontrols"));
137 setFocusPolicy(Qt::NoFocus);
138 setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
139 setMouseTracking(true);
140}
141
142QSize QMDIControl::sizeHint() const
143{
144 ensurePolished();
145 QStyleOptionComplex opt;
146 initStyleOption(&opt);
147 QSize size(48, 16);
148 return style()->sizeFromContents(QStyle::CT_MdiControls, &opt, size, this);
149}
150
151void QMDIControl::mousePressEvent(QMouseEvent *event)
152{
153 if (event->button() != Qt::LeftButton) {
154 event->ignore();
155 return;
156 }
157 QStyleOptionComplex opt;
158 initStyleOption(&opt);
159 QStyle::SubControl ctrl = style()->hitTestComplexControl(QStyle::CC_MdiControls, &opt,
160 event->pos(), this);
161 activeControl = ctrl;
162 update();
163}
164
165void QMDIControl::mouseReleaseEvent(QMouseEvent *event)
166{
167 if (event->button() != Qt::LeftButton) {
168 event->ignore();
169 return;
170 }
171 QStyleOptionTitleBar opt;
172 initStyleOption(&opt);
173 QStyle::SubControl under_mouse = style()->hitTestComplexControl(QStyle::CC_MdiControls, &opt,
174 event->pos(), this);
175 if (under_mouse == activeControl) {
176 switch (activeControl) {
177 case QStyle::SC_MdiCloseButton:
178 emit _q_close();
179 break;
180 case QStyle::SC_MdiNormalButton:
181 emit _q_restore();
182 break;
183 case QStyle::SC_MdiMinButton:
184 emit _q_minimize();
185 break;
186 default:
187 break;
188 }
189 }
190 activeControl = QStyle::SC_None;
191 update();
192}
193
194void QMDIControl::leaveEvent(QEvent * /*event*/)
195{
196 hoverControl = QStyle::SC_None;
197 update();
198}
199
200void QMDIControl::mouseMoveEvent(QMouseEvent *event)
201{
202 QStyleOptionTitleBar opt;
203 initStyleOption(&opt);
204 QStyle::SubControl under_mouse = style()->hitTestComplexControl(QStyle::CC_MdiControls, &opt,
205 event->pos(), this);
206 //test if hover state changes
207 if (hoverControl != under_mouse) {
208 hoverControl = under_mouse;
209 update();
210 }
211}
212
213void QMDIControl::paintEvent(QPaintEvent *)
214{
215 QPainter p(this);
216 QStyleOptionComplex opt;
217 initStyleOption(&opt);
218 if (activeControl == hoverControl) {
219 opt.activeSubControls = activeControl;
220 opt.state |= QStyle::State_Sunken;
221 } else if (hoverControl != QStyle::SC_None && (activeControl == QStyle::SC_None)) {
222 opt.activeSubControls = hoverControl;
223 opt.state |= QStyle::State_MouseOver;
224 }
225 style()->drawComplexControl(QStyle::CC_MdiControls, &opt, &p, this);
226}
227
228class QWorkspaceTitleBar : public QWidget
229{
230 Q_OBJECT
231 Q_DECLARE_PRIVATE(QWorkspaceTitleBar)
232 Q_PROPERTY(bool autoRaise READ autoRaise WRITE setAutoRaise)
233 Q_PROPERTY(bool movable READ isMovable WRITE setMovable)
234
235public:
236 QWorkspaceTitleBar (QWidget *w, QWidget *parent, Qt::WindowFlags f = 0);
237 ~QWorkspaceTitleBar();
238
239 bool isActive() const;
240 bool usesActiveColor() const;
241
242 bool isMovable() const;
243 void setMovable(bool);
244
245 bool autoRaise() const;
246 void setAutoRaise(bool);
247
248 QWidget *window() const;
249 bool isTool() const;
250
251 QSize sizeHint() const;
252 void initStyleOption(QStyleOptionTitleBar *option) const;
253
254public slots:
255 void setActive(bool);
256
257signals:
258 void doActivate();
259 void doNormal();
260 void doClose();
261 void doMaximize();
262 void doMinimize();
263 void doShade();
264 void showOperationMenu();
265 void popupOperationMenu(const QPoint&);
266 void doubleClicked();
267
268protected:
269 bool event(QEvent *);
270#ifndef QT_NO_CONTEXTMENU
271 void contextMenuEvent(QContextMenuEvent *);
272#endif
273 void mousePressEvent(QMouseEvent *);
274 void mouseDoubleClickEvent(QMouseEvent *);
275 void mouseReleaseEvent(QMouseEvent *);
276 void mouseMoveEvent(QMouseEvent *);
277 void enterEvent(QEvent *e);
278 void leaveEvent(QEvent *e);
279 void paintEvent(QPaintEvent *p);
280
281private:
282 Q_DISABLE_COPY(QWorkspaceTitleBar)
283};
284
285
286class QWorkspaceTitleBarPrivate : public QWidgetPrivate
287{
288 Q_DECLARE_PUBLIC(QWorkspaceTitleBar)
289public:
290 QWorkspaceTitleBarPrivate()
291 :
292 lastControl(QStyle::SC_None),
293#ifndef QT_NO_TOOLTIP
294 toolTip(0),
295#endif
296 act(0), window(0), movable(1), pressed(0), autoraise(0), moving(0)
297 {
298 }
299
300 Qt::WindowFlags flags;
301 QStyle::SubControl buttonDown;
302 QStyle::SubControl lastControl;
303 QPoint moveOffset;
304#ifndef QT_NO_TOOLTIP
305 QToolTip *toolTip;
306#endif
307 bool act :1;
308 QPointer<QWidget> window;
309 bool movable :1;
310 bool pressed :1;
311 bool autoraise :1;
312 bool moving : 1;
313
314 int titleBarState() const;
315 void readColors();
316};
317
318inline int QWorkspaceTitleBarPrivate::titleBarState() const
319{
320 Q_Q(const QWorkspaceTitleBar);
321 uint state = window ? window->windowState() : static_cast<Qt::WindowStates>(Qt::WindowNoState);
322 state |= uint((act && q->isActiveWindow()) ? QStyle::State_Active : QStyle::State_None);
323 return (int)state;
324}
325
326void QWorkspaceTitleBar::initStyleOption(QStyleOptionTitleBar *option) const
327{
328 Q_D(const QWorkspaceTitleBar);
329 option->initFrom(this);
330 //################
331 if (d->window && (d->flags & Qt::WindowTitleHint)) {
332 option->text = d->window->windowTitle();
333 QIcon icon = d->window->windowIcon();
334 QSize s = icon.actualSize(QSize(64, 64));
335 option->icon = icon.pixmap(s);
336 }
337 option->subControls = QStyle::SC_All;
338 option->activeSubControls = QStyle::SC_None;
339 option->titleBarState = d->titleBarState();
340 option->titleBarFlags = d->flags;
341 option->state &= ~QStyle::State_MouseOver;
342}
343
344QWorkspaceTitleBar::QWorkspaceTitleBar(QWidget *w, QWidget *parent, Qt::WindowFlags f)
345 : QWidget(*new QWorkspaceTitleBarPrivate, parent, Qt::FramelessWindowHint)
346{
347 Q_D(QWorkspaceTitleBar);
348 if (f == 0 && w)
349 f = w->windowFlags();
350 d->flags = f;
351 d->window = w;
352 d->buttonDown = QStyle::SC_None;
353 d->act = 0;
354 if (w) {
355 if (w->maximumSize() != QSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX))
356 d->flags &= ~Qt::WindowMaximizeButtonHint;
357 setWindowTitle(w->windowTitle());
358 }
359
360 d->readColors();
361 setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed));
362 setMouseTracking(true);
363 setAutoRaise(style()->styleHint(QStyle::SH_TitleBar_AutoRaise, 0, this));
364}
365
366QWorkspaceTitleBar::~QWorkspaceTitleBar()
367{
368}
369
370
371#ifdef Q_WS_WIN
372static inline QRgb colorref2qrgb(COLORREF col)
373{
374 return qRgb(GetRValue(col),GetGValue(col),GetBValue(col));
375}
376#endif
377
378void QWorkspaceTitleBarPrivate::readColors()
379{
380 Q_Q(QWorkspaceTitleBar);
381 QPalette pal = q->palette();
382
383 bool colorsInitialized = false;
384
385#ifdef Q_WS_WIN // ask system properties on windows
386#ifndef SPI_GETGRADIENTCAPTIONS
387#define SPI_GETGRADIENTCAPTIONS 0x1008
388#endif
389#ifndef COLOR_GRADIENTACTIVECAPTION
390#define COLOR_GRADIENTACTIVECAPTION 27
391#endif
392#ifndef COLOR_GRADIENTINACTIVECAPTION
393#define COLOR_GRADIENTINACTIVECAPTION 28
394#endif
395 if (QApplication::desktopSettingsAware()) {
396 pal.setColor(QPalette::Active, QPalette::Highlight, colorref2qrgb(GetSysColor(COLOR_ACTIVECAPTION)));
397 pal.setColor(QPalette::Inactive, QPalette::Highlight, colorref2qrgb(GetSysColor(COLOR_INACTIVECAPTION)));
398 pal.setColor(QPalette::Active, QPalette::HighlightedText, colorref2qrgb(GetSysColor(COLOR_CAPTIONTEXT)));
399 pal.setColor(QPalette::Inactive, QPalette::HighlightedText, colorref2qrgb(GetSysColor(COLOR_INACTIVECAPTIONTEXT)));
400 if (QSysInfo::WindowsVersion != QSysInfo::WV_95 && QSysInfo::WindowsVersion != QSysInfo::WV_NT) {
401 colorsInitialized = true;
402 BOOL gradient;
403 QT_WA({
404 SystemParametersInfo(SPI_GETGRADIENTCAPTIONS, 0, &gradient, 0);
405 } , {
406 SystemParametersInfoA(SPI_GETGRADIENTCAPTIONS, 0, &gradient, 0);
407 });
408 if (gradient) {
409 pal.setColor(QPalette::Active, QPalette::Base, colorref2qrgb(GetSysColor(COLOR_GRADIENTACTIVECAPTION)));
410 pal.setColor(QPalette::Inactive, QPalette::Base, colorref2qrgb(GetSysColor(COLOR_GRADIENTINACTIVECAPTION)));
411 } else {
412 pal.setColor(QPalette::Active, QPalette::Base, pal.color(QPalette::Active, QPalette::Highlight));
413 pal.setColor(QPalette::Inactive, QPalette::Base, pal.color(QPalette::Inactive, QPalette::Highlight));
414 }
415 }
416 }
417#endif // Q_WS_WIN
418 if (!colorsInitialized) {
419 pal.setColor(QPalette::Active, QPalette::Highlight,
420 pal.color(QPalette::Active, QPalette::Highlight));
421 pal.setColor(QPalette::Active, QPalette::Base,
422 pal.color(QPalette::Active, QPalette::Highlight));
423 pal.setColor(QPalette::Inactive, QPalette::Highlight,
424 pal.color(QPalette::Inactive, QPalette::Dark));
425 pal.setColor(QPalette::Inactive, QPalette::Base,
426 pal.color(QPalette::Inactive, QPalette::Dark));
427 pal.setColor(QPalette::Inactive, QPalette::HighlightedText,
428 pal.color(QPalette::Inactive, QPalette::Window));
429 }
430
431 q->setPalette(pal);
432 q->setActive(act);
433}
434
435void QWorkspaceTitleBar::mousePressEvent(QMouseEvent *e)
436{
437 Q_D(QWorkspaceTitleBar);
438 if (!d->act)
439 emit doActivate();
440 if (e->button() == Qt::LeftButton) {
441 if (style()->styleHint(QStyle::SH_TitleBar_NoBorder, 0, 0)
442 && !rect().adjusted(5, 5, -5, 0).contains(e->pos())) {
443 // propagate border events to the QWidgetResizeHandler
444 e->ignore();
445 return;
446 }
447
448 d->pressed = true;
449 QStyleOptionTitleBar opt;
450 initStyleOption(&opt);
451 QStyle::SubControl ctrl = style()->hitTestComplexControl(QStyle::CC_TitleBar, &opt,
452 e->pos(), this);
453 switch (ctrl) {
454 case QStyle::SC_TitleBarSysMenu:
455 if (d->flags & Qt::WindowSystemMenuHint) {
456 d->buttonDown = QStyle::SC_None;
457 static QTime *t = 0;
458 static QWorkspaceTitleBar *tc = 0;
459 if (!t)
460 t = new QTime;
461 if (tc != this || t->elapsed() > QApplication::doubleClickInterval()) {
462 emit showOperationMenu();
463 t->start();
464 tc = this;
465 } else {
466 tc = 0;
467 emit doClose();
468 return;
469 }
470 }
471 break;
472
473 case QStyle::SC_TitleBarShadeButton:
474 case QStyle::SC_TitleBarUnshadeButton:
475 if (d->flags & Qt::WindowShadeButtonHint)
476 d->buttonDown = ctrl;
477 break;
478
479 case QStyle::SC_TitleBarNormalButton:
480 d->buttonDown = ctrl;
481 break;
482
483 case QStyle::SC_TitleBarMinButton:
484 if (d->flags & Qt::WindowMinimizeButtonHint)
485 d->buttonDown = ctrl;
486 break;
487
488 case QStyle::SC_TitleBarMaxButton:
489 if (d->flags & Qt::WindowMaximizeButtonHint)
490 d->buttonDown = ctrl;
491 break;
492
493 case QStyle::SC_TitleBarCloseButton:
494 if (d->flags & Qt::WindowSystemMenuHint)
495 d->buttonDown = ctrl;
496 break;
497
498 case QStyle::SC_TitleBarLabel:
499 d->buttonDown = ctrl;
500 d->moveOffset = mapToParent(e->pos());
501 break;
502
503 default:
504 break;
505 }
506 update();
507 } else {
508 d->pressed = false;
509 }
510}
511
512#ifndef QT_NO_CONTEXTMENU
513void QWorkspaceTitleBar::contextMenuEvent(QContextMenuEvent *e)
514{
515 QStyleOptionTitleBar opt;
516 initStyleOption(&opt);
517 QStyle::SubControl ctrl = style()->hitTestComplexControl(QStyle::CC_TitleBar, &opt, e->pos(),
518 this);
519 if(ctrl == QStyle::SC_TitleBarLabel || ctrl == QStyle::SC_TitleBarSysMenu) {
520 e->accept();
521 emit popupOperationMenu(e->globalPos());
522 } else {
523 e->ignore();
524 }
525}
526#endif // QT_NO_CONTEXTMENU
527
528void QWorkspaceTitleBar::mouseReleaseEvent(QMouseEvent *e)
529{
530 Q_D(QWorkspaceTitleBar);
531 if (!d->window) {
532 // could have been deleted as part of a double click event on the sysmenu
533 return;
534 }
535 if (e->button() == Qt::LeftButton && d->pressed) {
536 if (style()->styleHint(QStyle::SH_TitleBar_NoBorder, 0, 0)
537 && !rect().adjusted(5, 5, -5, 0).contains(e->pos())) {
538 // propagate border events to the QWidgetResizeHandler
539 e->ignore();
540 d->buttonDown = QStyle::SC_None;
541 d->pressed = false;
542 return;
543 }
544 e->accept();
545 QStyleOptionTitleBar opt;
546 initStyleOption(&opt);
547 QStyle::SubControl ctrl = style()->hitTestComplexControl(QStyle::CC_TitleBar, &opt,
548 e->pos(), this);
549
550 if (d->pressed) {
551 update();
552 d->pressed = false;
553 d->moving = false;
554 }
555 if (ctrl == d->buttonDown) {
556 d->buttonDown = QStyle::SC_None;
557 switch(ctrl) {
558 case QStyle::SC_TitleBarShadeButton:
559 case QStyle::SC_TitleBarUnshadeButton:
560 if(d->flags & Qt::WindowShadeButtonHint)
561 emit doShade();
562 break;
563
564 case QStyle::SC_TitleBarNormalButton:
565 if(d->flags & Qt::WindowMinMaxButtonsHint)
566 emit doNormal();
567 break;
568
569 case QStyle::SC_TitleBarMinButton:
570 if(d->flags & Qt::WindowMinimizeButtonHint) {
571 if (d->window && d->window->isMinimized())
572 emit doNormal();
573 else
574 emit doMinimize();
575 }
576 break;
577
578 case QStyle::SC_TitleBarMaxButton:
579 if(d->flags & Qt::WindowMaximizeButtonHint) {
580 if(d->window && d->window->isMaximized())
581 emit doNormal();
582 else
583 emit doMaximize();
584 }
585 break;
586
587 case QStyle::SC_TitleBarCloseButton:
588 if(d->flags & Qt::WindowSystemMenuHint) {
589 d->buttonDown = QStyle::SC_None;
590 emit doClose();
591 return;
592 }
593 break;
594
595 default:
596 break;
597 }
598 }
599 } else {
600 e->ignore();
601 }
602}
603
604void QWorkspaceTitleBar::mouseMoveEvent(QMouseEvent *e)
605{
606 Q_D(QWorkspaceTitleBar);
607 e->ignore();
608 if ((e->buttons() & Qt::LeftButton) && style()->styleHint(QStyle::SH_TitleBar_NoBorder, 0, 0)
609 && !rect().adjusted(5, 5, -5, 0).contains(e->pos()) && !d->pressed) {
610 // propagate border events to the QWidgetResizeHandler
611 return;
612 }
613
614 QStyleOptionTitleBar opt;
615 initStyleOption(&opt);
616 QStyle::SubControl under_mouse = style()->hitTestComplexControl(QStyle::CC_TitleBar, &opt,
617 e->pos(), this);
618 if(under_mouse != d->lastControl) {
619 d->lastControl = under_mouse;
620 update();
621 }
622
623 switch (d->buttonDown) {
624 case QStyle::SC_None:
625 break;
626 case QStyle::SC_TitleBarSysMenu:
627 break;
628 case QStyle::SC_TitleBarLabel:
629 if (d->buttonDown == QStyle::SC_TitleBarLabel && d->movable && d->pressed) {
630 if (d->moving || (d->moveOffset - mapToParent(e->pos())).manhattanLength() >= 4) {
631 d->moving = true;
632 QPoint p = mapFromGlobal(e->globalPos());
633
634 QWidget *parent = d->window ? d->window->parentWidget() : 0;
635 if(parent && parent->inherits("QWorkspaceChild")) {
636 QWidget *workspace = parent->parentWidget();
637 p = workspace->mapFromGlobal(e->globalPos());
638 if (!workspace->rect().contains(p)) {
639 if (p.x() < 0)
640 p.rx() = 0;
641 if (p.y() < 0)
642 p.ry() = 0;
643 if (p.x() > workspace->width())
644 p.rx() = workspace->width();
645 if (p.y() > workspace->height())
646 p.ry() = workspace->height();
647 }
648 }
649
650 QPoint pp = p - d->moveOffset;
651 if (!parentWidget()->isMaximized())
652 parentWidget()->move(pp);
653 }
654 }
655 e->accept();
656 break;
657 default:
658 break;
659 }
660}
661
662bool QWorkspaceTitleBar::isTool() const
663{
664 Q_D(const QWorkspaceTitleBar);
665 return (d->flags & Qt::WindowType_Mask) == Qt::Tool;
666}
667
668// from qwidget.cpp
669extern QString qt_setWindowTitle_helperHelper(const QString &, const QWidget*);
670
671void QWorkspaceTitleBar::paintEvent(QPaintEvent *)
672{
673 Q_D(QWorkspaceTitleBar);
674 QStyleOptionTitleBar opt;
675 initStyleOption(&opt);
676 opt.subControls = QStyle::SC_TitleBarLabel;
677 opt.activeSubControls = d->buttonDown;
678
679 if (d->window && (d->flags & Qt::WindowTitleHint)) {
680 QString title = qt_setWindowTitle_helperHelper(opt.text, d->window);
681 int maxw = style()->subControlRect(QStyle::CC_TitleBar, &opt, QStyle::SC_TitleBarLabel,
682 this).width();
683 opt.text = fontMetrics().elidedText(title, Qt::ElideRight, maxw);
684 }
685
686 if (d->flags & Qt::WindowSystemMenuHint) {
687 opt.subControls |= QStyle::SC_TitleBarSysMenu | QStyle::SC_TitleBarCloseButton;
688 if (d->window && (d->flags & Qt::WindowShadeButtonHint)) {
689 if (d->window->isMinimized())
690 opt.subControls |= QStyle::SC_TitleBarUnshadeButton;
691 else
692 opt.subControls |= QStyle::SC_TitleBarShadeButton;
693 }
694 if (d->window && (d->flags & Qt::WindowMinMaxButtonsHint)) {
695 if(d->window && d->window->isMinimized())
696 opt.subControls |= QStyle::SC_TitleBarNormalButton;
697 else
698 opt.subControls |= QStyle::SC_TitleBarMinButton;
699 }
700 if (d->window && (d->flags & Qt::WindowMaximizeButtonHint) && !d->window->isMaximized())
701 opt.subControls |= QStyle::SC_TitleBarMaxButton;
702 }
703
704 QStyle::SubControl under_mouse = QStyle::SC_None;
705 under_mouse = style()->hitTestComplexControl(QStyle::CC_TitleBar, &opt,
706 mapFromGlobal(QCursor::pos()), this);
707 if ((d->buttonDown == under_mouse) && d->pressed) {
708 opt.state |= QStyle::State_Sunken;
709 } else if( autoRaise() && under_mouse != QStyle::SC_None && !d->pressed) {
710 opt.activeSubControls = under_mouse;
711 opt.state |= QStyle::State_MouseOver;
712 }
713 opt.palette.setCurrentColorGroup(usesActiveColor() ? QPalette::Active : QPalette::Inactive);
714
715 QPainter p(this);
716 style()->drawComplexControl(QStyle::CC_TitleBar, &opt, &p, this);
717}
718
719void QWorkspaceTitleBar::mouseDoubleClickEvent(QMouseEvent *e)
720{
721 Q_D(QWorkspaceTitleBar);
722 if (e->button() != Qt::LeftButton) {
723 e->ignore();
724 return;
725 }
726 e->accept();
727 QStyleOptionTitleBar opt;
728 initStyleOption(&opt);
729 switch (style()->hitTestComplexControl(QStyle::CC_TitleBar, &opt, e->pos(), this)) {
730 case QStyle::SC_TitleBarLabel:
731 emit doubleClicked();
732 break;
733
734 case QStyle::SC_TitleBarSysMenu:
735 if (d->flags & Qt::WindowSystemMenuHint)
736 emit doClose();
737 break;
738
739 default:
740 break;
741 }
742}
743
744void QWorkspaceTitleBar::leaveEvent(QEvent *)
745{
746 Q_D(QWorkspaceTitleBar);
747 d->lastControl = QStyle::SC_None;
748 if(autoRaise() && !d->pressed)
749 update();
750}
751
752void QWorkspaceTitleBar::enterEvent(QEvent *)
753{
754 Q_D(QWorkspaceTitleBar);
755 if(autoRaise() && !d->pressed)
756 update();
757 QEvent e(QEvent::Leave);
758 QApplication::sendEvent(parentWidget(), &e);
759}
760
761void QWorkspaceTitleBar::setActive(bool active)
762{
763 Q_D(QWorkspaceTitleBar);
764 if (d->act == active)
765 return ;
766
767 d->act = active;
768 update();
769}
770
771bool QWorkspaceTitleBar::isActive() const
772{
773 Q_D(const QWorkspaceTitleBar);
774 return d->act;
775}
776
777bool QWorkspaceTitleBar::usesActiveColor() const
778{
779 return (isActive() && isActiveWindow()) ||
780 (!window() && QWidget::window()->isActiveWindow());
781}
782
783QWidget *QWorkspaceTitleBar::window() const
784{
785 Q_D(const QWorkspaceTitleBar);
786 return d->window;
787}
788
789bool QWorkspaceTitleBar::event(QEvent *e)
790{
791 Q_D(QWorkspaceTitleBar);
792 if (e->type() == QEvent::ApplicationPaletteChange) {
793 d->readColors();
794 } else if (e->type() == QEvent::WindowActivate
795 || e->type() == QEvent::WindowDeactivate) {
796 if (d->act)
797 update();
798 }
799 return QWidget::event(e);
800}
801
802void QWorkspaceTitleBar::setMovable(bool b)
803{
804 Q_D(QWorkspaceTitleBar);
805 d->movable = b;
806}
807
808bool QWorkspaceTitleBar::isMovable() const
809{
810 Q_D(const QWorkspaceTitleBar);
811 return d->movable;
812}
813
814void QWorkspaceTitleBar::setAutoRaise(bool b)
815{
816 Q_D(QWorkspaceTitleBar);
817 d->autoraise = b;
818}
819
820bool QWorkspaceTitleBar::autoRaise() const
821{
822 Q_D(const QWorkspaceTitleBar);
823 return d->autoraise;
824}
825
826QSize QWorkspaceTitleBar::sizeHint() const
827{
828 ensurePolished();
829 QStyleOptionTitleBar opt;
830 initStyleOption(&opt);
831 QRect menur = style()->subControlRect(QStyle::CC_TitleBar, &opt,
832 QStyle::SC_TitleBarSysMenu, this);
833 return QSize(menur.width(), style()->pixelMetric(QStyle::PM_TitleBarHeight, &opt, this));
834}
835
836/*!
837 \class QWorkspace
838 \obsolete
839 \brief The QWorkspace widget provides a workspace window that can be
840 used in an MDI application.
841 \ingroup application
842
843 This class is deprecated. Use QMdiArea instead.
844
845 Multiple Document Interface (MDI) applications are typically
846 composed of a main window containing a menu bar, a toolbar, and
847 a central QWorkspace widget. The workspace itself is used to display
848 a number of child windows, each of which is a widget.
849
850 The workspace itself is an ordinary Qt widget. It has a standard
851 constructor that takes a parent widget.
852 Workspaces can be placed in any layout, but are typically given
853 as the central widget in a QMainWindow:
854
855 \snippet doc/src/snippets/code/src_gui_widgets_qworkspace.cpp 0
856
857 Child windows (MDI windows) are standard Qt widgets that are
858 inserted into the workspace with addWindow(). As with top-level
859 widgets, you can call functions such as show(), hide(),
860 showMaximized(), and setWindowTitle() on a child window to change
861 its appearance within the workspace. You can also provide widget
862 flags to determine the layout of the decoration or the behavior of
863 the widget itself.
864
865 To change or retrieve the geometry of a child window, you must
866 operate on its parentWidget(). The parentWidget() provides
867 access to the decorated frame that contains the child window
868 widget. When a child window is maximised, its decorated frame
869 is hidden. If the top-level widget contains a menu bar, it will display
870 the maximised window's operations menu to the left of the menu
871 entries, and the window's controls to the right.
872
873 A child window becomes active when it gets the keyboard focus,
874 or when setFocus() is called. The user can activate a window by moving
875 focus in the usual ways, for example by clicking a window or by pressing
876 Tab. The workspace emits a signal windowActivated() when the active
877 window changes, and the function activeWindow() returns a pointer to the
878 active child window, or 0 if no window is active.
879
880 The convenience function windowList() returns a list of all child
881 windows. This information could be used in a popup menu
882 containing a list of windows, for example. This feature is also
883 available as part of the \l{Window Menu} Solution.
884
885 QWorkspace provides two built-in layout strategies for child
886 windows: cascade() and tile(). Both are slots so you can easily
887 connect menu entries to them.
888
889 \table
890 \row \o \inlineimage mdi-cascade.png
891 \o \inlineimage mdi-tile.png
892 \endtable
893
894 If you want your users to be able to work with child windows
895 larger than the visible workspace area, set the scrollBarsEnabled
896 property to true.
897
898 \sa QDockWidget, {MDI Example}
899*/
900
901
902class QWorkspaceChild : public QWidget
903{
904 Q_OBJECT
905
906 friend class QWorkspacePrivate;
907 friend class QWorkspace;
908 friend class QWorkspaceTitleBar;
909
910public:
911 QWorkspaceChild(QWidget* window, QWorkspace* parent=0, Qt::WindowFlags flags = 0);
912 ~QWorkspaceChild();
913
914 void setActive(bool);
915 bool isActive() const;
916
917 void adjustToFullscreen();
918
919 QWidget* windowWidget() const;
920 QWidget* iconWidget() const;
921
922 void doResize();
923 void doMove();
924
925 QSize sizeHint() const;
926 QSize minimumSizeHint() const;
927
928 QSize baseSize() const;
929
930 int frameWidth() const;
931
932 void show();
933
934 bool isWindowOrIconVisible() const;
935
936signals:
937 void showOperationMenu();
938 void popupOperationMenu(const QPoint&);
939
940public slots:
941 void activate();
942 void showMinimized();
943 void showMaximized();
944 void showNormal();
945 void showShaded();
946 void internalRaise();
947 void titleBarDoubleClicked();
948
949protected:
950 void enterEvent(QEvent *);
951 void leaveEvent(QEvent *);
952 void childEvent(QChildEvent*);
953 void resizeEvent(QResizeEvent *);
954 void moveEvent(QMoveEvent *);
955 bool eventFilter(QObject *, QEvent *);
956
957 void paintEvent(QPaintEvent *);
958 void changeEvent(QEvent *);
959
960private:
961 void updateMask();
962
963 Q_DISABLE_COPY(QWorkspaceChild)
964
965 QWidget *childWidget;
966 QWidgetResizeHandler *widgetResizeHandler;
967 QWorkspaceTitleBar *titlebar;
968 QPointer<QWorkspaceTitleBar> iconw;
969 QSize windowSize;
970 QSize shadeRestore;
971 QSize shadeRestoreMin;
972 bool act :1;
973 bool shademode :1;
974};
975
976int QWorkspaceChild::frameWidth() const
977{
978 return contentsRect().left();
979}
980
981
982
983class QWorkspacePrivate : public QWidgetPrivate {
984 Q_DECLARE_PUBLIC(QWorkspace)
985public:
986 QWorkspaceChild* active;
987 QList<QWorkspaceChild *> windows;
988 QList<QWorkspaceChild *> focus;
989 QList<QWidget *> icons;
990 QWorkspaceChild* maxWindow;
991 QRect maxRestore;
992 QPointer<QMDIControl> maxcontrols;
993 QPointer<QMenuBar> maxmenubar;
994 QHash<int, const char*> shortcutMap;
995
996 int px;
997 int py;
998 QWidget *becomeActive;
999 QPointer<QLabel> maxtools;
1000 QString topTitle;
1001
1002 QMenu *popup, *toolPopup;
1003 enum WSActs { RestoreAct, MoveAct, ResizeAct, MinimizeAct, MaximizeAct, CloseAct, StaysOnTopAct, ShadeAct, NCountAct };
1004 QAction *actions[NCountAct];
1005
1006 QScrollBar *vbar, *hbar;
1007 QWidget *corner;
1008 int yoffset, xoffset;
1009 QBrush background;
1010
1011 void init();
1012 void insertIcon(QWidget* w);
1013 void removeIcon(QWidget* w);
1014 void place(QWidget*);
1015
1016 QWorkspaceChild* findChild(QWidget* w);
1017 void showMaximizeControls();
1018 void hideMaximizeControls();
1019 void activateWindow(QWidget* w, bool change_focus = true);
1020 void hideChild(QWorkspaceChild *c);
1021 void showWindow(QWidget* w);
1022 void maximizeWindow(QWidget* w);
1023 void minimizeWindow(QWidget* w);
1024 void normalizeWindow(QWidget* w);
1025
1026 QRect updateWorkspace();
1027
1028private:
1029 void _q_normalizeActiveWindow();
1030 void _q_minimizeActiveWindow();
1031 void _q_showOperationMenu();
1032 void _q_popupOperationMenu(const QPoint&);
1033 void _q_operationMenuActivated(QAction *);
1034 void _q_scrollBarChanged();
1035 void _q_updateActions();
1036 bool inTitleChange;
1037};
1038
1039static bool isChildOf(QWidget * child, QWidget * parent)
1040{
1041 if (!parent || !child)
1042 return false;
1043 QWidget * w = child;
1044 while(w && w != parent)
1045 w = w->parentWidget();
1046 return w != 0;
1047}
1048
1049/*!
1050 Constructs a workspace with the given \a parent.
1051*/
1052QWorkspace::QWorkspace(QWidget *parent)
1053 : QWidget(*new QWorkspacePrivate, parent, 0)
1054{
1055 Q_D(QWorkspace);
1056 d->init();
1057}
1058
1059#ifdef QT3_SUPPORT
1060/*!
1061 Use one of the constructors that doesn't take the \a name
1062 argument and then use setObjectName() instead.
1063*/
1064QWorkspace::QWorkspace(QWidget *parent, const char *name)
1065 : QWidget(*new QWorkspacePrivate, parent, 0)
1066{
1067 Q_D(QWorkspace);
1068 setObjectName(QString::fromAscii(name));
1069 d->init();
1070}
1071#endif // QT3_SUPPORT
1072
1073/*!
1074 \internal
1075*/
1076void
1077QWorkspacePrivate::init()
1078{
1079 Q_Q(QWorkspace);
1080
1081 maxcontrols = 0;
1082 active = 0;
1083 maxWindow = 0;
1084 maxtools = 0;
1085 px = 0;
1086 py = 0;
1087 becomeActive = 0;
1088 popup = new QMenu(q);
1089 toolPopup = new QMenu(q);
1090 popup->setObjectName(QLatin1String("qt_internal_mdi_popup"));
1091 toolPopup->setObjectName(QLatin1String("qt_internal_mdi_tool_popup"));
1092
1093 actions[QWorkspacePrivate::RestoreAct] = new QAction(QIcon(q->style()->standardPixmap(QStyle::SP_TitleBarNormalButton, 0, q)),
1094 QWorkspace::tr("&Restore"), q);
1095 actions[QWorkspacePrivate::MoveAct] = new QAction(QWorkspace::tr("&Move"), q);
1096 actions[QWorkspacePrivate::ResizeAct] = new QAction(QWorkspace::tr("&Size"), q);
1097 actions[QWorkspacePrivate::MinimizeAct] = new QAction(QIcon(q->style()->standardPixmap(QStyle::SP_TitleBarMinButton, 0, q)),
1098 QWorkspace::tr("Mi&nimize"), q);
1099 actions[QWorkspacePrivate::MaximizeAct] = new QAction(QIcon(q->style()->standardPixmap(QStyle::SP_TitleBarMaxButton, 0, q)),
1100 QWorkspace::tr("Ma&ximize"), q);
1101 actions[QWorkspacePrivate::CloseAct] = new QAction(QIcon(q->style()->standardPixmap(QStyle::SP_TitleBarCloseButton, 0, q)),
1102 QWorkspace::tr("&Close")
1103#ifndef QT_NO_SHORTCUT
1104 +QLatin1Char('\t')+(QString)QKeySequence(Qt::CTRL+Qt::Key_F4)
1105#endif
1106 ,q);
1107 QObject::connect(actions[QWorkspacePrivate::CloseAct], SIGNAL(triggered()), q, SLOT(closeActiveWindow()));
1108 actions[QWorkspacePrivate::StaysOnTopAct] = new QAction(QWorkspace::tr("Stay on &Top"), q);
1109 actions[QWorkspacePrivate::StaysOnTopAct]->setChecked(true);
1110 actions[QWorkspacePrivate::ShadeAct] = new QAction(QIcon(q->style()->standardPixmap(QStyle::SP_TitleBarShadeButton, 0, q)),
1111 QWorkspace::tr("Sh&ade"), q);
1112
1113 QObject::connect(popup, SIGNAL(aboutToShow()), q, SLOT(_q_updateActions()));
1114 QObject::connect(popup, SIGNAL(triggered(QAction*)), q, SLOT(_q_operationMenuActivated(QAction*)));
1115 popup->addAction(actions[QWorkspacePrivate::RestoreAct]);
1116 popup->addAction(actions[QWorkspacePrivate::MoveAct]);
1117 popup->addAction(actions[QWorkspacePrivate::ResizeAct]);
1118 popup->addAction(actions[QWorkspacePrivate::MinimizeAct]);
1119 popup->addAction(actions[QWorkspacePrivate::MaximizeAct]);
1120 popup->addSeparator();
1121 popup->addAction(actions[QWorkspacePrivate::CloseAct]);
1122
1123 QObject::connect(toolPopup, SIGNAL(aboutToShow()), q, SLOT(_q_updateActions()));
1124 QObject::connect(toolPopup, SIGNAL(triggered(QAction*)), q, SLOT(_q_operationMenuActivated(QAction*)));
1125 toolPopup->addAction(actions[QWorkspacePrivate::MoveAct]);
1126 toolPopup->addAction(actions[QWorkspacePrivate::ResizeAct]);
1127 toolPopup->addAction(actions[QWorkspacePrivate::StaysOnTopAct]);
1128 toolPopup->addSeparator();
1129 toolPopup->addAction(actions[QWorkspacePrivate::ShadeAct]);
1130 toolPopup->addAction(actions[QWorkspacePrivate::CloseAct]);
1131
1132#ifndef QT_NO_SHORTCUT
1133 // Set up shortcut bindings (id -> slot), most used first
1134 QList <QKeySequence> shortcuts = QKeySequence::keyBindings(QKeySequence::NextChild);
1135 foreach (const QKeySequence &seq, shortcuts)
1136 shortcutMap.insert(q->grabShortcut(seq), "activateNextWindow");
1137
1138 shortcuts = QKeySequence::keyBindings(QKeySequence::PreviousChild);
1139 foreach (const QKeySequence &seq, shortcuts)
1140 shortcutMap.insert(q->grabShortcut(seq), "activatePreviousWindow");
1141
1142 shortcuts = QKeySequence::keyBindings(QKeySequence::Close);
1143 foreach (const QKeySequence &seq, shortcuts)
1144 shortcutMap.insert(q->grabShortcut(seq), "closeActiveWindow");
1145
1146 shortcutMap.insert(q->grabShortcut(QKeySequence(QLatin1String("ALT+-"))), "_q_showOperationMenu");
1147#endif // QT_NO_SHORTCUT
1148
1149 q->setBackgroundRole(QPalette::Dark);
1150 q->setAutoFillBackground(true);
1151 q->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding));
1152
1153 hbar = vbar = 0;
1154 corner = 0;
1155 xoffset = yoffset = 0;
1156
1157 q->window()->installEventFilter(q);
1158
1159 inTitleChange = false;
1160 updateWorkspace();
1161}
1162
1163/*!
1164 Destroys the workspace and frees any allocated resources.
1165*/
1166
1167QWorkspace::~QWorkspace()
1168{
1169}
1170
1171/*! \reimp */
1172QSize QWorkspace::sizeHint() const
1173{
1174 QSize s(QApplication::desktop()->size());
1175 return QSize(s.width()*2/3, s.height()*2/3);
1176}
1177
1178
1179#ifdef QT3_SUPPORT
1180/*!
1181 Sets the background color to \a c.
1182 Use setBackground() instead.
1183*/
1184void QWorkspace::setPaletteBackgroundColor(const QColor & c)
1185{
1186 setBackground(c);
1187}
1188
1189/*!
1190 Sets the background pixmap to \a pm.
1191 Use setBackground() instead.
1192*/
1193void QWorkspace::setPaletteBackgroundPixmap(const QPixmap & pm)
1194{
1195 setBackground(pm);
1196}
1197#endif // QT3_SUPPORT
1198
1199/*!
1200 \property QWorkspace::background
1201 \brief the workspace's background
1202*/
1203QBrush QWorkspace::background() const
1204{
1205 Q_D(const QWorkspace);
1206 if (d->background.style() == Qt::NoBrush)
1207 return palette().dark();
1208 return d->background;
1209}
1210
1211void QWorkspace::setBackground(const QBrush &background)
1212{
1213 Q_D(QWorkspace);
1214 d->background = background;
1215 setAttribute(Qt::WA_OpaquePaintEvent, background.style() == Qt::NoBrush);
1216 update();
1217}
1218
1219/*!
1220 Adds widget \a w as new sub window to the workspace. If \a flags
1221 are non-zero, they will override the flags set on the widget.
1222
1223 Returns the widget used for the window frame.
1224
1225 To remove the widget \a w from the workspace, simply call
1226 setParent() with the new parent (or 0 to make it a stand-alone
1227 window).
1228*/
1229QWidget * QWorkspace::addWindow(QWidget *w, Qt::WindowFlags flags)
1230{
1231 Q_D(QWorkspace);
1232 if (!w)
1233 return 0;
1234
1235 w->setAutoFillBackground(true);
1236
1237 QWidgetPrivate::adjustFlags(flags);
1238
1239#if 0
1240 bool wasMaximized = w->isMaximized();
1241 bool wasMinimized = w->isMinimized();
1242#endif
1243 bool hasSize = w->testAttribute(Qt::WA_Resized);
1244 int x = w->x();
1245 int y = w->y();
1246 bool hasPos = w->testAttribute(Qt::WA_Moved);
1247 QSize s = w->size().expandedTo(qSmartMinSize(w));
1248 if (!hasSize && w->sizeHint().isValid())
1249 w->adjustSize();
1250
1251 QWorkspaceChild* child = new QWorkspaceChild(w, this, flags);
1252 child->setObjectName(QLatin1String("qt_workspacechild"));
1253 child->installEventFilter(this);
1254
1255 connect(child, SIGNAL(popupOperationMenu(QPoint)),
1256 this, SLOT(_q_popupOperationMenu(QPoint)));
1257 connect(child, SIGNAL(showOperationMenu()),
1258 this, SLOT(_q_showOperationMenu()));
1259 d->windows.append(child);
1260 if (child->isVisibleTo(this))
1261 d->focus.append(child);
1262 child->internalRaise();
1263
1264 if (!hasPos)
1265 d->place(child);
1266 if (!hasSize)
1267 child->adjustSize();
1268 if (hasPos)
1269 child->move(x, y);
1270
1271 return child;
1272
1273#if 0
1274 if (wasMaximized)
1275 w->showMaximized();
1276 else if (wasMinimized)
1277 w->showMinimized();
1278 else if (!hasBeenHidden)
1279 d->activateWindow(w);
1280
1281 d->updateWorkspace();
1282 return child;
1283#endif
1284}
1285
1286/*! \reimp */
1287void QWorkspace::childEvent(QChildEvent * e)
1288{
1289 Q_D(QWorkspace);
1290 if (e->removed()) {
1291 if (d->windows.removeAll(static_cast<QWorkspaceChild*>(e->child()))) {
1292 d->focus.removeAll(static_cast<QWorkspaceChild*>(e->child()));
1293 if (d->maxWindow == e->child())
1294 d->maxWindow = 0;
1295 d->updateWorkspace();
1296 }
1297 }
1298}
1299
1300/*! \reimp */
1301#ifndef QT_NO_WHEELEVENT
1302void QWorkspace::wheelEvent(QWheelEvent *e)
1303{
1304 Q_D(QWorkspace);
1305 if (!scrollBarsEnabled())
1306 return;
1307 // the scroll bars are children of the workspace, so if we receive
1308 // a wheel event we redirect to the scroll bars using a direct event
1309 // call, /not/ using sendEvent() because if the scroll bar ignores the
1310 // event QApplication::sendEvent() will propagate the event to the parent widget,
1311 // which is us, who /just/ sent it.
1312 if (d->vbar && d->vbar->isVisible() && !(e->modifiers() & Qt::AltModifier))
1313 d->vbar->event(e);
1314 else if (d->hbar && d->hbar->isVisible())
1315 d->hbar->event(e);
1316}
1317#endif
1318
1319void QWorkspacePrivate::activateWindow(QWidget* w, bool change_focus)
1320{
1321 Q_Q(QWorkspace);
1322 if (!w) {
1323 active = 0;
1324 emit q->windowActivated(0);
1325 return;
1326 }
1327 if (!q->isVisible()) {
1328 becomeActive = w;
1329 return;
1330 }
1331
1332 if (active && active->windowWidget() == w) {
1333 if (!isChildOf(q->focusWidget(), w)) // child window does not have focus
1334 active->setActive(true);
1335 return;
1336 }
1337
1338 active = 0;
1339 // First deactivate all other workspace clients
1340 QList<QWorkspaceChild *>::Iterator it(windows.begin());
1341 while (it != windows.end()) {
1342 QWorkspaceChild* c = *it;
1343 ++it;
1344 if (c->windowWidget() == w)
1345 active = c;
1346 else
1347 c->setActive(false);
1348 }
1349
1350 if (!active)
1351 return;
1352
1353 // Then activate the new one, so the focus is stored correctly
1354 active->setActive(true);
1355
1356 if (!active)
1357 return;
1358
1359 if (maxWindow && maxWindow != active && active->windowWidget() &&
1360 (active->windowWidget()->windowFlags() & Qt::WindowMaximizeButtonHint))
1361 active->showMaximized();
1362
1363 active->internalRaise();
1364
1365 if (change_focus) {
1366 int from = focus.indexOf(active);
1367 if (from >= 0)
1368 focus.move(from, focus.size() - 1);
1369 }
1370
1371 updateWorkspace();
1372 emit q->windowActivated(w);
1373}
1374
1375
1376/*!
1377 Returns a pointer to the widget corresponding to the active child
1378 window, or 0 if no window is active.
1379
1380 \sa setActiveWindow()
1381*/
1382QWidget* QWorkspace::activeWindow() const
1383{
1384 Q_D(const QWorkspace);
1385 return d->active? d->active->windowWidget() : 0;
1386}
1387
1388/*!
1389 Makes the child window that contains \a w the active child window.
1390
1391 \sa activeWindow()
1392*/
1393void QWorkspace::setActiveWindow(QWidget *w)
1394{
1395 Q_D(QWorkspace);
1396 d->activateWindow(w, true);
1397 if (w && w->isMinimized())
1398 w->setWindowState(w->windowState() & ~Qt::WindowMinimized);
1399}
1400
1401void QWorkspacePrivate::place(QWidget *w)
1402{
1403 Q_Q(QWorkspace);
1404
1405 QList<QWidget *> widgets;
1406 for (QList<QWorkspaceChild *>::Iterator it(windows.begin()); it != windows.end(); ++it)
1407 if (*it != w)
1408 widgets.append(*it);
1409
1410 int overlap, minOverlap = 0;
1411 int possible;
1412
1413 QRect r1(0, 0, 0, 0);
1414 QRect r2(0, 0, 0, 0);
1415 QRect maxRect = q->rect();
1416 int x = maxRect.left(), y = maxRect.top();
1417 QPoint wpos(maxRect.left(), maxRect.top());
1418
1419 bool firstPass = true;
1420
1421 do {
1422 if (y + w->height() > maxRect.bottom()) {
1423 overlap = -1;
1424 } else if(x + w->width() > maxRect.right()) {
1425 overlap = -2;
1426 } else {
1427 overlap = 0;
1428
1429 r1.setRect(x, y, w->width(), w->height());
1430
1431 QWidget *l;
1432 QList<QWidget *>::Iterator it(widgets.begin());
1433 while (it != widgets.end()) {
1434 l = *it;
1435 ++it;
1436
1437 if (maxWindow == l)
1438 r2 = QStyle::visualRect(q->layoutDirection(), maxRect, maxRestore);
1439 else
1440 r2 = QStyle::visualRect(q->layoutDirection(), maxRect,
1441 QRect(l->x(), l->y(), l->width(), l->height()));
1442
1443 if (r2.intersects(r1)) {
1444 r2.setCoords(qMax(r1.left(), r2.left()),
1445 qMax(r1.top(), r2.top()),
1446 qMin(r1.right(), r2.right()),
1447 qMin(r1.bottom(), r2.bottom())
1448 );
1449
1450 overlap += (r2.right() - r2.left()) *
1451 (r2.bottom() - r2.top());
1452 }
1453 }
1454 }
1455
1456 if (overlap == 0) {
1457 wpos = QPoint(x, y);
1458 break;
1459 }
1460
1461 if (firstPass) {
1462 firstPass = false;
1463 minOverlap = overlap;
1464 } else if (overlap >= 0 && overlap < minOverlap) {
1465 minOverlap = overlap;
1466 wpos = QPoint(x, y);
1467 }
1468
1469 if (overlap > 0) {
1470 possible = maxRect.right();
1471 if (possible - w->width() > x) possible -= w->width();
1472
1473 QWidget *l;
1474 QList<QWidget *>::Iterator it(widgets.begin());
1475 while (it != widgets.end()) {
1476 l = *it;
1477 ++it;
1478 if (maxWindow == l)
1479 r2 = QStyle::visualRect(q->layoutDirection(), maxRect, maxRestore);
1480 else
1481 r2 = QStyle::visualRect(q->layoutDirection(), maxRect,
1482 QRect(l->x(), l->y(), l->width(), l->height()));
1483
1484 if((y < r2.bottom()) && (r2.top() < w->height() + y)) {
1485 if(r2.right() > x)
1486 possible = possible < r2.right() ?
1487 possible : r2.right();
1488
1489 if(r2.left() - w->width() > x)
1490 possible = possible < r2.left() - w->width() ?
1491 possible : r2.left() - w->width();
1492 }
1493 }
1494
1495 x = possible;
1496 } else if (overlap == -2) {
1497 x = maxRect.left();
1498 possible = maxRect.bottom();
1499
1500 if (possible - w->height() > y) possible -= w->height();
1501
1502 QWidget *l;
1503 QList<QWidget *>::Iterator it(widgets.begin());
1504 while (it != widgets.end()) {
1505 l = *it;
1506 ++it;
1507 if (maxWindow == l)
1508 r2 = QStyle::visualRect(q->layoutDirection(), maxRect, maxRestore);
1509 else
1510 r2 = QStyle::visualRect(q->layoutDirection(), maxRect,
1511 QRect(l->x(), l->y(), l->width(), l->height()));
1512
1513 if(r2.bottom() > y)
1514 possible = possible < r2.bottom() ?
1515 possible : r2.bottom();
1516
1517 if(r2.top() - w->height() > y)
1518 possible = possible < r2.top() - w->height() ?
1519 possible : r2.top() - w->height();
1520 }
1521
1522 y = possible;
1523 }
1524 }
1525 while(overlap != 0 && overlap != -1);
1526
1527 QRect resultRect = w->geometry();
1528 resultRect.moveTo(wpos);
1529 w->setGeometry(QStyle::visualRect(q->layoutDirection(), maxRect, resultRect));
1530 updateWorkspace();
1531}
1532
1533
1534void QWorkspacePrivate::insertIcon(QWidget* w)
1535{
1536 Q_Q(QWorkspace);
1537 if (!w || icons.contains(w))
1538 return;
1539 icons.append(w);
1540 if (w->parentWidget() != q) {
1541 w->setParent(q, 0);
1542 w->move(0,0);
1543 }
1544 QRect cr = updateWorkspace();
1545 int x = 0;
1546 int y = cr.height() - w->height();
1547
1548 QList<QWidget *>::Iterator it(icons.begin());
1549 while (it != icons.end()) {
1550 QWidget* i = *it;
1551 ++it;
1552 if (x > 0 && x + i->width() > cr.width()){
1553 x = 0;
1554 y -= i->height();
1555 }
1556
1557 if (i != w &&
1558 i->geometry().intersects(QRect(x, y, w->width(), w->height())))
1559 x += i->width();
1560 }
1561 w->move(x, y);
1562
1563 if (q->isVisibleTo(q->parentWidget())) {
1564 w->show();
1565 w->lower();
1566 }
1567 updateWorkspace();
1568}
1569
1570
1571void QWorkspacePrivate::removeIcon(QWidget* w)
1572{
1573 if (icons.removeAll(w))
1574 w->hide();
1575}
1576
1577
1578/*! \reimp */
1579void QWorkspace::resizeEvent(QResizeEvent *)
1580{
1581 Q_D(QWorkspace);
1582 if (d->maxWindow) {
1583 d->maxWindow->adjustToFullscreen();
1584 if (d->maxWindow->windowWidget())
1585 d->maxWindow->windowWidget()->overrideWindowState(Qt::WindowMaximized);
1586 }
1587 d->updateWorkspace();
1588}
1589
1590/*! \reimp */
1591void QWorkspace::showEvent(QShowEvent *e)
1592{
1593 Q_D(QWorkspace);
1594 if (d->maxWindow)
1595 d->showMaximizeControls();
1596 QWidget::showEvent(e);
1597 if (d->becomeActive) {
1598 d->activateWindow(d->becomeActive);
1599 d->becomeActive = 0;
1600 } else if (d->windows.count() > 0 && !d->active) {
1601 d->activateWindow(d->windows.first()->windowWidget());
1602 }
1603
1604// // force a frame repaint - this is a workaround for what seems to be a bug
1605// // introduced when changing the QWidget::show() implementation. Might be
1606// // a windows bug as well though.
1607// for (int i = 0; i < d->windows.count(); ++i) {
1608// QWorkspaceChild* c = d->windows.at(i);
1609// c->update(c->rect());
1610// }
1611
1612 d->updateWorkspace();
1613}
1614
1615/*! \reimp */
1616void QWorkspace::hideEvent(QHideEvent *)
1617{
1618 Q_D(QWorkspace);
1619 if (!isVisible())
1620 d->hideMaximizeControls();
1621}
1622
1623/*! \reimp */
1624void QWorkspace::paintEvent(QPaintEvent *)
1625{
1626 Q_D(QWorkspace);
1627
1628 if (d->background.style() != Qt::NoBrush) {
1629 QPainter p(this);
1630 p.fillRect(0, 0, width(), height(), d->background);
1631 }
1632}
1633
1634void QWorkspacePrivate::minimizeWindow(QWidget* w)
1635{
1636 QWorkspaceChild* c = findChild(w);
1637
1638 if (!w || !(w->windowFlags() & Qt::WindowMinimizeButtonHint))
1639 return;
1640
1641 if (c) {
1642 bool wasMax = false;
1643 if (c == maxWindow) {
1644 wasMax = true;
1645 maxWindow = 0;
1646 hideMaximizeControls();
1647 for (QList<QWorkspaceChild *>::Iterator it(windows.begin()); it != windows.end(); ++it) {
1648 QWorkspaceChild* c = *it;
1649 if (c->titlebar)
1650 c->titlebar->setMovable(true);
1651 c->widgetResizeHandler->setActive(true);
1652 }
1653 }
1654 c->hide();
1655 if (wasMax)
1656 c->setGeometry(maxRestore);
1657 if (!focus.contains(c))
1658 focus.append(c);
1659 insertIcon(c->iconWidget());
1660
1661 if (!maxWindow)
1662 activateWindow(w);
1663
1664 updateWorkspace();
1665
1666 w->overrideWindowState(Qt::WindowMinimized);
1667 c->overrideWindowState(Qt::WindowMinimized);
1668 }
1669}
1670
1671void QWorkspacePrivate::normalizeWindow(QWidget* w)
1672{
1673 Q_Q(QWorkspace);
1674 QWorkspaceChild* c = findChild(w);
1675 if (!w)
1676 return;
1677 if (c) {
1678 w->overrideWindowState(Qt::WindowNoState);
1679 hideMaximizeControls();
1680 if (!maxmenubar || q->style()->styleHint(QStyle::SH_Workspace_FillSpaceOnMaximize, 0, q) || !maxWindow) {
1681 if (w->minimumSize() != w->maximumSize())
1682 c->widgetResizeHandler->setActive(true);
1683 if (c->titlebar)
1684 c->titlebar->setMovable(true);
1685 }
1686 w->overrideWindowState(Qt::WindowNoState);
1687 c->overrideWindowState(Qt::WindowNoState);
1688
1689 if (c == maxWindow) {
1690 c->setGeometry(maxRestore);
1691 maxWindow = 0;
1692 } else {
1693 if (c->iconw)
1694 removeIcon(c->iconw->parentWidget());
1695 c->show();
1696 }
1697
1698 hideMaximizeControls();
1699 for (QList<QWorkspaceChild *>::Iterator it(windows.begin()); it != windows.end(); ++it) {
1700 QWorkspaceChild* c = *it;
1701 if (c->titlebar)
1702 c->titlebar->setMovable(true);
1703 if (c->childWidget && c->childWidget->minimumSize() != c->childWidget->maximumSize())
1704 c->widgetResizeHandler->setActive(true);
1705 }
1706 activateWindow(w, true);
1707 updateWorkspace();
1708 }
1709}
1710
1711void QWorkspacePrivate::maximizeWindow(QWidget* w)
1712{
1713 Q_Q(QWorkspace);
1714 QWorkspaceChild* c = findChild(w);
1715
1716 if (!w || !(w->windowFlags() & Qt::WindowMaximizeButtonHint))
1717 return;
1718
1719 if (!c || c == maxWindow)
1720 return;
1721
1722 bool updatesEnabled = q->updatesEnabled();
1723 q->setUpdatesEnabled(false);
1724
1725 if (c->iconw && icons.contains(c->iconw->parentWidget()))
1726 normalizeWindow(w);
1727 QRect r(c->geometry());
1728 QWorkspaceChild *oldMaxWindow = maxWindow;
1729 maxWindow = c;
1730
1731 showMaximizeControls();
1732
1733 c->adjustToFullscreen();
1734 c->show();
1735 c->internalRaise();
1736 if (oldMaxWindow != c) {
1737 if (oldMaxWindow) {
1738 oldMaxWindow->setGeometry(maxRestore);
1739 oldMaxWindow->overrideWindowState(Qt::WindowNoState);
1740 if(oldMaxWindow->windowWidget())
1741 oldMaxWindow->windowWidget()->overrideWindowState(Qt::WindowNoState);
1742 }
1743 maxRestore = r;
1744 }
1745
1746 activateWindow(w);
1747
1748 if(!maxmenubar || q->style()->styleHint(QStyle::SH_Workspace_FillSpaceOnMaximize, 0, q)) {
1749 if (!active && becomeActive) {
1750 active = (QWorkspaceChild*)becomeActive->parentWidget();
1751 active->setActive(true);
1752 becomeActive = 0;
1753 emit q->windowActivated(active->windowWidget());
1754 }
1755 c->widgetResizeHandler->setActive(false);
1756 if (c->titlebar)
1757 c->titlebar->setMovable(false);
1758 }
1759 updateWorkspace();
1760
1761 w->overrideWindowState(Qt::WindowMaximized);
1762 c->overrideWindowState(Qt::WindowMaximized);
1763 q->setUpdatesEnabled(updatesEnabled);
1764}
1765
1766void QWorkspacePrivate::showWindow(QWidget* w)
1767{
1768 if (w->isMinimized() && (w->windowFlags() & Qt::WindowMinimizeButtonHint))
1769 minimizeWindow(w);
1770 else if ((maxWindow || w->isMaximized()) && w->windowFlags() & Qt::WindowMaximizeButtonHint)
1771 maximizeWindow(w);
1772 else if (w->windowFlags() & Qt::WindowMaximizeButtonHint)
1773 normalizeWindow(w);
1774 else
1775 w->parentWidget()->show();
1776 if (maxWindow)
1777 maxWindow->internalRaise();
1778 updateWorkspace();
1779}
1780
1781
1782QWorkspaceChild* QWorkspacePrivate::findChild(QWidget* w)
1783{
1784 QList<QWorkspaceChild *>::Iterator it(windows.begin());
1785 while (it != windows.end()) {
1786 QWorkspaceChild* c = *it;
1787 ++it;
1788 if (c->windowWidget() == w)
1789 return c;
1790 }
1791 return 0;
1792}
1793
1794/*!
1795 Returns a list of all visible or minimized child windows. If \a
1796 order is CreationOrder (the default), the windows are listed in
1797 the order in which they were inserted into the workspace. If \a
1798 order is StackingOrder, the windows are listed in their stacking
1799 order, with the topmost window as the last item in the list.
1800*/
1801QWidgetList QWorkspace::windowList(WindowOrder order) const
1802{
1803 Q_D(const QWorkspace);
1804 QWidgetList windows;
1805 if (order == StackingOrder) {
1806 QObjectList cl = children();
1807 for (int i = 0; i < cl.size(); ++i) {
1808 QWorkspaceChild *c = qobject_cast<QWorkspaceChild*>(cl.at(i));
1809 if (c && c->isWindowOrIconVisible())
1810 windows.append(c->windowWidget());
1811 }
1812 } else {
1813 QList<QWorkspaceChild *>::ConstIterator it(d->windows.begin());
1814 while (it != d->windows.end()) {
1815 QWorkspaceChild* c = *it;
1816 ++it;
1817 if (c && c->isWindowOrIconVisible())
1818 windows.append(c->windowWidget());
1819 }
1820 }
1821 return windows;
1822}
1823
1824
1825/*! \reimp */
1826bool QWorkspace::event(QEvent *e)
1827{
1828#ifndef QT_NO_SHORTCUT
1829 Q_D(QWorkspace);
1830 if (e->type() == QEvent::Shortcut) {
1831 QShortcutEvent *se = static_cast<QShortcutEvent *>(e);
1832 const char *theSlot = d->shortcutMap.value(se->shortcutId(), 0);
1833 if (theSlot)
1834 QMetaObject::invokeMethod(this, theSlot);
1835 } else
1836#endif
1837 if (e->type() == QEvent::FocusIn || e->type() == QEvent::FocusOut){
1838 return true;
1839 }
1840 return QWidget::event(e);
1841}
1842
1843/*! \reimp */
1844bool QWorkspace::eventFilter(QObject *o, QEvent * e)
1845{
1846 Q_D(QWorkspace);
1847 static QTime* t = 0;
1848 static QWorkspace* tc = 0;
1849 if (o == d->maxtools) {
1850 switch (e->type()) {
1851 case QEvent::MouseButtonPress:
1852 {
1853 QMenuBar* b = (QMenuBar*)o->parent();
1854 if (!t)
1855 t = new QTime;
1856 if (tc != this || t->elapsed() > QApplication::doubleClickInterval()) {
1857 if (isRightToLeft()) {
1858 QPoint p = b->mapToGlobal(QPoint(b->x() + b->width(), b->y() + b->height()));
1859 p.rx() -= d->popup->sizeHint().width();
1860 d->_q_popupOperationMenu(p);
1861 } else {
1862 d->_q_popupOperationMenu(b->mapToGlobal(QPoint(b->x(), b->y() + b->height())));
1863 }
1864 t->start();
1865 tc = this;
1866 } else {
1867 tc = 0;
1868 closeActiveWindow();
1869 }
1870 return true;
1871 }
1872 default:
1873 break;
1874 }
1875 return QWidget::eventFilter(o, e);
1876 }
1877 switch (e->type()) {
1878 case QEvent::HideToParent:
1879 break;
1880 case QEvent::ShowToParent:
1881 if (QWorkspaceChild *c = qobject_cast<QWorkspaceChild*>(o))
1882 if (!d->focus.contains(c))
1883 d->focus.append(c);
1884 d->updateWorkspace();
1885 break;
1886 case QEvent::WindowTitleChange:
1887 if (!d->inTitleChange) {
1888 if (o == window())
1889 d->topTitle = window()->windowTitle();
1890 if (d->maxWindow && d->maxWindow->windowWidget() && d->topTitle.size()) {
1891 d->inTitleChange = true;
1892 window()->setWindowTitle(tr("%1 - [%2]")
1893 .arg(d->topTitle).arg(d->maxWindow->windowWidget()->windowTitle()));
1894 d->inTitleChange = false;
1895 }
1896 }
1897 break;
1898
1899 case QEvent::ModifiedChange:
1900 if (o == d->maxWindow)
1901 window()->setWindowModified(d->maxWindow->isWindowModified());
1902 break;
1903
1904 case QEvent::Close:
1905 if (o == window())
1906 {
1907 QList<QWorkspaceChild *>::Iterator it(d->windows.begin());
1908 while (it != d->windows.end()) {
1909 QWorkspaceChild* c = *it;
1910 ++it;
1911 if (c->shademode)
1912 c->showShaded();
1913 }