/****************************************************************************
**
** Implementation of the QWorkspace class
**
** Created : 931107
**
** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved.
**
** This file is part of the workspace module of the Qt GUI Toolkit.
**
** This file may be used under the terms of the GNU General
** Public License versions 2.0 or 3.0 as published by the Free
** Software Foundation and appearing in the files LICENSE.GPL2
** and LICENSE.GPL3 included in the packaging of this file.
** Alternatively you may (at your option) use any later version
** of the GNU General Public License if such license has been
** publicly approved by Trolltech ASA (or its successors, if any)
** and the KDE Free Qt Foundation.
**
** Please review the following information to ensure GNU General
** Public Licensing requirements will be met:
** http://trolltech.com/products/qt/licenses/licensing/opensource/.
** If you are unsure which license is appropriate for your use, please
** review the following information:
** http://trolltech.com/products/qt/licenses/licensing/licensingoverview
** or contact the sales department at sales@trolltech.com.
**
** This file may be used under the terms of the Q Public License as
** defined by Trolltech ASA and appearing in the file LICENSE.QPL
** included in the packaging of this file. Licensees holding valid Qt
** Commercial licenses may use this file in accordance with the Qt
** Commercial License Agreement provided with the Software.
**
** This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted
** herein.
**
**********************************************************************/
#include "qworkspace.h"
#ifndef QT_NO_WORKSPACE
#include "qapplication.h"
#include "../widgets/qtitlebar_p.h"
#include "qobjectlist.h"
#include "qlayout.h"
#include "qtoolbutton.h"
#include "qlabel.h"
#include "qvbox.h"
#include "qaccel.h"
#include "qcursor.h"
#include "qpopupmenu.h"
#include "qmenubar.h"
#include "qguardedptr.h"
#include "qiconset.h"
#include "../widgets/qwidgetresizehandler_p.h"
#include "qfocusdata.h"
#include "qdatetime.h"
#include "qtooltip.h"
#include "qwmatrix.h"
#include "qimage.h"
#include "qscrollbar.h"
#include "qstyle.h"
#include "qbitmap.h"
// magic non-mdi things
#include "qtimer.h"
#include "qdockarea.h"
#include "qstatusbar.h"
#include "qmainwindow.h"
#include "qdockwindow.h"
#include "qtoolbar.h"
#define BUTTON_WIDTH 16
#define BUTTON_HEIGHT 14
/*!
\class QWorkspace qworkspace.h
\brief The QWorkspace widget provides a workspace window that can
contain decorated windows, e.g. for MDI.
\module workspace
\ingroup application
\ingroup organizers
\mainclass
MDI (multiple document interface) applications typically have one
main window with a menu bar and toolbar, and a central widget that
is a QWorkspace. The workspace itself contains zero, one or more
document 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 and an object name. The
parent window is usually a QMainWindow, but it need not be.
Document windows (i.e. MDI windows) are also ordinary Qt widgets
which have the workspace as their parent widget. When you call
show(), hide(), showMaximized(), setCaption(), etc. on a document
window, it is shown, hidden, etc. with a frame, caption, icon and
icon text, just as you'd expect. You can provide widget flags
which will be used for the layout of the decoration or the
behaviour of the widget itself.
To change or retrieve the geometry of MDI windows you must operate
on the MDI widget's parentWidget(). (The parentWidget() provides
access to the decorated window in which the MDI window's widget is
shown.)
A document window becomes active when it gets the keyboard focus.
You can also activate a window in code using setFocus(). 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 it detects the activation
change, and the function activeWindow() always returns a pointer
to the active document window.
The convenience function windowList() returns a list of all
document windows. This is useful to create a popup menu
"Windows" on the fly, for example.
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.
If you want your users to be able to work with document windows
larger than the actual workspace, set the scrollBarsEnabled
property to TRUE.
If the top-level window contains a menu bar and a document window
is maximised, QWorkspace moves the document window's minimize,
restore and close buttons from the document window's frame to the
workspace window's menu bar. It then inserts a window operations
menu at the far left of the menu bar.
*/
static bool inCaptionChange = FALSE;
class QWorkspaceChild : public QFrame
{
Q_OBJECT
friend class QWorkspace;
friend class QTitleBar;
public:
QWorkspaceChild( QWidget* window,
QWorkspace* parent=0, const char* name=0 );
~QWorkspaceChild();
void setActive( bool );
bool isActive() const;
void adjustToFullscreen();
void setStatusBar(QStatusBar *);
QWidget* windowWidget() const;
QWidget* iconWidget() const;
void doResize();
void doMove();
QSize sizeHint() const;
QSize minimumSizeHint() const;
QSize baseSize() const;
signals:
void showOperationMenu();
void popupOperationMenu( const QPoint& );
public slots:
void activate();
void showMinimized();
void showMaximized();
void showNormal();
void showShaded();
void setCaption( const QString& );
void internalRaise();
void titleBarDoubleClicked();
void move( int x, int y );
protected:
bool event(QEvent * );
void enterEvent( QEvent * );
void leaveEvent( QEvent * );
void childEvent( QChildEvent* );
void resizeEvent( QResizeEvent * );
void moveEvent( QMoveEvent * );
bool eventFilter( QObject *, QEvent * );
bool focusNextPrevChild( bool );
void drawFrame( QPainter * );
void styleChange( QStyle & );
private:
QWidget* childWidget;
QGuardedPtr lastfocusw;
QWidgetResizeHandler *widgetResizeHandler;
QTitleBar* titlebar;
QGuardedPtr statusbar;
QGuardedPtr iconw;
QSize windowSize;
QSize shadeRestore;
QSize shadeRestoreMin;
bool act :1;
bool shademode :1;
bool snappedRight :1;
bool snappedDown :1;
#if defined(Q_DISABLE_COPY) // Disabled copy constructor and operator=
QWorkspaceChild( const QWorkspaceChild & );
QWorkspaceChild &operator=( const QWorkspaceChild & );
#endif
};
class QMainWindow;
class QWorkspacePrivate {
public:
QWorkspaceChild* active;
QPtrList windows;
QPtrList focus;
QPtrList icons;
QWorkspaceChild* maxWindow;
QRect maxRestore;
QGuardedPtr maxcontrols;
QGuardedPtr maxmenubar;
int px;
int py;
QWidget *becomeActive;
QGuardedPtr maxtools;
QPopupMenu* popup;
QPopupMenu* toolPopup;
int menuId;
int controlId;
QString topCaption;
QScrollBar *vbar, *hbar;
QWidget *corner;
int yoffset, xoffset;
// toplevel mdi fu
QWorkspace::WindowMode wmode;
QGuardedPtr mainwindow;
QPtrList dockwindows, newdocks;
};
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 a \a parent and a \a name.
*/
QWorkspace::QWorkspace( QWidget *parent, const char *name )
: QWidget( parent, name )
{
init();
}
#ifdef QT_WORKSPACE_WINDOWMODE
/*!
Constructs a workspace with a \a parent and a \a name. This
constructor will also set the WindowMode to \a mode.
\sa windowMode()
*/
QWorkspace::QWorkspace( QWorkspace::WindowMode mode, QWidget *parent, const char *name )
: QWidget( parent, name )
{
init();
d->wmode = mode;
}
#endif
/*!
\internal
*/
void
QWorkspace::init()
{
d = new QWorkspacePrivate;
d->maxcontrols = 0;
d->active = 0;
d->maxWindow = 0;
d->maxtools = 0;
d->px = 0;
d->py = 0;
d->becomeActive = 0;
#if defined( QT_WORKSPACE_WINDOWMODE ) && defined( Q_WS_MAC )
d->wmode = AutoDetect;
#else
d->wmode = MDI;
#endif
d->mainwindow = 0;
#if defined(Q_WS_WIN)
d->popup = new QPopupMenu( this, "qt_internal_mdi_popup" );
d->toolPopup = new QPopupMenu( this, "qt_internal_mdi_popup" );
#else
d->popup = new QPopupMenu( parentWidget(), "qt_internal_mdi_popup" );
d->toolPopup = new QPopupMenu( parentWidget(), "qt_internal_mdi_popup" );
#endif
d->menuId = -1;
d->controlId = -1;
connect( d->popup, SIGNAL( aboutToShow() ), this, SLOT(operationMenuAboutToShow() ));
connect( d->popup, SIGNAL( activated(int) ), this, SLOT( operationMenuActivated(int) ) );
d->popup->insertItem(QIconSet(style().stylePixmap(QStyle::SP_TitleBarNormalButton)), tr("&Restore"), 1);
d->popup->insertItem(tr("&Move"), 2);
d->popup->insertItem(tr("&Size"), 3);
d->popup->insertItem(QIconSet(style().stylePixmap(QStyle::SP_TitleBarMinButton)), tr("Mi&nimize"), 4);
d->popup->insertItem(QIconSet(style().stylePixmap(QStyle::SP_TitleBarMaxButton)), tr("Ma&ximize"), 5);
d->popup->insertSeparator();
d->popup->insertItem(QIconSet(style().stylePixmap(QStyle::SP_TitleBarCloseButton)),
tr("&Close")
#ifndef QT_NO_ACCEL
+"\t"+QAccel::keyToString(CTRL+Key_F4)
#endif
, this, SLOT( closeActiveWindow() ) );
connect( d->toolPopup, SIGNAL( aboutToShow() ), this, SLOT(toolMenuAboutToShow() ));
connect( d->toolPopup, SIGNAL( activated(int) ), this, SLOT( operationMenuActivated(int) ) );
d->toolPopup->insertItem(tr("&Move"), 2);
d->toolPopup->insertItem(tr("&Size"), 3);
d->toolPopup->insertItem(tr("Stay on &Top"), 7);
d->toolPopup->setItemChecked( 7, TRUE );
d->toolPopup->setCheckable( TRUE );
d->toolPopup->insertSeparator();
d->toolPopup->insertItem(QIconSet(style().stylePixmap(QStyle::SP_TitleBarShadeButton)), tr("Sh&ade"), 6);
d->toolPopup->insertItem(QIconSet(style().stylePixmap(QStyle::SP_TitleBarCloseButton)),
tr("&Close")
#ifndef QT_NO_ACCEL
+"\t"+QAccel::keyToString( CTRL+Key_F4)
#endif
, this, SLOT( closeActiveWindow() ) );
#ifndef QT_NO_ACCEL
QAccel* a = new QAccel( this );
a->connectItem( a->insertItem( ALT + Key_Minus),
this, SLOT( showOperationMenu() ) );
a->connectItem( a->insertItem( CTRL + Key_F6),
this, SLOT( activateNextWindow() ) );
a->connectItem( a->insertItem( CTRL + Key_Tab),
this, SLOT( activateNextWindow() ) );
a->connectItem( a->insertItem( Key_Forward ),
this, SLOT( activateNextWindow() ) );
a->connectItem( a->insertItem( CTRL + SHIFT + Key_F6),
this, SLOT( activatePreviousWindow() ) );
a->connectItem( a->insertItem( CTRL + SHIFT + Key_Tab),
this, SLOT( activatePreviousWindow() ) );
a->connectItem( a->insertItem( Key_Back ),
this, SLOT( activatePreviousWindow() ) );
a->connectItem( a->insertItem( CTRL + Key_F4 ),
this, SLOT( closeActiveWindow() ) );
#endif
setBackgroundMode( PaletteDark );
setSizePolicy( QSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding ) );
#ifndef QT_NO_WIDGET_TOPEXTRA
d->topCaption = topLevelWidget()->caption();
#endif
d->hbar = d->vbar = 0;
d->corner = 0;
d->xoffset = d->yoffset = 0;
updateWorkspace();
topLevelWidget()->installEventFilter( this );
}
/*! Destroys the workspace and frees any allocated resources. */
QWorkspace::~QWorkspace()
{
delete d;
d = 0;
}
/*!\reimp */
QSize QWorkspace::sizeHint() const
{
QSize s( QApplication::desktop()->size() );
return QSize( s.width()*2/3, s.height()*2/3);
}
/*! \reimp */
void QWorkspace::setPaletteBackgroundColor( const QColor & c )
{
setEraseColor( c );
}
/*! \reimp */
void QWorkspace::setPaletteBackgroundPixmap( const QPixmap & pm )
{
setErasePixmap( pm );
}
/*! \reimp */
void QWorkspace::childEvent( QChildEvent * e)
{
if (e->inserted() && e->child()->isWidgetType()) {
QWidget* w = (QWidget*) e->child();
if ( !w || !w->testWFlags( WStyle_Title | WStyle_NormalBorder | WStyle_DialogBorder) || w->testWFlags(WType_Dialog)
|| d->icons.contains( w ) || w == d->vbar || w == d->hbar || w == d->corner )
return; // nothing to do
bool wasMaximized = w->isMaximized();
bool wasMinimized = w->isMinimized();
bool hasBeenHidden = w->isHidden();
bool hasSize = w->testWState( WState_Resized );
int x = w->x();
int y = w->y();
bool hasPos = x != 0 || y != 0;
QSize s = w->size().expandedTo( w->minimumSizeHint() );
if ( !hasSize && w->sizeHint().isValid() )
w->adjustSize();
QWorkspaceChild* child = new QWorkspaceChild( w, this, "qt_workspacechild" );
child->installEventFilter( this );
connect( child, SIGNAL( popupOperationMenu(const QPoint&) ),
this, SLOT( popupOperationMenu(const QPoint&) ) );
connect( child, SIGNAL( showOperationMenu() ),
this, SLOT( showOperationMenu() ) );
d->windows.append( child );
if ( child->isVisibleTo( this ) )
d->focus.append( child );
child->internalRaise();
if ( !hasPos )
place( child );
if ( hasSize )
child->resize( s + child->baseSize() );
else
child->adjustSize();
if ( hasPos )
child->move( x, y );
if ( hasBeenHidden )
w->hide();
else if ( !isVisible() ) // that's a case were we don't receive a showEvent in time. Tricky.
child->show();
if ( wasMaximized )
w->showMaximized();
else if ( wasMinimized )
w->showMinimized();
else if (!hasBeenHidden)
activateWindow( w );
updateWorkspace();
} else if (e->removed() ) {
if ( d->windows.contains( (QWorkspaceChild*)e->child() ) ) {
d->windows.removeRef( (QWorkspaceChild*)e->child() );
d->focus.removeRef( (QWorkspaceChild*)e->child() );
if (d->maxWindow == e->child())
d->maxWindow = 0;
updateWorkspace();
}
}
}
/*! \reimp
*/
#ifndef QT_NO_WHEELEVENT
void QWorkspace::wheelEvent( QWheelEvent *e )
{
if ( !scrollBarsEnabled() )
return;
if ( d->vbar && d->vbar->isVisible() && !( e->state() & AltButton ) )
QApplication::sendEvent( d->vbar, e );
else if ( d->hbar && d->hbar->isVisible() )
QApplication::sendEvent( d->hbar, e );
}
#endif
void QWorkspace::activateWindow( QWidget* w, bool change_focus )
{
if ( !w ) {
d->active = 0;
emit windowActivated( 0 );
return;
}
if ( d->wmode == MDI && !isVisibleTo( 0 ) ) {
d->becomeActive = w;
return;
}
if ( d->active && d->active->windowWidget() == w ) {
if ( !isChildOf( focusWidget(), w ) ) // child window does not have focus
d->active->setActive( TRUE );
return;
}
d->active = 0;
// First deactivate all other workspace clients
QPtrListIterator it( d->windows );
while ( it.current () ) {
QWorkspaceChild* c = it.current();
++it;
if(windowMode() == QWorkspace::TopLevel && c->isTopLevel() &&
c->windowWidget() == w && !c->isActive())
c->setActiveWindow();
if (c->windowWidget() == w)
d->active = c;
else
c->setActive( FALSE );
}
if (!d->active)
return;
// Then activate the new one, so the focus is stored correctly
d->active->setActive( TRUE );
if (!d->active)
return;
if ( d->maxWindow && d->maxWindow != d->active && d->active->windowWidget() &&
d->active->windowWidget()->testWFlags( WStyle_MinMax ) &&
!d->active->windowWidget()->testWFlags( WStyle_Tool ) ) {
d->active->showMaximized();
if ( d->maxtools ) {
#ifndef QT_NO_WIDGET_TOPEXTRA
if ( w->icon() ) {
QPixmap pm(*w->icon());
int iconSize = d->maxtools->size().height();
if(pm.width() > iconSize || pm.height() > iconSize) {
QImage im;
im = pm;
pm = im.smoothScale( QMIN(iconSize, pm.width()), QMIN(iconSize, pm.height()) );
}
d->maxtools->setPixmap( pm );
} else
#endif
{
QPixmap pm(14,14);
pm.fill( color1 );
pm.setMask(pm.createHeuristicMask());
d->maxtools->setPixmap( pm );
}
}
} else { // done implicitly in maximizeWindow otherwise
d->active->internalRaise();
}
if ( change_focus ) {
if ( d->focus.find( d->active ) >=0 ) {
d->focus.removeRef( d->active );
d->focus.append( d->active );
}
}
updateWorkspace();
emit windowActivated( w );
}
/*!
Returns the active window, or 0 if no window is active.
*/
QWidget* QWorkspace::activeWindow() const
{
return d->active?d->active->windowWidget():0;
}
void QWorkspace::place( QWidget* w)
{
QPtrList widgets;
for(QPtrListIterator it( d->windows ); it.current(); ++it)
if ((*it) != w)
widgets.append((*it));
if(d->wmode == TopLevel) {
for(QPtrListIterator it( d->dockwindows ); it.current(); ++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 = rect();
if(d->wmode == TopLevel) {
const QDesktopWidget *dw = qApp->desktop();
maxRect = dw->availableGeometry(dw->screenNumber(topLevelWidget()));
}
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;
QPtrListIterator it( widgets );
while ( it.current () ) {
l = it.current();
++it;
if ( d->maxWindow == l )
r2 = d->maxRestore;
else
r2.setRect(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;
QPtrListIterator it( widgets );
while ( it.current () ) {
l = it.current();
++it;
if ( d->maxWindow == l )
r2 = d->maxRestore;
else
r2.setRect(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;
QPtrListIterator it( widgets );
while ( it.current () ) {
l = it.current();
++it;
if ( d->maxWindow == l )
r2 = d->maxRestore;
else
r2.setRect(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 );
#if 0
if(windowMode() == QWorkspace::TopLevel && wpos.y()) {
QPoint fr = w->topLevelWidget()->frameGeometry().topLeft(),
r = w->topLevelWidget()->geometry().topLeft();
wpos += QPoint(r.x() - fr.x(), r.y() - fr.y());
}
#endif
w->move(wpos);
updateWorkspace();
}
void QWorkspace::insertIcon( QWidget* w )
{
if ( !w || d->icons.contains( w ) )
return;
d->icons.append( w );
if (w->parentWidget() != this )
w->reparent( this, 0, QPoint(0,0), FALSE);
QRect cr = updateWorkspace();
int x = 0;
int y = cr.height() - w->height();
QPtrListIterator it( d->icons );
while ( it.current () ) {
QWidget* i = it.current();
++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 ( isVisibleTo( parentWidget() ) ) {
w->show();
w->lower();
}
updateWorkspace();
}
void QWorkspace::removeIcon( QWidget* w)
{
if ( !d->icons.contains( w ) )
return;
d->icons.remove( w );
w->hide();
}
/*! \reimp */
void QWorkspace::resizeEvent( QResizeEvent * )
{
if ( d->maxWindow ) {
d->maxWindow->adjustToFullscreen();
if (d->maxWindow->windowWidget())
((QWorkspace*)d->maxWindow->windowWidget())->setWState( WState_Maximized );
}
QRect cr = updateWorkspace();
QPtrListIterator it( d->windows );
while ( it.current () ) {
QWorkspaceChild* c = it.current();
++it;
if ( c->windowWidget() && !c->windowWidget()->testWFlags( WStyle_Tool ) )
continue;
int x = c->x();
int y = c->y();
if ( c->snappedDown )
y = cr.height() - c->height();
if ( c->snappedRight )
x = cr.width() - c->width();
if ( x != c->x() || y != c->y() )
c->move( x, y );
}
}
void QWorkspace::handleUndock(QDockWindow *w)
{
const QDesktopWidget *dw = qApp->desktop();
QRect maxRect = dw->availableGeometry(dw->screenNumber(d->mainwindow));
QPoint wpos(maxRect.left(), maxRect.top());
int possible = 0;
if(!::qt_cast(w)) {
struct place_score { int o, x, y; } score = {0, 0, 0};
int left = 1, x = wpos.x(), y = wpos.y();
QPtrListIterator it( d->dockwindows );
while(1) {
if(y + w->height() > maxRect.bottom()) {
if(left) {
x = maxRect.right() - w->width();
y = maxRect.top();
left = 0;
} else {
break;
}
}
QDockWindow *l, *nearest = NULL, *furthest;
for ( it.toFirst(); it.current(); ++it ) {
l = it.current();
if ( l != w && y == l->y() ) {
if(!nearest) {
nearest = l;
} else if(l->x() == x) {
nearest = l;
break;
} else if(left && (l->x() - x) < (nearest->x() - x)) {
nearest = l;
} else if(!left && (x - l->x()) < (x - nearest->x())) {
nearest = l;
}
}
}
QRect r2(x, y, w->width(), w->height());
if(!nearest || !nearest->geometry().intersects(r2)) {
wpos = QPoint(x, y); //best possible outcome
possible = 2;
break;
}
QDockWindow *o = NULL;
int overlap = 0;
for( it.toFirst(); it.current(); ++it ) {
l = it.current();
if ( l != w && l->geometry().intersects(QRect(QPoint(x, y), w->size()))) {
overlap++;
o = l;
}
}
if(o && overlap == 1 && w->isVisible() && !o->isVisible()) {
wpos = QPoint(x, y);
possible = 2;
while(d->dockwindows.remove(o));
d->newdocks.append(o);
if(d->newdocks.count() == 1)
QTimer::singleShot(0, this, SLOT(dockWindowsShow()));
break;
}
for ( furthest = nearest, it.toFirst(); it.current(); ++it ) {
l = it.current();
if ( l != w && l->y() == nearest->y() &&
((left && (l->x() == nearest->x() + nearest->width())) ||
(!left && (l->x() + l->width() == nearest->x()) )))
furthest = l;
}
if(left)
x = furthest->x() + furthest->width();
else
x = furthest->x() - w->width();
QPoint sc_pt(x, y);
place_score sc;
if(left)
sc.x = (x + w->width()) * 2;
else
sc.x = ((maxRect.width() - x) * 2) + 1;
sc.y = sc_pt.y();
for( sc.o = 0, it.toFirst(); it.current(); ++it ) {
l = it.current();
if ( l != w && l->geometry().intersects(QRect(sc_pt, w->size())))
sc.o++;
}
if(maxRect.contains(QRect(sc_pt, w->size())) &&
(!possible || (sc.o < score.o) ||
((score.o || sc.o == score.o) && score.x < sc.x))) {
wpos = sc_pt;
score = sc;
possible = 1;
}
y += nearest->height();
if(left)
x = maxRect.x();
else
x = maxRect.right() - w->width();
}
if(!possible || (possible == 1 && score.o)) { //fallback to less knowledgeable function
place(w);
wpos = w->pos();
}
}
bool ishidden = w->isHidden();
QSize olds(w->size());
if(w->place() == QDockWindow::InDock)
w->undock();
w->move(wpos);
w->resize(olds);
if(!ishidden)
w->show();
else
w->hide();
}
void QWorkspace::dockWindowsShow()
{
QPtrList lst = d->newdocks;
d->newdocks.clear();
for(QPtrListIterator dw_it(lst); (*dw_it); ++dw_it) {
if(d->dockwindows.find((*dw_it)) != -1)
continue;
handleUndock((*dw_it));
d->dockwindows.append((*dw_it));
}
}
/*! \reimp */
void QWorkspace::showEvent( QShowEvent *e )
{
/* This is all magic, be carefull when playing with this code - this tries to allow people to
use QWorkspace as a high level abstraction for window management, but removes enforcement that
QWorkspace be used as an MDI. */
if(d->wmode == AutoDetect) {
d->wmode = MDI;
QWidget *o = topLevelWidget();
if(::qt_cast(o)) {
d->wmode = TopLevel;
const QObjectList *c = o->children();
for(QObjectListIt it(*c); it; ++it) {
if((*it)->isWidgetType() && !((QWidget *)(*it))->isTopLevel() &&
!::qt_cast(*it) && !::qt_cast(*it) &&
!::qt_cast(*it) && !(*it)->inherits("QHideDock") &&
!::qt_cast(*it) && !::qt_cast(*it) &&
!::qt_cast(*it) && !::qt_cast(*it)) {
d->wmode = MDI;
break;
}
}
}
}
if(d->wmode == TopLevel) {
QWidget *o = topLevelWidget();
d->mainwindow = ::qt_cast(o);
const QObjectList children = *o->children();
for(QObjectListIt it(children); it; ++it) {
if(!(*it)->isWidgetType())
continue;
QWidget *w = (QWidget *)(*it);
if(w->isTopLevel())
continue;
if(::qt_cast(w)) {
const QObjectList *dock_c = w->children();
if(dock_c) {
QPtrList tb_list;
for(QObjectListIt dock_it(*dock_c); dock_it; ++dock_it) {
if(!(*dock_it)->isWidgetType())
continue;
if(::qt_cast(*dock_it)) {
tb_list.append((QToolBar *)(*dock_it));
} else if (::qt_cast(*dock_it)) {
QDockWindow *dw = (QDockWindow*)(*dock_it);
dw->move(dw->mapToGlobal(QPoint(0, 0)));
d->newdocks.append(dw);
} else {
qDebug("not sure what to do with %s %s", (*dock_it)->className(),
(*dock_it)->name());
}
}
if(tb_list.count() == 1) {
QToolBar *tb = tb_list.first();
tb->move(0, 0);
d->newdocks.prepend(tb);
} else if(tb_list.count()) {
QDockWindow *dw = new QDockWindow(QDockWindow::OutsideDock,
w->parentWidget(),
QString("QMagicDock_") + w->name());
dw->installEventFilter(this);
dw->setResizeEnabled(TRUE);
dw->setCloseMode( QDockWindow::Always );
dw->setResizeEnabled(FALSE);
#ifndef QT_NO_WIDGET_TOPEXTRA
dw->setCaption(o->caption());
#endif
QSize os(w->size());
if(w->layout() && w->layout()->hasHeightForWidth()) {
w->layout()->invalidate();
os.setHeight(w->layout()->heightForWidth(os.width()));
}
if(!w->isHidden())
dw->show();
w->reparent(dw, QPoint(0, 0));
dw->setWidget(w);
dw->setSizePolicy(QSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum));
dw->setGeometry(0, 0, os.width(), os.height() + dw->sizeHint().height());
d->newdocks.prepend(dw);
((QDockArea*)w)->setAcceptDockWindow(dw, FALSE);
w->show();
}
}
w->installEventFilter(this);
} else if(::qt_cast(w)) {
if(activeWindow()) {
QWorkspaceChild *c;
if ( ( c = findChild(activeWindow()) ) )
c->setStatusBar((QStatusBar*)w);
}
} else if(::qt_cast(w)) {
w->reparent(this, w->testWFlags(~(0)) | WType_TopLevel, w->pos());
}
}
dockWindowsShow(); //now place and undock windows discovered
QWidget *w = new QWidget(NULL, "QDoesNotExist",
WType_Dialog | WStyle_Customize | WStyle_NoBorder);
// if(qApp->mainWidget() == o)
// QObject::connect(qApp, SIGNAL(lastWindowClosed()), qApp, SLOT(quit()));
QDesktopWidget *dw = QApplication::desktop();
w->setGeometry(dw->availableGeometry(dw->screenNumber(o)));
o->reparent(w, QPoint(0, 0), TRUE);
{
QMenuBar *mb = 0;
if(::qt_cast(o))
mb = ((QMainWindow *)o)->menuBar();
if(!mb)
mb = (QMenuBar*)o->child(NULL, "QMenuBar");
if(mb)
mb->reparent(w, QPoint(0, 0));
}
reparent(w, QPoint(0,0));
setGeometry(0, 0, w->width(), w->height());
#if 0
/* Hide really isn't acceptable because I need to make the rest of Qt
think it is visible, so instead I set it to an empty mask. I'm not
sure what problems this is going to create, hopefully everything will
be happy (or not even notice since this is mostly intended for Qt/Mac) */
// w->setMask(QRegion());
// w->show();
#else
w->hide();
#endif
}
//done with that nastiness, on with your regularly schedueled programming..
if ( d->maxWindow && !style().styleHint(QStyle::SH_Workspace_FillSpaceOnMaximize, this))
showMaximizeControls();
QWidget::showEvent( e );
if ( d->becomeActive ) {
activateWindow( d->becomeActive );
d->becomeActive = 0;
} else if ( d->windows.count() > 0 && !d->active ) {
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 (QPtrListIterator it( d->windows ); it.current(); ++it ) {
QWorkspaceChild* c = it.current();
QApplication::postEvent(c, new QPaintEvent(c->rect(), TRUE));
}
updateWorkspace();
}
/*! \reimp */
void QWorkspace::hideEvent( QHideEvent * )
{
if ( !isVisibleTo(0) && !style().styleHint(QStyle::SH_Workspace_FillSpaceOnMaximize, this))
hideMaximizeControls();
}
void QWorkspace::minimizeWindow( QWidget* w)
{
QWorkspaceChild* c = findChild( w );
if ( !w || ( ( w && (!w->testWFlags( WStyle_Minimize ) ) ) || w->testWFlags( WStyle_Tool) ) )
return;
if ( c ) {
QWorkspace *fake = (QWorkspace*)w;
setUpdatesEnabled( FALSE );
bool wasMax = FALSE;
if ( c == d->maxWindow ) {
wasMax = TRUE;
d->maxWindow = 0;
inCaptionChange = TRUE;
#ifndef QT_NO_WIDGET_TOPEXTRA
if ( !!d->topCaption )
topLevelWidget()->setCaption( d->topCaption );
#endif
inCaptionChange = FALSE;
if ( !style().styleHint(QStyle::SH_Workspace_FillSpaceOnMaximize, this) )
hideMaximizeControls();
for (QPtrListIterator it( d->windows ); it.current(); ++it ) {
QWorkspaceChild* c = it.current();
if ( c->titlebar )
c->titlebar->setMovable( TRUE );
c->widgetResizeHandler->setActive( TRUE );
}
}
insertIcon( c->iconWidget() );
c->hide();
if ( wasMax )
c->setGeometry( d->maxRestore );
d->focus.append( c );
activateWindow(w);
setUpdatesEnabled( TRUE );
updateWorkspace();
fake->clearWState( WState_Maximized );
fake->setWState( WState_Minimized );
c->clearWState( WState_Maximized );
c->setWState( WState_Minimized );
}
}
void QWorkspace::normalizeWindow( QWidget* w)
{
QWorkspaceChild* c = findChild( w );
if ( !w )
return;
if ( c ) {
QWorkspace *fake = (QWorkspace*)w;
fake->clearWState( WState_Minimized | WState_Maximized );
if ( !style().styleHint(QStyle::SH_Workspace_FillSpaceOnMaximize, this) && d->maxWindow ) {
hideMaximizeControls();
} else {
if ( w->minimumSize() != w->maximumSize() )
c->widgetResizeHandler->setActive( TRUE );
if ( c->titlebar )
c->titlebar->setMovable(TRUE);
}
fake->clearWState( WState_Minimized | WState_Maximized );
c->clearWState( WState_Minimized | WState_Maximized );
if ( c == d->maxWindow ) {
c->setGeometry( d->maxRestore );
d->maxWindow = 0;
#ifndef QT_NO_WIDGET_TOPEXTRA
inCaptionChange = TRUE;
if ( !!d->topCaption )
topLevelWidget()->setCaption( d->topCaption );
inCaptionChange = FALSE;
#endif
} else {
if ( c->iconw )
removeIcon( c->iconw->parentWidget() );
c->show();
}
if ( !style().styleHint(QStyle::SH_Workspace_FillSpaceOnMaximize, this))
hideMaximizeControls();
for (QPtrListIterator it( d->windows ); it.current(); ++it ) {
QWorkspaceChild* c = it.current();
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 QWorkspace::maximizeWindow( QWidget* w)
{
QWorkspaceChild* c = findChild( w );
if ( !w || ( ( w && (!w->testWFlags( WStyle_Maximize ) ) ) || w->testWFlags( WStyle_Tool) ) )
return;
if ( c ) {
setUpdatesEnabled( FALSE );
if (c->iconw && d->icons.contains( c->iconw->parentWidget() ) )
normalizeWindow( w );
QWorkspace *fake = (QWorkspace*)w;
QRect r( c->geometry() );
c->adjustToFullscreen();
c->show();
c->internalRaise();
qApp->sendPostedEvents( c, QEvent::Resize );
qApp->sendPostedEvents( c, QEvent::Move );
qApp->sendPostedEvents( c, QEvent::ShowWindowRequest );
if ( d->maxWindow != c ) {
if ( d->maxWindow )
d->maxWindow->setGeometry( d->maxRestore );
d->maxWindow = c;
d->maxRestore = r;
}
activateWindow( w );
if(!style().styleHint(QStyle::SH_Workspace_FillSpaceOnMaximize, this)) {
showMaximizeControls();
} else {
c->widgetResizeHandler->setActive( FALSE );
if ( c->titlebar )
c->titlebar->setMovable( FALSE );
}
#ifndef QT_NO_WIDGET_TOPEXTRA
inCaptionChange = TRUE;
if ( !!d->topCaption )
topLevelWidget()->setCaption( tr("%1 - [%2]")
.arg(d->topCaption).arg(c->caption()) );
inCaptionChange = FALSE;
#endif
setUpdatesEnabled( TRUE );
updateWorkspace();
fake->clearWState( WState_Minimized );
fake->setWState( WState_Maximized );
c->clearWState( WState_Minimized );
c->setWState( WState_Maximized );
}
}
void QWorkspace::showWindow( QWidget* w)
{
if ( d->maxWindow && w->testWFlags( WStyle_Maximize ) && !w->testWFlags( WStyle_Tool) )
maximizeWindow(w);
else if (w->isMinimized() && !w->testWFlags(WStyle_Tool))
minimizeWindow(w);
else if ( !w->testWFlags( WStyle_Tool ) )
normalizeWindow(w);
else
w->parentWidget()->show();
if ( d->maxWindow )
d->maxWindow->internalRaise();
updateWorkspace();
}
QWorkspaceChild* QWorkspace::findChild( QWidget* w)
{
QPtrListIterator it( d->windows );
while ( it.current () ) {
QWorkspaceChild* c = it.current();
++it;
if (c->windowWidget() == w)
return c;
}
return 0;
}
/*!
\obsolete
\overload
*/
QWidgetList QWorkspace::windowList() const
{
return windowList( CreationOrder );
}
/*!
Returns a list of all windows. If \a order is CreationOrder
(the default) the windows are listed in the order in which they
had been inserted into the workspace. If \a order is StackingOrder
the windows are listed in their stacking order, with the topmost window
being the last window in the list.
QWidgetList is the same as QPtrList.
\sa QPtrList
*/
QWidgetList QWorkspace::windowList( WindowOrder order ) const
{
QWidgetList windows;
if ( order == StackingOrder ) {
const QObjectList *cl = children();
if ( cl ) {
QObjectListIt it( *cl );
while (it.current()) {
QObject *o = it.current();
++it;
QWorkspaceChild *c = ::qt_cast(o);
if (c && c->windowWidget())
windows.append(c->windowWidget());
}
}
} else {
QPtrListIterator it( d->windows );
while (it.current()) {
QWorkspaceChild* c = it.current();
++it;
if ( c->windowWidget() )
windows.append( c->windowWidget() );
}
}
return windows;
}
/*!\reimp*/
bool QWorkspace::eventFilter( QObject *o, QEvent * e)
{
if(d->wmode == TopLevel && d->mainwindow && o->parent() == d->mainwindow) {
if((e->type() == QEvent::ChildInserted || e->type() == QEvent::Reparent) &&
::qt_cast(o) && !((QWidget*)o)->isVisible()) {
QChildEvent *ce = (QChildEvent*)e;
if(!::qt_cast(ce->child())) {
qDebug("No idea what to do..");
return FALSE;
}
QDockWindow *w = (QDockWindow*)ce->child();
if(d->newdocks.find(w) == -1 && d->dockwindows.find(w) == -1) {
if(::qt_cast(w))
d->newdocks.prepend(w);
else
d->newdocks.append(w);
if(d->newdocks.count() == 1)
QTimer::singleShot(0, this, SLOT(dockWindowsShow()));
}
} else if(e->type() == QEvent::Hide && !e->spontaneous() && !qstrncmp(o->name(), "QMagicDock_", 11)) {
// d->mainwindow->close();
}
return QWidget::eventFilter(o, e);
}
static QTime* t = 0;
static QWorkspace* tc = 0;
#ifndef QT_NO_MENUBAR
if ( o == d->maxtools && d->menuId != -1 ) {
switch ( e->type() ) {
case QEvent::MouseButtonPress:
{
QMenuBar* b = (QMenuBar*)o->parent();
if ( !t )
t = new QTime;
if ( tc != this || t->elapsed() > QApplication::doubleClickInterval() ) {
if ( QApplication::reverseLayout() ) {
QPoint p = b->mapToGlobal( QPoint( b->x() + b->width(), b->y() + b->height() ) );
p.rx() -= d->popup->sizeHint().width();
popupOperationMenu( p );
} else {
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 );
}
#endif
switch ( e->type() ) {
case QEvent::Hide:
case QEvent::HideToParent:
if ( !o->isA( "QWorkspaceChild" ) || !isVisible() || e->spontaneous() )
break;
if ( d->active == o ) {
int a = d->focus.find( d->active );
for ( ;; ) {
if ( --a < 0 )
a = d->focus.count()-1;
QWorkspaceChild* c = d->focus.at( a );
if ( !c || c == o ) {
if ( c && c->iconw && d->icons.contains( c->iconw->parentWidget() ) )
break;
activateWindow( 0 );
break;
}
if ( c->isShown() ) {
activateWindow( c->windowWidget(), FALSE );
break;
}
}
}
d->focus.removeRef( (QWorkspaceChild*)o );
if ( d->maxWindow == o && d->maxWindow->isHidden() ) {
d->maxWindow->setGeometry( d->maxRestore );
d->maxWindow = 0;
if ( d->active )
maximizeWindow( d->active );
if ( !d->maxWindow ) {
if ( style().styleHint(QStyle::SH_Workspace_FillSpaceOnMaximize, this)) {
QWorkspaceChild *wc = (QWorkspaceChild *)o;
wc->widgetResizeHandler->setActive( TRUE );
if ( wc->titlebar )
wc->titlebar->setMovable( TRUE );
} else {
hideMaximizeControls();
}
#ifndef QT_NO_WIDGET_TOPEXTRA
inCaptionChange = TRUE;
if ( !!d->topCaption )
topLevelWidget()->setCaption( d->topCaption );
inCaptionChange = FALSE;
#endif
}
}
updateWorkspace();
break;
case QEvent::Show:
if ( o->isA("QWorkspaceChild") && !d->focus.containsRef( (QWorkspaceChild*)o ) )
d->focus.append( (QWorkspaceChild*)o );
updateWorkspace();
break;
case QEvent::CaptionChange:
if ( inCaptionChange )
break;
#ifndef QT_NO_WIDGET_TOPEXTRA
inCaptionChange = TRUE;
if ( o == topLevelWidget() ) {
QWidget *tlw = (QWidget*)o;
if ( !d->maxWindow
|| tlw->caption() != tr("%1 - [%2]").arg(d->topCaption).arg(d->maxWindow->caption()) )
d->topCaption = tlw->caption();
}
if ( d->maxWindow && !!d->topCaption )
topLevelWidget()->setCaption( tr("%1 - [%2]")
.arg(d->topCaption).arg(d->maxWindow->caption()));
inCaptionChange = FALSE;
#endif
break;
case QEvent::Close:
if ( o == topLevelWidget() )
{
QPtrListIterator it( d->windows );
while ( it.current () ) {
QWorkspaceChild* c = it.current();
++it;
if ( c->shademode )
c->showShaded();
}
} else if ( ::qt_cast(o) ) {
d->popup->hide();
}
updateWorkspace();
break;
default:
break;
}
return QWidget::eventFilter( o, e);
}
void QWorkspace::showMaximizeControls()
{
#ifndef QT_NO_MENUBAR
Q_ASSERT(d->maxWindow);
QMenuBar* b = 0;
// Do a breadth-first search first on every parent,
QWidget* w = parentWidget();
QObjectList * l = 0;
while ( !l && w ) {
l = w->queryList( "QMenuBar", 0, FALSE, FALSE );
w = w->parentWidget();
if ( l && !l->count() ) {
delete l;
l = 0;
}
}
// and query recursively if nothing is found.
if ( !l || !l->count() ) {
if ( l )
delete l;
l = topLevelWidget()->queryList( "QMenuBar", 0, 0, TRUE );
}
if ( l && l->count() )
b = (QMenuBar *)l->first();
delete l;
if ( !b )
return;
if ( !d->maxcontrols ) {
d->maxmenubar = b;
d->maxcontrols = new QFrame( topLevelWidget(), "qt_maxcontrols" );
QHBoxLayout* l = new QHBoxLayout( d->maxcontrols,
d->maxcontrols->frameWidth(), 0 );
if ( d->maxWindow->windowWidget() &&
d->maxWindow->windowWidget()->testWFlags(WStyle_Minimize) ) {
QToolButton* iconB = new QToolButton( d->maxcontrols, "iconify" );
#ifndef QT_NO_TOOLTIP
QToolTip::add( iconB, tr( "Minimize" ) );
#endif
l->addWidget( iconB );
iconB->setFocusPolicy( NoFocus );
iconB->setIconSet(style().stylePixmap(QStyle::SP_TitleBarMinButton));
iconB->setFixedSize(BUTTON_WIDTH, BUTTON_HEIGHT);
connect( iconB, SIGNAL( clicked() ),
this, SLOT( minimizeActiveWindow() ) );
}
QToolButton* restoreB = new QToolButton( d->maxcontrols, "restore" );
#ifndef QT_NO_TOOLTIP
QToolTip::add( restoreB, tr( "Restore Down" ) );
#endif
l->addWidget( restoreB );
restoreB->setFocusPolicy( NoFocus );
restoreB->setIconSet( style().stylePixmap(QStyle::SP_TitleBarNormalButton));
restoreB->setFixedSize(BUTTON_WIDTH, BUTTON_HEIGHT);
connect( restoreB, SIGNAL( clicked() ),
this, SLOT( normalizeActiveWindow() ) );
l->addSpacing( 2 );
QToolButton* closeB = new QToolButton( d->maxcontrols, "close" );
#ifndef QT_NO_TOOLTIP
QToolTip::add( closeB, tr( "Close" ) );
#endif
l->addWidget( closeB );
closeB->setFocusPolicy( NoFocus );
closeB->setIconSet( style().stylePixmap(QStyle::SP_TitleBarCloseButton) );
closeB->setFixedSize(BUTTON_WIDTH, BUTTON_HEIGHT);
connect( closeB, SIGNAL( clicked() ),
this, SLOT( closeActiveWindow() ) );
d->maxcontrols->setFixedSize( d->maxcontrols->minimumSizeHint() );
}
if ( d->controlId == -1 || b->indexOf( d->controlId ) == -1 ) {
QFrame* dmaxcontrols = d->maxcontrols;
d->controlId = b->insertItem( dmaxcontrols, -1, b->count() );
}
if ( !d->active && d->becomeActive ) {
d->active = (QWorkspaceChild*)d->becomeActive->parentWidget();
d->active->setActive( TRUE );
d->becomeActive = 0;
emit windowActivated( d->active->windowWidget() );
}
if ( d->active && ( d->menuId == -1 || b->indexOf( d->menuId ) == -1 ) ) {
if ( !d->maxtools ) {
d->maxtools = new QLabel( topLevelWidget(), "qt_maxtools" );
d->maxtools->installEventFilter( this );
}
#ifndef QT_NO_WIDGET_TOPEXTRA
if ( d->active->windowWidget() && d->active->windowWidget()->icon() ) {
QPixmap pm(*d->active->windowWidget()->icon());
int iconSize = d->maxcontrols->size().height();
if(pm.width() > iconSize || pm.height() > iconSize) {
QImage im;
im = pm;
pm = im.smoothScale( QMIN(iconSize, pm.width()), QMIN(iconSize, pm.height()) );
}
d->maxtools->setPixmap( pm );
} else
#endif
{
QPixmap pm(14,14);
pm.fill( color1 );
pm.setMask(pm.createHeuristicMask());
d->maxtools->setPixmap( pm );
}
d->menuId = b->insertItem( d->maxtools, -1, 0 );
}
#endif
}
void QWorkspace::hideMaximizeControls()
{
#ifndef QT_NO_MENUBAR
if ( d->maxmenubar ) {
int mi = d->menuId;
if ( mi != -1 ) {
if ( d->maxmenubar->indexOf( mi ) != -1 )
d->maxmenubar->removeItem( mi );
d->maxtools = 0;
}
int ci = d->controlId;
if ( ci != -1 && d->maxmenubar->indexOf( ci ) != -1 )
d->maxmenubar->removeItem( ci );
}
d->maxcontrols = 0;
d->menuId = -1;
d->controlId = -1;
#endif
}
/*!
Closes the child window that is currently active.
\sa closeAllWindows()
*/
void QWorkspace::closeActiveWindow()
{
setUpdatesEnabled( FALSE );
if ( d->maxWindow && d->maxWindow->windowWidget() )
d->maxWindow->windowWidget()->close();
else if ( d->active && d->active->windowWidget() )
d->active->windowWidget()->close();
setUpdatesEnabled( TRUE );
updateWorkspace();
}
/*!
Closes all child windows.
The windows are closed in random order. The operation stops if a
window does not accept the close event.
\sa closeActiveWindow()
*/
void QWorkspace::closeAllWindows()
{
bool did_close = TRUE;
QPtrListIterator it( d->windows );
QWorkspaceChild *c = 0;
while ( ( c = it.current() ) && did_close ) {
++it;
if ( c->windowWidget() )
did_close = c->windowWidget()->close();
}
}
void QWorkspace::normalizeActiveWindow()
{
if ( d->maxWindow )
d->maxWindow->showNormal();
else if ( d->active )
d->active->showNormal();
}
void QWorkspace::minimizeActiveWindow()
{
if ( d->maxWindow )
d->maxWindow->showMinimized();
else if ( d->active )
d->active->showMinimized();
}
void QWorkspace::showOperationMenu()
{
if ( !d->active || !d->active->windowWidget() )
return;
Q_ASSERT( d->active->windowWidget()->testWFlags( WStyle_SysMenu ) );
QPoint p;
QPopupMenu *popup = d->active->windowWidget()->testWFlags( WStyle_Tool ) ? d->toolPopup : d->popup;
if ( QApplication::reverseLayout() ) {
p = QPoint( d->active->windowWidget()->mapToGlobal( QPoint(d->active->windowWidget()->width(),0) ) );
p.rx() -= popup->sizeHint().width();
} else {
p = QPoint( d->active->windowWidget()->mapToGlobal( QPoint(0,0) ) );
}
if ( !d->active->isVisible() ) {
p = d->active->iconWidget()->mapToGlobal( QPoint(0,0) );
p.ry() -= popup->sizeHint().height();
}
popupOperationMenu( p );
}
void QWorkspace::popupOperationMenu( const QPoint& p)
{
if ( !d->active || !d->active->windowWidget() || !d->active->windowWidget()->testWFlags( WStyle_SysMenu ) )
return;
if ( d->active->windowWidget()->testWFlags( WStyle_Tool ))
d->toolPopup->popup( p );
else
d->popup->popup( p );
}
void QWorkspace::operationMenuAboutToShow()
{
for ( int i = 1; i < 6; i++ ) {
bool enable = d->active != 0;
d->popup->setItemEnabled( i, enable );
}
if ( !d->active || !d->active->windowWidget() )
return;
QWidget *windowWidget = d->active->windowWidget();
bool canResize = windowWidget->maximumSize() != windowWidget->minimumSize();
d->popup->setItemEnabled( 3, canResize );
d->popup->setItemEnabled( 4, windowWidget->testWFlags( WStyle_Minimize ) );
d->popup->setItemEnabled( 5, windowWidget->testWFlags( WStyle_Maximize ) && canResize );
if ( d->active == d->maxWindow ) {
d->popup->setItemEnabled( 2, FALSE );
d->popup->setItemEnabled( 3, FALSE );
d->popup->setItemEnabled( 5, FALSE );
} else if ( d->active->isVisible() ){
d->popup->setItemEnabled( 1, FALSE );
} else {
d->popup->setItemEnabled( 2, FALSE );
d->popup->setItemEnabled( 3, FALSE );
d->popup->setItemEnabled( 4, FALSE );
}
}
void QWorkspace::toolMenuAboutToShow()
{
if ( !d->active || !d->active->windowWidget() )
return;
QWidget *windowWidget = d->active->windowWidget();
bool canResize = windowWidget->maximumSize() != windowWidget->minimumSize();
d->toolPopup->setItemEnabled( 3, !d->active->shademode && canResize );
if ( d->active->shademode )
d->toolPopup->changeItem( 6,
QIconSet(style().stylePixmap(QStyle::SP_TitleBarUnshadeButton)), tr("&Unshade") );
else
d->toolPopup->changeItem( 6, QIconSet(style().stylePixmap(QStyle::SP_TitleBarShadeButton)), tr("Sh&ade") );
d->toolPopup->setItemEnabled( 6, d->active->windowWidget()->testWFlags( WStyle_MinMax ) );
d->toolPopup->setItemChecked( 7, d->active->windowWidget()->testWFlags( WStyle_StaysOnTop ) );
}
void QWorkspace::operationMenuActivated( int a )
{
if ( !d->active )
return;
switch ( a ) {
case 1:
d->active->showNormal();
break;
case 2:
d->active->doMove();
break;
case 3:
if ( d->active->shademode )
d->active->showShaded();
d->active->doResize();
break;
case 4:
d->active->showMinimized();
break;
case 5:
d->active->showMaximized();
break;
case 6:
d->active->showShaded();
break;
case 7:
{
QWorkspace* w = (QWorkspace*)d->active->windowWidget();
if ( !w )
break;
if ( w->testWFlags( WStyle_StaysOnTop ) ) {
w->clearWFlags( WStyle_StaysOnTop );
} else {
w->setWFlags( WStyle_StaysOnTop );
w->parentWidget()->raise();
}
}
break;
default:
break;
}
}
/*!
Activates the next window in the child window chain.
\sa activatePrevWindow()
*/
void QWorkspace::activateNextWindow()
{
if ( d->focus.isEmpty() )
return;
if ( !d->active ) {
if ( d->focus.first() )
activateWindow( d->focus.first()->windowWidget(), FALSE );
return;
}
int a = d->focus.find( d->active ) + 1;
a = a % d->focus.count();
if ( d->focus.at( a ) )
activateWindow( d->focus.at( a )->windowWidget(), FALSE );
else
activateWindow(0);
}
void QWorkspace::activatePreviousWindow()
{
activatePrevWindow();
}
/*!
Activates the previous window in the child window chain.
\sa activateNextWindow()
*/
void QWorkspace::activatePrevWindow()
{
if ( d->focus.isEmpty() )
return;
if ( !d->active ) {
if ( d->focus.last() )
activateWindow( d->focus.first()->windowWidget(), FALSE );
else
activateWindow( 0 );
return;
}
int a = d->focus.find( d->active ) - 1;
if ( a < 0 )
a = d->focus.count()-1;
if ( d->focus.at( a ) )
activateWindow( d->focus.at( a )->windowWidget(), FALSE );
else
activateWindow( 0 );
}
/*!
\fn void QWorkspace::windowActivated( QWidget* w )
This signal is emitted when the window widget \a w becomes active.
Note that \a w can be null, 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()
*/
void QWorkspace::cascade()
{
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 );
scrollBarChanged();
}
const int xoffset = 13;
const int yoffset = 20;
// make a list of all relevant mdi clients
QPtrList widgets;
QWorkspaceChild* wc = 0;
for ( wc = d->focus.first(); wc; wc = d->focus.next() )
if ( wc->windowWidget()->isVisibleTo( this ) && !wc->windowWidget()->testWFlags( WStyle_Tool ) && !wc->iconw )
widgets.append( wc );
int x = 0;
int y = 0;
setUpdatesEnabled( FALSE );
QPtrListIterator it( widgets );
while ( it.current () ) {
QWorkspaceChild *child = it.current();
++it;
child->setUpdatesEnabled( FALSE );
QSize prefSize = child->windowWidget()->sizeHint().expandedTo( child->windowWidget()->minimumSizeHint() );
if ( !prefSize.isValid() )
prefSize = child->windowWidget()->size();
prefSize = prefSize.expandedTo( child->windowWidget()->minimumSize() ).boundedTo( child->windowWidget()->maximumSize() );
if (prefSize.isValid())
prefSize += QSize( child->baseSize().width(), child->baseSize().height() );
int w = prefSize.width();
int h = prefSize.height();
child->showNormal();
qApp->sendPostedEvents( 0, QEvent::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();
child->setUpdatesEnabled( TRUE );
}
setUpdatesEnabled( TRUE );
updateWorkspace();
blockSignals(FALSE);
}
/*!
Arranges all child windows in a tile pattern.
\sa cascade()
*/
void QWorkspace::tile()
{
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 );
scrollBarChanged();
}
int rows = 1;
int cols = 1;
int n = 0;
QWorkspaceChild* c;
QPtrListIterator it( d->windows );
while ( it.current () ) {
c = it.current();
++it;
if ( !c->windowWidget()->isHidden() &&
!c->windowWidget()->testWFlags( WStyle_StaysOnTop ) &&
!c->windowWidget()->testWFlags( WStyle_Tool ) &&
!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.toFirst();
while ( it.current () ) {
c = it.current();
++it;
if ( c->iconw || c->windowWidget()->isHidden() || c->windowWidget()->testWFlags( WStyle_Tool ) )
continue;
if (!row && !col) {
w -= c->baseSize().width();
h -= c->baseSize().height();
}
if ( c->windowWidget()->testWFlags( WStyle_StaysOnTop ) ) {
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->QFrame::move( p );
} else {
c->showNormal();
qApp->sendPostedEvents( 0, QEvent::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;
c->setGeometry(col*w + col*bsize.width(), row*h + row*bsize.height(), sz.width(), sz.height());
used[(row+1)*cols+col] = TRUE;
add--;
} else {
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;
activateWindow( oldActive );
updateWorkspace();
blockSignals(FALSE);
}
QWorkspaceChild::QWorkspaceChild( QWidget* window, QWorkspace *parent,
const char *name )
: QFrame( parent, name,
(parent->windowMode() == QWorkspace::TopLevel ? (WStyle_MinMax | WStyle_SysMenu | WType_TopLevel) :
WStyle_NoBorder ) | WStyle_Customize | WDestructiveClose | WNoMousePropagation | WSubWindow )
{
statusbar = 0;
setMouseTracking( TRUE );
act = FALSE;
iconw = 0;
lastfocusw = 0;
shademode = FALSE;
titlebar = 0;
snappedRight = FALSE;
snappedDown = FALSE;
if (window) {
switch (window->focusPolicy()) {
case QWidget::NoFocus:
window->setFocusPolicy(QWidget::ClickFocus);
break;
case QWidget::TabFocus:
window->setFocusPolicy(QWidget::StrongFocus);
break;
default:
break;
}
}
if ( window && window->testWFlags( WStyle_Title ) && parent->windowMode() != QWorkspace::TopLevel ) {
titlebar = new QTitleBar( window, this, "qt_ws_titlebar" );
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(const QPoint&) ),
this, SIGNAL( popupOperationMenu(const QPoint&) ) );
connect( titlebar, SIGNAL( showOperationMenu() ),
this, SIGNAL( showOperationMenu() ) );
connect( titlebar, SIGNAL( doShade() ),
this, SLOT( showShaded() ) );
connect( titlebar, SIGNAL( doubleClicked() ),
this, SLOT( titleBarDoubleClicked() ) );
}
setFrameStyle( QFrame::StyledPanel | QFrame::Raised );
setLineWidth( style().pixelMetric(QStyle::PM_MDIFrameWidth, this) );
setMinimumSize( 128, 0 );
childWidget = window;
if (!childWidget)
return;
#ifndef QT_NO_WIDGET_TOPEXTRA
setCaption( childWidget->caption() );
#endif
QPoint p;
QSize s;
QSize cs;
bool hasBeenResized = childWidget->testWState( WState_Resized );
if ( !hasBeenResized )
cs = childWidget->sizeHint().expandedTo( childWidget->minimumSizeHint() );
else
cs = childWidget->size();
int th = titlebar ? titlebar->sizeHint().height() : 0;
if ( titlebar ) {
#ifndef QT_NO_WIDGET_TOPEXTRA
int iconSize = th;
if( childWidget->icon() ) {
QPixmap pm(*childWidget->icon());
if(pm.width() > iconSize || pm.height() > iconSize) {
QImage im;
im = pm;
pm = im.smoothScale( QMIN(iconSize, pm.width()), QMIN(iconSize, pm.height()) );
}
titlebar->setIcon( pm );
}
#endif
if ( !style().styleHint( QStyle::SH_TitleBar_NoBorder, titlebar ) )
th += frameWidth();
else
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->reparent( this, p);
resize( s );
childWidget->installEventFilter( this );
widgetResizeHandler = new QWidgetResizeHandler( this, window );
widgetResizeHandler->setSizeProtection( !parent->scrollBarsEnabled() );
connect( widgetResizeHandler, SIGNAL( activate() ),
this, SLOT( activate() ) );
if ( !style().styleHint( QStyle::SH_TitleBar_NoBorder, titlebar ) )
widgetResizeHandler->setExtraHeight( th + contentsRect().y() - 2*frameWidth() );
else
widgetResizeHandler->setExtraHeight( th + contentsRect().y() - frameWidth() );
if(parent->windowMode() == QWorkspace::TopLevel && isTopLevel()) {
move(0, 0);
widgetResizeHandler->setActive( FALSE );
}
if ( childWidget->minimumSize() == childWidget->maximumSize() )
widgetResizeHandler->setActive( QWidgetResizeHandler::Resize, FALSE );
setBaseSize( baseSize() );
}
QWorkspaceChild::~QWorkspaceChild()
{
if ( iconw )
delete iconw->parentWidget();
QWorkspace *workspace = ::qt_cast(parentWidget());
if ( workspace ) {
workspace->d->focus.removeRef(this);
if ( workspace->d->active == this ) {
workspace->activatePrevWindow();
if (workspace->d->active == this) {
workspace->activateWindow(0);
}
}
if ( workspace->d->maxWindow == this ) {
workspace->hideMaximizeControls();
workspace->d->maxWindow = 0;
}
}
}
bool QWorkspaceChild::event( QEvent *e )
{
if(((QWorkspace*)parentWidget())->windowMode() == QWorkspace::TopLevel) {
switch(e->type()) {
case QEvent::Close:
if(windowWidget()) {
if(!windowWidget()->close()) {
if(((QWorkspace*) parentWidget() )->d->active == this)
((QWorkspace*) parentWidget() )->activatePrevWindow();
return TRUE;
}
}
break;
#if 0
case QEvent::WindowDeactivate:
if(statusbar) {
QSize newsize(width(), height() - statusbar->height());
if(statusbar->parentWidget() == this)
statusbar->hide();
statusbar = 0;
resize(newsize);
}
break;
#endif
case QEvent::WindowActivate:
if(((QWorkspace*)parentWidget())->activeWindow() == windowWidget())
activate();
if(statusbar)
statusbar->show();
else if(((QWorkspace*) parentWidget() )->d->mainwindow)
setStatusBar(((QWorkspace*) parentWidget() )->d->mainwindow->statusBar());
break;
default:
break;
}
}
return QWidget::event(e);
}
void QWorkspaceChild::setStatusBar( QStatusBar *sb )
{
if(((QWorkspace*) parentWidget() )->windowMode() == QWorkspace::TopLevel) {
QSize newsize;
if(sb) {
sb->show();
if(sb != statusbar) {
sb->reparent(this, QPoint(0, height()), TRUE);
newsize = QSize(width(), height() + sb->height());
}
}
statusbar = sb;
if(!newsize.isNull())
resize(newsize);
}
}
void QWorkspaceChild::moveEvent( QMoveEvent *e )
{
if(((QWorkspace*) parentWidget() )->windowMode() == QWorkspace::TopLevel && !e->spontaneous()) {
QPoint p = parentWidget()->topLevelWidget()->pos();
if(x() < p.x() || y() < p.y())
move(QMAX(x(), p.x()), QMAX(y(), p.y()));
}
((QWorkspace*) parentWidget() )->updateWorkspace();
}
void QWorkspaceChild::resizeEvent( QResizeEvent * )
{
QRect r = contentsRect();
QRect cr;
if ( titlebar ) {
int th = titlebar->sizeHint().height();
QRect tbrect( 0, 0, width(), th );
if ( !style().styleHint( QStyle::SH_TitleBar_NoBorder ) )
tbrect = QRect( r.x(), r.y(), r.width(), th );
titlebar->setGeometry( tbrect );
if ( style().styleHint( QStyle::SH_TitleBar_NoBorder, titlebar ) )
th -= frameWidth();
cr = QRect( r.x(), r.y() + th + (shademode ? (frameWidth() * 3) : 0),
r.width(), r.height() - th );
} else {
cr = r;
}
if(statusbar && statusbar->isVisible()) {
int sh = statusbar->height();
statusbar->setGeometry(r.x(), r.bottom() - sh, r.width(), sh);
cr.setBottom(cr.bottom() - sh);
}
if (!childWidget)
return;
windowSize = cr.size();
childWidget->setGeometry( cr );
((QWorkspace*) parentWidget() )->updateWorkspace();
}
QSize QWorkspaceChild::baseSize() const
{
int th = titlebar ? titlebar->sizeHint().height() : 0;
if ( style().styleHint( QStyle::SH_TitleBar_NoBorder, titlebar ) )
th -= frameWidth();
return QSize( 2*frameWidth(), 2*frameWidth() + th );
}
QSize QWorkspaceChild::sizeHint() const
{
if ( !childWidget )
return QFrame::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 QFrame::minimumSizeHint() + baseSize();
QSize s = childWidget->minimumSize();
if ( s.isEmpty() )
s = childWidget->minimumSizeHint();
return s + baseSize();
}
void QWorkspaceChild::activate()
{
((QWorkspace*)parentWidget())->activateWindow( windowWidget() );
}
bool QWorkspaceChild::eventFilter( QObject * o, QEvent * e)
{
if ( !isActive() && ( e->type() == QEvent::MouseButtonPress ||
e->type() == QEvent::FocusIn ) ) {
if ( iconw ) {
((QWorkspace*)parentWidget())->normalizeWindow( windowWidget() );
if ( iconw ) {
((QWorkspace*)parentWidget())->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::Show:
if ( ((QWorkspace*)parentWidget())->d->focus.find( this ) < 0 )
((QWorkspace*)parentWidget())->d->focus.append( this );
if ( isVisibleTo( parentWidget() ) )
break;
if (( (QShowEvent*)e)->spontaneous() )
break;
// fall through
case QEvent::ShowToParent:
if ( windowWidget() && windowWidget()->testWFlags( WStyle_StaysOnTop ) ) {
internalRaise();
show();
}
((QWorkspace*)parentWidget())->showWindow( windowWidget() );
break;
case QEvent::ShowMaximized:
if ( windowWidget()->maximumSize().isValid() &&
( windowWidget()->maximumWidth() < parentWidget()->width() ||
windowWidget()->maximumHeight() < parentWidget()->height() ) ) {
windowWidget()->resize( windowWidget()->maximumSize() );
((QWorkspace*)windowWidget())->clearWState(WState_Maximized);
if (titlebar)
titlebar->repaint(FALSE);
break;
}
if ( windowWidget()->testWFlags( WStyle_Maximize ) && !windowWidget()->testWFlags( WStyle_Tool ) )
((QWorkspace*)parentWidget())->maximizeWindow( windowWidget() );
else
((QWorkspace*)parentWidget())->normalizeWindow( windowWidget() );
break;
case QEvent::ShowMinimized:
((QWorkspace*)parentWidget())->minimizeWindow( windowWidget() );
break;
case QEvent::ShowNormal:
((QWorkspace*)parentWidget())->normalizeWindow( windowWidget() );
if (iconw) {
((QWorkspace*)parentWidget())->removeIcon( iconw->parentWidget() );
delete iconw->parentWidget();
}
break;
case QEvent::Hide:
case QEvent::HideToParent:
if ( !childWidget->isVisibleTo( this ) ) {
QWidget * w = iconw;
if ( w && ( w = w->parentWidget() ) ) {
((QWorkspace*)parentWidget())->removeIcon( w );
delete w;
}
hide();
}
break;
case QEvent::CaptionChange:
#ifndef QT_NO_WIDGET_TOPEXTRA
setCaption( childWidget->caption() );
if ( iconw )
iconw->setCaption( childWidget->caption() );
#endif
break;
case QEvent::IconChange:
{
QWorkspace* ws = (QWorkspace*)parentWidget();
if ( !titlebar )
break;
QPixmap pm;
int iconSize = titlebar->size().height();
#ifndef QT_NO_WIDGET_TOPEXTRA
if ( childWidget->icon() ) {
pm = *childWidget->icon();
if(pm.width() > iconSize || pm.height() > iconSize) {
QImage im;
im = pm;
pm = im.smoothScale( QMIN(iconSize, pm.width()), QMIN(iconSize, pm.height()) );
}
} else
#endif
{
pm.resize( iconSize, iconSize );
pm.fill( color1 );
pm.setMask(pm.createHeuristicMask());
}
titlebar->setIcon( pm );
if ( iconw )
iconw->setIcon( pm );
if ( ws->d->maxWindow != this )
break;
if ( ws->d->maxtools )
ws->d->maxtools->setPixmap( pm );
}
break;
case QEvent::Resize:
{
QResizeEvent* re = (QResizeEvent*)e;
if ( re->size() != windowSize && !shademode )
resize( re->size() + baseSize() );
}
break;
case QEvent::WindowDeactivate:
if ( titlebar )
titlebar->setActive( FALSE );
repaint( FALSE );
break;
case QEvent::WindowActivate:
if ( titlebar )
titlebar->setActive( act );
repaint( FALSE );
break;
default:
break;
}
return QFrame::eventFilter(o, e);
}
bool QWorkspaceChild::focusNextPrevChild( bool next )
{
QFocusData *f = focusData();
QWidget *startingPoint = f->home();
QWidget *candidate = 0;
QWidget *w = next ? f->next() : f->prev();
while( !candidate && w != startingPoint ) {
if ( w != startingPoint &&
(w->focusPolicy() & TabFocus) == TabFocus
&& w->isEnabled() &&!w->focusProxy() && w->isVisible() )
candidate = w;
w = next ? f->next() : f->prev();
}
if ( candidate ) {
QObjectList *ol = queryList();
bool ischild = ol->findRef( candidate ) != -1;
delete ol;
if ( !ischild ) {
startingPoint = f->home();
QWidget *nw = next ? f->prev() : f->next();
QObjectList *ol2 = queryList();
QWidget *lastValid = 0;
candidate = startingPoint;
while ( nw != startingPoint ) {
if ( ( candidate->focusPolicy() & TabFocus ) == TabFocus
&& candidate->isEnabled() &&!candidate->focusProxy() && candidate->isVisible() )
lastValid = candidate;
if ( ol2->findRef( nw ) == -1 ) {
candidate = lastValid;
break;
}
candidate = nw;
nw = next ? f->prev() : f->next();
}
delete ol2;
}
}
if ( !candidate )
return FALSE;
candidate->setFocus();
return TRUE;
}
void QWorkspaceChild::childEvent( QChildEvent* e)
{
if ( e->type() == QEvent::ChildRemoved && e->child() == childWidget ) {
childWidget = 0;
if ( iconw ) {
((QWorkspace*)parentWidget())->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( arrowCursor );
#endif
}
void QWorkspaceChild::drawFrame( QPainter *p )
{
QStyle::SFlags flags = QStyle::Style_Default;
QStyleOption opt(lineWidth(),midLineWidth());
if ( titlebar && titlebar->isActive() )
flags |= QStyle::Style_Active;
style().drawPrimitive( QStyle::PE_WindowFrame, p, rect(), colorGroup(), flags, opt );
}
void QWorkspaceChild::styleChange( QStyle & )
{
resizeEvent( 0 );
if ( iconw ) {
QVBox *vbox = (QVBox*)iconw->parentWidget()->qt_cast( "QVBox" );
Q_ASSERT(vbox);
if ( !style().styleHint( QStyle::SH_TitleBar_NoBorder ) ) {
vbox->setFrameStyle( QFrame::WinPanel | QFrame::Raised );
vbox->resize( 196+2*vbox->frameWidth(), 20 + 2*vbox->frameWidth() );
} else {
vbox->resize( 196, 20 );
}
}
}
void QWorkspaceChild::setActive( bool b )
{
if ( !childWidget )
return;
bool hasFocus = isChildOf( focusWidget(), childWidget );
if ( act == b && hasFocus )
return;
act = b;
if ( titlebar )
titlebar->setActive( act );
if ( iconw )
iconw->setActive( act );
repaint( FALSE );
QObjectList* ol = childWidget->queryList( "QWidget" );
if ( act ) {
QObject *o;
for ( o = ol->first(); o; o = ol->next() )
o->removeEventFilter( this );
if ( !hasFocus ) {
if ( lastfocusw && ol->contains( lastfocusw ) &&
lastfocusw->focusPolicy() != NoFocus ) {
// this is a bug if lastfocusw has been deleted, a new
// widget has been created, and the new one is a child
// of the same window as the old one. but even though
// it's a bug the behaviour is reasonable
lastfocusw->setFocus();
} else if ( childWidget->focusPolicy() != NoFocus ) {
childWidget->setFocus();
} else {
// find something, anything, that accepts focus, and use that.
o = ol->first();
while( o && ((QWidget*)o)->focusPolicy() == NoFocus )
o = ol->next();
if ( o )
((QWidget*)o)->setFocus();
}
}
} else {
if ( isChildOf( focusWidget(), childWidget ) )
lastfocusw = focusWidget();
QObject * o;
for ( o = ol->first(); o; o = ol->next() ) {
o->removeEventFilter( this );
o->installEventFilter( this );
}
}
delete ol;
}
bool QWorkspaceChild::isActive() const
{
return act;
}
QWidget* QWorkspaceChild::windowWidget() const
{
return childWidget;
}
QWidget* QWorkspaceChild::iconWidget() const
{
if ( !iconw ) {
QWorkspaceChild* that = (QWorkspaceChild*) this;
// ### why do we even need the vbox? -Brad
QVBox* vbox = new QVBox(that, "qt_vbox", WType_TopLevel );
QTitleBar *tb = new QTitleBar( windowWidget(), vbox, "_workspacechild_icon_");
int th = style().pixelMetric( QStyle::PM_TitleBarHeight, tb );
int iconSize = style().pixelMetric( QStyle::PM_MDIMinimizedWidth, this );
if ( !style().styleHint( QStyle::SH_TitleBar_NoBorder ) ) {
vbox->setFrameStyle( QFrame::WinPanel | QFrame::Raised );
vbox->resize( iconSize+2*vbox->frameWidth(), th+2*vbox->frameWidth() );
} else {
vbox->resize( iconSize, th );
}
that->iconw = tb;
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(const QPoint&) ),
this, SIGNAL( popupOperationMenu(const QPoint&) ) );
connect( iconw, SIGNAL( showOperationMenu() ),
this, SIGNAL( showOperationMenu() ) );
connect( iconw, SIGNAL( doubleClicked() ),
this, SLOT( titleBarDoubleClicked() ) );
}
#ifndef QT_NO_WIDGET_TOPEXTRA
if ( windowWidget() ) {
iconw->setCaption( windowWidget()->caption() );
if ( windowWidget()->icon() ) {
int iconSize = iconw->sizeHint().height();
QPixmap pm(*childWidget->icon());
if(pm.width() > iconSize || pm.height() > iconSize) {
QImage im;
im = pm;
pm = im.smoothScale( QMIN(iconSize, pm.width()), QMIN(iconSize, pm.height()) );
}
iconw->setIcon( pm );
}
}
#endif
return iconw->parentWidget();
}
void QWorkspaceChild::showMinimized()
{
windowWidget()->setWindowState(WindowMinimized | windowWidget()->windowState());
}
void QWorkspaceChild::showMaximized()
{
windowWidget()->setWindowState(WindowMaximized | (windowWidget()->windowState() & ~WindowMinimized));
}
void QWorkspaceChild::showNormal()
{
windowWidget()->setWindowState(windowWidget()->windowState() & ~(WindowMinimized|WindowMaximized));
}
void QWorkspaceChild::showShaded()
{
if ( !titlebar)
return;
Q_ASSERT( windowWidget()->testWFlags( WStyle_MinMax ) && windowWidget()->testWFlags( WStyle_Tool ) );
((QWorkspace*)parentWidget())->activateWindow( windowWidget() );
if ( shademode ) {
QWorkspaceChild* fake = (QWorkspaceChild*)windowWidget();
fake->clearWState( WState_Minimized );
clearWState( WState_Minimized );
shademode = FALSE;
resize( shadeRestore );
setMinimumSize( shadeRestoreMin );
style().polish(this);
} else {
shadeRestore = size();
shadeRestoreMin = minimumSize();
setMinimumHeight(0);
shademode = TRUE;
QWorkspaceChild* fake = (QWorkspaceChild*)windowWidget();
fake->setWState( WState_Minimized );
setWState( WState_Minimized );
if ( style().styleHint( QStyle::SH_TitleBar_NoBorder ) )
resize( width(), titlebar->height() );
else
resize( width(), titlebar->height() + 2*lineWidth() + 1 );
style().polish(this);
}
titlebar->update();
}
void QWorkspaceChild::titleBarDoubleClicked()
{
if ( !windowWidget() )
return;
if ( windowWidget()->testWFlags( WStyle_MinMax ) ) {
if ( windowWidget()->testWFlags( WStyle_Tool ) )
showShaded();
else if ( iconw )
showNormal();
else if ( windowWidget()->testWFlags( WStyle_Maximize ) )
showMaximized();
}
}
void QWorkspaceChild::adjustToFullscreen()
{
if ( !childWidget )
return;
qApp->sendPostedEvents( this, QEvent::Resize );
qApp->sendPostedEvents( childWidget, QEvent::Resize );
qApp->sendPostedEvents( childWidget, QEvent::Move );
if( style().styleHint(QStyle::SH_Workspace_FillSpaceOnMaximize, this) ) {
setGeometry( 0, 0, parentWidget()->width(), parentWidget()->height());
} else {
int w = parentWidget()->width() + width() - childWidget->width();
int h = parentWidget()->height() + height() - childWidget->height();
w = QMAX( w, childWidget->minimumWidth() );
h = QMAX( h, childWidget->minimumHeight() );
setGeometry( -childWidget->x(), -childWidget->y(), w, h );
}
setWState( WState_Maximized );
((QWorkspaceChild*)childWidget)->setWState( WState_Maximized );
}
void QWorkspaceChild::setCaption( const QString& cap )
{
if ( titlebar )
titlebar->setCaption( cap );
#ifndef QT_NO_WIDGET_TOPEXTRA
QWidget::setCaption( cap );
#endif
}
void QWorkspaceChild::internalRaise()
{
setUpdatesEnabled( FALSE );
if ( iconw )
iconw->parentWidget()->raise();
raise();
if ( !windowWidget() || windowWidget()->testWFlags( WStyle_StaysOnTop ) ) {
setUpdatesEnabled( TRUE );
return;
}
QPtrListIterator it( ((QWorkspace*)parent())->d->windows );
while ( it.current () ) {
QWorkspaceChild* c = it.current();
++it;
if ( c->windowWidget() &&
!c->windowWidget()->isHidden() &&
c->windowWidget()->testWFlags( WStyle_StaysOnTop ) )
c->raise();
}
setUpdatesEnabled( TRUE );
}
void QWorkspaceChild::move( int x, int y )
{
int nx = x;
int ny = y;
if ( windowWidget() && windowWidget()->testWFlags( WStyle_Tool ) ) {
int dx = 10;
int dy = 10;
if ( QABS( x ) < dx )
nx = 0;
if ( QABS( y ) < dy )
ny = 0;
if ( QABS( x + width() - parentWidget()->width() ) < dx ) {
nx = parentWidget()->width() - width();
snappedRight = TRUE;
} else
snappedRight = FALSE;
if ( QABS( y + height() - parentWidget()->height() ) < dy ) {
ny = parentWidget()->height() - height();
snappedDown = TRUE;
} else
snappedDown = FALSE;
}
QFrame::move( nx, ny );
}
bool QWorkspace::scrollBarsEnabled() const
{
return d->vbar != 0;
}
/*!
\property QWorkspace::scrollBarsEnabled
\brief whether the workspace provides scrollbars
If this property is set to TRUE, it is possible to resize child
windows over the right or the bottom edge out of the visible area
of the workspace. The workspace shows scrollbars to make it
possible for the user to access those windows. If this property is
set to FALSE (the default), resizing windows out of the visible
area of the workspace is not permitted.
*/
void QWorkspace::setScrollBarsEnabled( bool enable )
{
if ( (d->vbar != 0) == enable )
return;
d->xoffset = d->yoffset = 0;
if ( enable ) {
d->vbar = new QScrollBar( Vertical, this, "vertical scrollbar" );
connect( d->vbar, SIGNAL( valueChanged(int) ), this, SLOT( scrollBarChanged() ) );
d->hbar = new QScrollBar( Horizontal, this, "horizontal scrollbar" );
connect( d->hbar, SIGNAL( valueChanged(int) ), this, SLOT( scrollBarChanged() ) );
d->corner = new QWidget( this, "qt_corner" );
updateWorkspace();
} else {
delete d->vbar;
delete d->hbar;
delete d->corner;
d->vbar = d->hbar = 0;
d->corner = 0;
}
QPtrListIterator it( d->windows );
while ( it.current () ) {
QWorkspaceChild *child = it.current();
++it;
child->widgetResizeHandler->setSizeProtection( !enable );
}
}
QRect QWorkspace::updateWorkspace()
{
if ( !isUpdatesEnabled() )
return rect();
QRect cr( rect() );
if ( scrollBarsEnabled() && !d->maxWindow ) {
d->corner->raise();
d->vbar->raise();
d->hbar->raise();
if ( d->maxWindow )
d->maxWindow->internalRaise();
QRect r( 0, 0, 0, 0 );
QPtrListIterator it( d->windows );
while ( it.current () ) {
QWorkspaceChild *child = it.current();
++it;
if ( !child->isHidden() )
r = r.unite( child->geometry() );
}
d->vbar->blockSignals( TRUE );
d->hbar->blockSignals( TRUE );
int hsbExt = d->hbar->sizeHint().height();
int vsbExt = d->vbar->sizeHint().width();
bool showv = d->yoffset || d->yoffset + r.bottom() - height() + 1 > 0 || d->yoffset + r.top() < 0;
bool showh = d->xoffset || d->xoffset + r.right() - width() + 1 > 0 || d->xoffset + r.left() < 0;
if ( showh && !showv)
showv = d->yoffset + r.bottom() - height() + hsbExt + 1 > 0;
if ( showv && !showh )
showh = d->xoffset + r.right() - width() + vsbExt + 1 > 0;
if ( !showh )
hsbExt = 0;
if ( !showv )
vsbExt = 0;
if ( showv ) {
d->vbar->setSteps( QMAX( height() / 12, 30 ), height() - hsbExt );
d->vbar->setRange( QMIN( 0, d->yoffset + QMIN( 0, r.top() ) ), QMAX( 0, d->yoffset + QMAX( 0, r.bottom() - height() + hsbExt + 1) ) );
d->vbar->setGeometry( width() - vsbExt, 0, vsbExt, height() - hsbExt );
d->vbar->setValue( d->yoffset );
d->vbar->show();
} else {
d->vbar->hide();
}
if ( showh ) {
d->hbar->setSteps( QMAX( width() / 12, 30 ), width() - vsbExt );
d->hbar->setRange( QMIN( 0, d->xoffset + QMIN( 0, r.left() ) ), QMAX( 0, d->xoffset + QMAX( 0, r.right() - width() + vsbExt + 1) ) );
d->hbar->setGeometry( 0, height() - hsbExt, width() - vsbExt, hsbExt );
d->hbar->setValue( d->xoffset );
d->hbar->show();
} else {
d->hbar->hide();
}
if ( showh && showv ) {
d->corner->setGeometry( width() - vsbExt, height() - hsbExt, vsbExt, hsbExt );
d->corner->show();
} else {
d->corner->hide();
}
d->vbar->blockSignals( FALSE );
d->hbar->blockSignals( FALSE );
cr.setRect( 0, 0, width() - vsbExt, height() - hsbExt );
}
QPtrListIterator ii( d->icons );
while ( ii.current() ) {
QWorkspaceChild* w = (QWorkspaceChild*)ii.current();
++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 )
w->move( x, y );
}
return cr;
}
void QWorkspace::scrollBarChanged()
{
int ver = d->yoffset - d->vbar->value();
int hor = d->xoffset - d->hbar->value();
d->yoffset = d->vbar->value();
d->xoffset = d->hbar->value();
QPtrListIterator it( d->windows );
while ( it.current () ) {
QWorkspaceChild *child = it.current();
++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 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
*/
#ifdef QT_WORKSPACE_WINDOWMODE
/*!
\enum QWorkspace::WindowMode
Determines the Windowing Model QWorkspace will use for sub-windows.
\value TopLevel Subwindows are treated as toplevel windows
\value MDI Subwindows are organized in an MDI interface
\value AutoDetect QWorkspace will detect whether TopLevel or MDI
is appropriate
*/
/*!
The windowing model influences how the subwindows are actually
created. For most platforms the default behavior of a workspace is
to operate in MDI mode, with Qt/Mac the default mode is
AutoDetect.
*/
#else
/*! \internal */
#endif
QWorkspace::WindowMode QWorkspace::windowMode() const
{
return d->wmode;
}
#ifndef QT_NO_STYLE
/*!\reimp */
void QWorkspace::styleChange( QStyle &olds )
{
int fs = style().styleHint(QStyle::SH_Workspace_FillSpaceOnMaximize, this);
if ( isVisibleTo(0) && d->maxWindow &&
fs != olds.styleHint(QStyle::SH_Workspace_FillSpaceOnMaximize, this)) {
if( fs )
hideMaximizeControls();
else
showMaximizeControls();
}
QWidget::styleChange(olds);
}
#endif
#include "qworkspace.moc"
#endif // QT_NO_WORKSPACE