KTutorial  0.5.1
WindowOnTopEnforcer.cpp
00001 /***************************************************************************
00002  *   Copyright (C) 2010 by Daniel Calviño Sánchez <danxuliu@gmail.com>     *
00003  *   Copyright (C) 2012 by Daniel Calviño Sánchez <danxuliu@gmail.com>     *
00004  *                                                                         *
00005  *   This program is free software; you can redistribute it and/or modify  *
00006  *   it under the terms of the GNU General Public License as published by  *
00007  *   the Free Software Foundation; either version 2 of the License, or     *
00008  *   (at your option) any later version.                                   *
00009  *                                                                         *
00010  *   This program is distributed in the hope that it will be useful,       *
00011  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
00012  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
00013  *   GNU General Public License for more details.                          *
00014  *                                                                         *
00015  *   You should have received a copy of the GNU General Public License     *
00016  *   along with this program; If not, see <http://www.gnu.org/licenses/>.  *
00017  ***************************************************************************/
00018 
00019 #include "WindowOnTopEnforcer.h"
00020 
00021 #include <QWidget>
00022 
00023 #include "../common/WindowVisibilitySpy.h"
00024 
00025 using ktutorial::common::WindowVisibilitySpy;
00026 
00027 namespace ktutorial {
00028 namespace view {
00029 
00030 //public:
00031 
00032 WindowOnTopEnforcer::WindowOnTopEnforcer(QWidget* widget): QObject(widget),
00033     mWidgetToKeepOnTop(widget) {
00034 
00035     Q_ASSERT(widget);
00036 
00037     mParentStack.push(mWidgetToKeepOnTop->parentWidget());
00038 }
00039 
00040 void WindowOnTopEnforcer::setBaseWindow(QWidget* baseWindow) {
00041     Q_ASSERT(baseWindow);
00042 
00043     WindowVisibilitySpy* spy = new WindowVisibilitySpy(this);
00044     spy->addWidgetToSpy(baseWindow);
00045     connect(spy, SIGNAL(windowShown(QWidget*)),
00046             this, SLOT(handleWindowShown(QWidget*)));
00047     connect(spy, SIGNAL(windowHidden(QWidget*)),
00048             this, SLOT(handleWindowHidden(QWidget*)));
00049 }
00050 
00051 //private:
00052 
00053 bool WindowOnTopEnforcer::isAncestorOf(QObject* object,
00054                                        QObject* childObject) const {
00055     if (childObject->parent() == 0) {
00056         return false;
00057     }
00058 
00059     if (childObject->parent() == object) {
00060         return true;
00061     }
00062 
00063     return isAncestorOf(object, childObject->parent());
00064 }
00065 
00066 void WindowOnTopEnforcer::reparentWindowTo(QWidget* window,
00067                                            QWidget* parent) const {
00068     //When a widget is reparented it is hidden and its window flags are cleared,
00069     //so they must be restored and the widget shown again
00070     Qt::WindowFlags flags = window->windowFlags();
00071     window->setParent(parent);
00072     window->setWindowFlags(flags);
00073     window->show();
00074 }
00075 
00076 //private slots:
00077 
00078 void WindowOnTopEnforcer::handleWindowShown(QWidget* window) {
00079     Q_ASSERT(window);
00080 
00081     if (!window->isModal() || mParentStack.contains(window)) {
00082         return;
00083     }
00084 
00085     //If the modal window shown is ancestor of any of the modal windows already
00086     //shown just insert it at the appropriate place in the parent stack.
00087     for (int i=1; i<mParentStack.size(); ++i) {
00088         QWidget* widgetInStack = mParentStack[i];
00089 
00090         if (!isAncestorOf(widgetInStack, window) &&
00091                 isAncestorOf(window, widgetInStack)) {
00092             mParentStack.insert(i, window);
00093             return;
00094         }
00095     }
00096 
00097     mParentStack.push(window);
00098 
00099     reparentWindowTo(mWidgetToKeepOnTop, window);
00100 }
00101 
00102 void WindowOnTopEnforcer::handleWindowHidden(QWidget* window) {
00103     Q_ASSERT(window);
00104 
00105     if (!window->isModal() || !mParentStack.contains(window)) {
00106         return;
00107     }
00108 
00109     if (window != mParentStack.top()) {
00110         mParentStack.remove(mParentStack.indexOf(window));
00111         return;
00112     }
00113 
00114     mParentStack.pop();
00115 
00116     reparentWindowTo(mWidgetToKeepOnTop, mParentStack.top());
00117 }
00118 
00119 }
00120 }