/********* * * This file is part of BibleTime's source code, http://www.bibletime.info/. * * Copyright 1999-2008 by the BibleTime developers. * The BibleTime source code is licensed under the GNU General Public License version 2.0. * **********/ #include "cmdiarea.h" //QT includes #include #include #include #include #include CMDIArea::CMDIArea(QWidget *parent) : QMdiArea(parent), m_mdiArrangementMode(ArrangementModeManual) { setActivationOrder( CreationOrder ); //keep window order consistent connect(this, SIGNAL(subWindowActivated(QMdiSubWindow*)), this, SLOT(slotClientActivated(QMdiSubWindow*))); } QMdiSubWindow* CMDIArea::addSubWindow(QWidget * widget, Qt::WindowFlags windowFlags) { QMdiSubWindow* subWindow = QMdiArea::addSubWindow(widget, windowFlags); subWindow->installEventFilter(this); //If we do have a maximized Window, set it to normal so that the new window can be seen if (activeSubWindow() && activeSubWindow()->isMaximized()){ activeSubWindow()->showNormal(); } if (m_mdiArrangementMode == ArrangementModeManual) { subWindow->resize(400, 400); //set the window to be big enough subWindow->raise(); } else { triggerWindowUpdate(); } return subWindow; } void CMDIArea::deleteAll() { closeAllSubWindows(); } void CMDIArea::setMDIArrangementMode( const MDIArrangementMode newArrangementMode ) { m_mdiArrangementMode = newArrangementMode; triggerWindowUpdate(); } CMDIArea::MDIArrangementMode CMDIArea::getMDIArrangementMode(void) const { return m_mdiArrangementMode; } void CMDIArea::myTileVertical() { if (!updatesEnabled() || !usableWindowList().count() ) { return; } QList windows = usableWindowList(); if (activeSubWindow() && activeSubWindow()->isMaximized()){ if (activeSubWindow()->size() != this->size()) { activeSubWindow()->resize(this->size()); } } else if (windows.count() == 1) { windows.at(0)->showMaximized(); } else { setUpdatesEnabled(false); QMdiSubWindow* active = activeSubWindow(); QMdiArea::tileSubWindows(); if (active) active->setFocus(); setUpdatesEnabled(true); } emitWindowCaptionChanged(); } void CMDIArea::myTileHorizontal() { if (!updatesEnabled() || !usableWindowList().count() ) { return; } QList windows = usableWindowList(); if (activeSubWindow() && activeSubWindow()->isMaximized()){ if (activeSubWindow()->size() != this->size()) { activeSubWindow()->resize(this->size()); } } else if (windows.count() == 1) { windows.at(0)->showMaximized(); } else { setUpdatesEnabled(false); QMdiSubWindow* active = activeSubWindow(); const int heightForEach = height() / windows.count(); unsigned int y = 0; foreach (QMdiSubWindow *window, windows) { window->showNormal(); const int preferredHeight = window->minimumHeight() + window->baseSize().height(); const int actHeight = qMax(heightForEach, preferredHeight); window->setGeometry( 0, y, width(), actHeight ); y += actHeight; } active->setFocus(); setUpdatesEnabled(true); } emitWindowCaptionChanged(); } void CMDIArea::myCascade() { if (!updatesEnabled() || !usableWindowList().count() ) { return; } QList windows = usableWindowList(); if (activeSubWindow() && activeSubWindow()->isMaximized()){ if (activeSubWindow()->size() != this->size()) { activeSubWindow()->resize(this->size()); } } else if (windows.count() == 1) { windows.at(0)->showMaximized(); } else { setUpdatesEnabled(false); QMdiSubWindow* active = activeSubWindow(); const unsigned int offsetX = 40; const unsigned int offsetY = 40; const unsigned int windowWidth = width() - (windows.count()-1)*offsetX; const unsigned int windowHeight = height() - (windows.count()-1)*offsetY; unsigned int x = 0; unsigned int y = 0; foreach (QMdiSubWindow* window, windows) { if (window == active) { //leave out the active window which should be the top window continue; } window->raise(); //make it the on-top-of-window-stack window to make sure they're in the right order window->setGeometry(x, y, windowWidth, windowHeight); x += offsetX; y += offsetY; } active->setGeometry(x, y, windowWidth, windowHeight); active->raise(); active->activateWindow(); setUpdatesEnabled(true); } emitWindowCaptionChanged(); } void CMDIArea::emitWindowCaptionChanged() { QString appCaption; if (activeSubWindow()) { appCaption = activeSubWindow()->windowTitle(); } emit sigSetToplevelCaption(appCaption); } QList CMDIArea::usableWindowList() { //Take care: when new windows are added, they will not appear //in subWindowList() when their ChildAdded-Event is triggered QList ret; foreach(QMdiSubWindow* w, subWindowList()) { if (w->isMinimized() || w->isHidden()) { //not usable for us continue; } ret.append( w ); } return ret; } void CMDIArea::slotClientActivated(QMdiSubWindow* client) { if (!client || !updatesEnabled()) { return; } emit sigSetToplevelCaption( client->windowTitle().trimmed() ); } //resize event of the MDI area itself, update layout if necessary void CMDIArea::resizeEvent(QResizeEvent* /*e*/) { //do not call QMdiArea::resizeEvent(e), this would mess up our layout if (updatesEnabled()) triggerWindowUpdate(); } //handle events of the client windows to update layout if necessary bool CMDIArea::eventFilter(QObject *o, QEvent *e) { QMdiSubWindow* w = dynamic_cast(o); if (!w) return false; //let the event be handled by other filters too if (e->type() == QEvent::WindowStateChange) { Qt::WindowStates newState = w->windowState(); Qt::WindowStates oldState = ((QWindowStateChangeEvent*)e)->oldState(); //Do not handle window activation or deactivation here, it will produce wrong //results because this event is handled too early. Let slotClientActivated() handle this. bool needsLayoutUpdate = false; //Window was maximized or un-maximized if ((newState ^ oldState) & Qt::WindowMaximized) needsLayoutUpdate = true; //Window was minimized or de-minimized if ((newState ^ oldState) & Qt::WindowMinimized) needsLayoutUpdate = true; //update Layout? if (needsLayoutUpdate) triggerWindowUpdate(); } if (e->type() == QEvent::Close) { triggerWindowUpdate(); } return false; //let the event be handled by other filters too } void CMDIArea::triggerWindowUpdate() { if (updatesEnabled()) { switch (m_mdiArrangementMode) { case ArrangementModeTileVertical: QTimer::singleShot(0, this, SLOT(myTileVertical())); break; case ArrangementModeTileHorizontal: QTimer::singleShot(0, this, SLOT(myTileHorizontal())); break; case ArrangementModeCascade: QTimer::singleShot(0, this, SLOT(myCascade())); break; default: break; } } }