FreeCAD
1/***************************************************************************
2* Copyright (c) 2004 Werner Mayer <wmayer[at]users.sourceforge.net> *
3* *
4* This file is part of the FreeCAD CAx development system. *
5* *
6* This library is free software; you can redistribute it and/or *
7* modify it under the terms of the GNU Library General Public *
8* License as published by the Free Software Foundation; either *
9* version 2 of the License, or (at your option) any later version. *
10* *
11* This library is distributed in the hope that it will be useful, *
12* but WITHOUT ANY WARRANTY; without even the implied warranty of *
13* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
14* GNU Library General Public License for more details. *
15* *
16* You should have received a copy of the GNU Library General Public *
17* License along with this library; see the file COPYING.LIB. If not, *
18* write to the Free Software Foundation, Inc., 59 Temple Place, *
19* Suite 330, Boston, MA 02111-1307, USA *
20* *
21***************************************************************************/
22
23
24#include "PreCompiled.h"25
26#ifndef _PreComp_27# include <QApplication>28# include <QMessageBox>29# include <QProgressDialog>30# include <QWindow>31# ifdef FC_OS_WIN3232# include <windows.h>33# endif34#endif35
36#include "WaitCursor.h"37
38using namespace Gui;39
40namespace Gui {41class WaitCursorP : public QObject42{
43public:44static WaitCursorP* getInstance();45void setBusy(bool);46WaitCursor::FilterEventsFlags ignoreEvents() const;47void setIgnoreEvents(WaitCursor::FilterEventsFlags flags);48
49protected:50bool eventFilter(QObject*, QEvent*) override;51bool isModalDialog(QObject* o) const;52
53private:54WaitCursorP(); // Disable constructor55static WaitCursorP* _instance;56bool isOn{false};57WaitCursor::FilterEventsFlags flags{WaitCursor::AllEvents};58};59} // namespace Gui60
61WaitCursorP* WaitCursorP::_instance = nullptr;62
63WaitCursorP::WaitCursorP() : QObject(nullptr)64{
65}
66
67WaitCursorP* WaitCursorP::getInstance()68{
69if (!_instance)70_instance = new WaitCursorP();71return _instance;72}
73
74void WaitCursorP::setBusy(bool on)75{
76if (on == this->isOn)77return;78
79if (on) {80qApp->installEventFilter(this);81QApplication::setOverrideCursor(Qt::WaitCursor);82}83else {84qApp->removeEventFilter(this);85QApplication::restoreOverrideCursor();86}87
88this->isOn = on;89}
90
91WaitCursor::FilterEventsFlags WaitCursorP::ignoreEvents() const92{
93return this->flags;94}
95
96void WaitCursorP::setIgnoreEvents(WaitCursor::FilterEventsFlags flags)97{
98this->flags = flags;99}
100
101bool WaitCursorP::isModalDialog(QObject* o) const102{
103QWidget* parent = qobject_cast<QWidget*>(o);104if (!parent) {105QWindow* window = qobject_cast<QWindow*>(o);106if (window)107parent = QWidget::find(window->winId());108}109while (parent) {110auto dlg = qobject_cast<QMessageBox*>(parent);111if (dlg && dlg->isModal())112return true;113auto pd = qobject_cast<QProgressDialog*>(parent);114if (pd)115return true;116parent = parent->parentWidget();117}118
119return false;120}
121
122bool WaitCursorP::eventFilter(QObject* o, QEvent* e)123{
124// Note: This might cause problems when we want to open a modal dialog at the lifetime125// of a WaitCursor instance because the incoming events are still filtered.126if (e->type() == QEvent::KeyPress ||127e->type() == QEvent::KeyRelease) {128if (isModalDialog(o))129return false;130if (this->flags & WaitCursor::KeyEvents)131return true;132}133if (e->type() == QEvent::MouseButtonPress ||134e->type() == QEvent::MouseButtonRelease ||135e->type() == QEvent::MouseButtonDblClick) {136if (isModalDialog(o))137return false;138if (this->flags & WaitCursor::MouseEvents)139return true;140}141return false;142}
143
144int WaitCursor::instances = 0;145
146/**
147* Constructs this object and shows the wait cursor immediately. If you need to open a dialog as
148* long as an instance of WaitCursor exists you must call restoreCursor() before and setWaitCursor()
149* afterwards because all key events and mouse button events are filtered, otherwise you will run
150* into strange behaviour.
151*/
152WaitCursor::WaitCursor()153{
154if (instances++ == 0)155setWaitCursor();156filter = WaitCursorP::getInstance()->ignoreEvents();157}
158
159/** Restores the last cursor again. */
160WaitCursor::~WaitCursor()161{
162if (--instances == 0)163restoreCursor();164WaitCursorP::getInstance()->setIgnoreEvents(filter);165}
166
167/**
168* Sets the wait cursor if needed.
169*/
170void WaitCursor::setWaitCursor()171{
172WaitCursorP::getInstance()->setBusy(true);173}
174
175/**
176* Restores the last cursor if needed.
177*/
178void WaitCursor::restoreCursor()179{
180WaitCursorP::getInstance()->setBusy(false);181}
182
183WaitCursor::FilterEventsFlags WaitCursor::ignoreEvents() const184{
185return WaitCursorP::getInstance()->ignoreEvents();186}
187
188void WaitCursor::setIgnoreEvents(FilterEventsFlags flags)189{
190WaitCursorP::getInstance()->setIgnoreEvents(flags);191}
192