Optimized the use of Waiting Cursors by using a specialized context manager class.

Sat, 10 Oct 2020 12:20:51 +0200

author
Detlev Offenbach <detlev@die-offenbachs.de>
date
Sat, 10 Oct 2020 12:20:51 +0200
changeset 7771
787a6b3f8c9f
parent 7770
49f3377aebf1
child 7772
1958fe8d3f2c

Optimized the use of Waiting Cursors by using a specialized context manager class.

eric6.e4p file | annotate | diff | comparison | revisions
eric6/CondaInterface/CondaExportDialog.py file | annotate | diff | comparison | revisions
eric6/CondaInterface/CondaPackagesWidget.py file | annotate | diff | comparison | revisions
eric6/E5Gui/E5OverrideCursor.py file | annotate | diff | comparison | revisions
eric6/E5Network/E5XmlRpcClient.py file | annotate | diff | comparison | revisions
eric6/MultiProject/MultiProject.py file | annotate | diff | comparison | revisions
eric6/PipInterface/PipFreezeDialog.py file | annotate | diff | comparison | revisions
eric6/PipInterface/PipPackagesWidget.py file | annotate | diff | comparison | revisions
eric6/Plugins/VcsPlugins/vcsGit/GitBisectLogBrowserDialog.py file | annotate | diff | comparison | revisions
eric6/Plugins/VcsPlugins/vcsGit/GitDiffDialog.py file | annotate | diff | comparison | revisions
eric6/Plugins/VcsPlugins/vcsGit/GitDiffGenerator.py file | annotate | diff | comparison | revisions
eric6/Plugins/VcsPlugins/vcsGit/GitLogBrowserDialog.py file | annotate | diff | comparison | revisions
eric6/Plugins/VcsPlugins/vcsGit/GitReflogBrowserDialog.py file | annotate | diff | comparison | revisions
eric6/Plugins/VcsPlugins/vcsGit/GitStashBrowserDialog.py file | annotate | diff | comparison | revisions
eric6/Plugins/VcsPlugins/vcsMercurial/HgConflictsListDialog.py file | annotate | diff | comparison | revisions
eric6/Plugins/VcsPlugins/vcsMercurial/HgDiffDialog.py file | annotate | diff | comparison | revisions
eric6/Plugins/VcsPlugins/vcsMercurial/HgDiffGenerator.py file | annotate | diff | comparison | revisions
eric6/Plugins/VcsPlugins/vcsMercurial/HgLogBrowserDialog.py file | annotate | diff | comparison | revisions
eric6/Plugins/VcsPlugins/vcsMercurial/ShelveExtension/HgShelveBrowserDialog.py file | annotate | diff | comparison | revisions
eric6/Plugins/VcsPlugins/vcsPySvn/SvnChangeListsDialog.py file | annotate | diff | comparison | revisions
eric6/Plugins/VcsPlugins/vcsPySvn/SvnDialogMixin.py file | annotate | diff | comparison | revisions
eric6/Plugins/VcsPlugins/vcsPySvn/SvnDiffDialog.py file | annotate | diff | comparison | revisions
eric6/Plugins/VcsPlugins/vcsPySvn/SvnLogBrowserDialog.py file | annotate | diff | comparison | revisions
eric6/Plugins/VcsPlugins/vcsPySvn/SvnRepoBrowserDialog.py file | annotate | diff | comparison | revisions
eric6/Plugins/VcsPlugins/vcsPySvn/SvnStatusDialog.py file | annotate | diff | comparison | revisions
eric6/Plugins/VcsPlugins/vcsSubversion/SvnLogBrowserDialog.py file | annotate | diff | comparison | revisions
eric6/Plugins/VcsPlugins/vcsSubversion/SvnRepoBrowserDialog.py file | annotate | diff | comparison | revisions
eric6/Plugins/WizardPlugins/SetupWizard/SetupWizardDialog.py file | annotate | diff | comparison | revisions
eric6/Preferences/ConfigurationPages/EmailPage.py file | annotate | diff | comparison | revisions
eric6/Preferences/ProgramsDialog.py file | annotate | diff | comparison | revisions
eric6/Project/Project.py file | annotate | diff | comparison | revisions
eric6/Project/ProjectBaseBrowser.py file | annotate | diff | comparison | revisions
eric6/QScintilla/Editor.py file | annotate | diff | comparison | revisions
eric6/QScintilla/Exporters/ExporterHTML.py file | annotate | diff | comparison | revisions
eric6/QScintilla/Exporters/ExporterODT.py file | annotate | diff | comparison | revisions
eric6/QScintilla/Exporters/ExporterPDF.py file | annotate | diff | comparison | revisions
eric6/QScintilla/Exporters/ExporterRTF.py file | annotate | diff | comparison | revisions
eric6/QScintilla/Exporters/ExporterTEX.py file | annotate | diff | comparison | revisions
eric6/QScintilla/MiniEditor.py file | annotate | diff | comparison | revisions
eric6/Snapshot/SnapWidget.py file | annotate | diff | comparison | revisions
eric6/Tools/UIPreviewer.py file | annotate | diff | comparison | revisions
eric6/UI/EmailDialog.py file | annotate | diff | comparison | revisions
eric6/UI/PythonAstViewer.py file | annotate | diff | comparison | revisions
eric6/UI/PythonDisViewer.py file | annotate | diff | comparison | revisions
eric6/WebBrowser/AdBlock/AdBlockTreeWidget.py file | annotate | diff | comparison | revisions
eric6/WebBrowser/FlashCookieManager/FlashCookieManagerDialog.py file | annotate | diff | comparison | revisions
eric6/WebBrowser/SafeBrowsing/SafeBrowsingDialog.py file | annotate | diff | comparison | revisions
eric6/WebBrowser/Session/SessionManager.py file | annotate | diff | comparison | revisions
eric6/WebBrowser/WebBrowserTabWidget.py file | annotate | diff | comparison | revisions
eric6/WebBrowser/WebBrowserWindow.py file | annotate | diff | comparison | revisions
--- a/eric6.e4p	Fri Oct 09 17:19:29 2020 +0200
+++ b/eric6.e4p	Sat Oct 10 12:20:51 2020 +0200
@@ -149,6 +149,7 @@
     <Source>eric6/E5Gui/E5MessageBox.py</Source>
     <Source>eric6/E5Gui/E5ModelMenu.py</Source>
     <Source>eric6/E5Gui/E5ModelToolBar.py</Source>
+    <Source>eric6/E5Gui/E5OverrideCursor.py</Source>
     <Source>eric6/E5Gui/E5PassivePopup.py</Source>
     <Source>eric6/E5Gui/E5PasswordMeter.py</Source>
     <Source>eric6/E5Gui/E5PathPicker.py</Source>
--- a/eric6/CondaInterface/CondaExportDialog.py	Fri Oct 09 17:19:29 2020 +0200
+++ b/eric6/CondaInterface/CondaExportDialog.py	Sat Oct 10 12:20:51 2020 +0200
@@ -18,6 +18,7 @@
 from E5Gui import E5MessageBox, E5FileDialog
 from E5Gui.E5PathPicker import E5PathPickerModes
 from E5Gui.E5Application import e5App
+from E5Gui.E5OverrideCursor import E5OverrideCursor
 
 from .Ui_CondaExportDialog import Ui_CondaExportDialog
 
@@ -69,7 +70,6 @@
         @param e close event
         @type QCloseEvent
         """
-        QApplication.restoreOverrideCursor()
         e.accept()
     
     @pyqtSlot(str)
@@ -131,17 +131,16 @@
             self.__prefix,
         ]
         
-        QApplication.setOverrideCursor(Qt.WaitCursor)
-        success, output = self.__conda.runProcess(args)
+        with E5OverrideCursor():
+            success, output = self.__conda.runProcess(args)
+            
+            if success:
+                self.requirementsEdit.setPlainText(output)
+                self.__requirementsAvailable = True
+            else:
+                self.requirementsEdit.setPlainText(
+                    self.tr("No output generated by conda."))
         
-        if success:
-            self.requirementsEdit.setPlainText(output)
-            self.__requirementsAvailable = True
-        else:
-            self.requirementsEdit.setPlainText(
-                self.tr("No output generated by conda."))
-        
-        QApplication.restoreOverrideCursor()
         self.__updateButtons()
         
         self.__requirementsEdited = False
--- a/eric6/CondaInterface/CondaPackagesWidget.py	Fri Oct 09 17:19:29 2020 +0200
+++ b/eric6/CondaInterface/CondaPackagesWidget.py	Sat Oct 10 12:20:51 2020 +0200
@@ -11,7 +11,6 @@
 import os
 
 from PyQt5.QtCore import pyqtSlot, Qt
-from PyQt5.QtGui import QCursor
 from PyQt5.QtWidgets import (
     QWidget, QToolButton, QMenu, QTreeWidgetItem, QApplication, QLineEdit,
     QDialog
@@ -19,6 +18,7 @@
 
 from E5Gui import E5FileDialog, E5MessageBox, E5TextInputDialog
 from E5Gui.E5Application import e5App
+from E5Gui.E5OverrideCursor import E5OverrideCursor
 
 from .Ui_CondaPackagesWidget import Ui_CondaPackagesWidget
 
@@ -218,51 +218,51 @@
         self.packagesList.clear()
         prefix = self.environmentsComboBox.itemData(index)
         if prefix:
-            QApplication.setOverrideCursor(QCursor(Qt.WaitCursor))
             self.statusLabel.show()
             self.statusLabel.setText(self.tr("Getting installed packages..."))
-            QApplication.processEvents()
             
-            # 1. populate with installed packages
-            self.packagesList.setUpdatesEnabled(False)
-            installedPackages = self.__conda.getInstalledPackages(
-                prefix=prefix)
-            for package, version, build in installedPackages:
-                itm = QTreeWidgetItem(self.packagesList, [package, version])
-                itm.setData(1, self.PackageVersionRole, version)
-                itm.setData(1, self.PackageBuildRole, build)
-            self.packagesList.setUpdatesEnabled(True)
-            self.statusLabel.setText(self.tr("Getting outdated packages..."))
-            QApplication.processEvents()
-            
-            # 2. update with update information
-            self.packagesList.setUpdatesEnabled(False)
-            updateablePackages = self.__conda.getUpdateablePackages(
-                prefix=prefix)
-            for package, version, build in updateablePackages:
-                items = self.packagesList.findItems(
-                    package, Qt.MatchExactly | Qt.MatchCaseSensitive)
-                if items:
-                    itm = items[0]
-                    itm.setText(2, version)
-                    itm.setData(2, self.PackageVersionRole, version)
-                    itm.setData(2, self.PackageBuildRole, build)
-                    if itm.data(1, self.PackageVersionRole) == version:
-                        # build must be different, show in version display
-                        itm.setText(1, self.tr("{0} (Build: {1})").format(
-                            itm.data(1, self.PackageVersionRole),
-                            itm.data(1, self.PackageBuildRole),
-                        ))
-                        itm.setText(2, self.tr("{0} (Build: {1})").format(
-                            itm.data(2, self.PackageVersionRole),
-                            itm.data(2, self.PackageBuildRole),
-                        ))
-            
-            self.packagesList.sortItems(0, Qt.AscendingOrder)
-            for col in range(self.packagesList.columnCount()):
-                self.packagesList.resizeColumnToContents(col)
-            self.packagesList.setUpdatesEnabled(True)
-            QApplication.restoreOverrideCursor()
+            with E5OverrideCursor():
+                # 1. populate with installed packages
+                self.packagesList.setUpdatesEnabled(False)
+                installedPackages = self.__conda.getInstalledPackages(
+                    prefix=prefix)
+                for package, version, build in installedPackages:
+                    itm = QTreeWidgetItem(self.packagesList,
+                                          [package, version])
+                    itm.setData(1, self.PackageVersionRole, version)
+                    itm.setData(1, self.PackageBuildRole, build)
+                self.packagesList.setUpdatesEnabled(True)
+                self.statusLabel.setText(
+                    self.tr("Getting outdated packages..."))
+                QApplication.processEvents()
+                
+                # 2. update with update information
+                self.packagesList.setUpdatesEnabled(False)
+                updateablePackages = self.__conda.getUpdateablePackages(
+                    prefix=prefix)
+                for package, version, build in updateablePackages:
+                    items = self.packagesList.findItems(
+                        package, Qt.MatchExactly | Qt.MatchCaseSensitive)
+                    if items:
+                        itm = items[0]
+                        itm.setText(2, version)
+                        itm.setData(2, self.PackageVersionRole, version)
+                        itm.setData(2, self.PackageBuildRole, build)
+                        if itm.data(1, self.PackageVersionRole) == version:
+                            # build must be different, show in version display
+                            itm.setText(1, self.tr("{0} (Build: {1})").format(
+                                itm.data(1, self.PackageVersionRole),
+                                itm.data(1, self.PackageBuildRole),
+                            ))
+                            itm.setText(2, self.tr("{0} (Build: {1})").format(
+                                itm.data(2, self.PackageVersionRole),
+                                itm.data(2, self.PackageBuildRole),
+                            ))
+                
+                self.packagesList.sortItems(0, Qt.AscendingOrder)
+                for col in range(self.packagesList.columnCount()):
+                    self.packagesList.resizeColumnToContents(col)
+                self.packagesList.setUpdatesEnabled(True)
             self.statusLabel.hide()
         
         self.__updateActionButtons()
@@ -284,17 +284,14 @@
         self.environmentsComboBox.clear()
         self.packagesList.clear()
         
-        QApplication.setOverrideCursor(QCursor(Qt.WaitCursor))
-        QApplication.processEvents()
-        
-        self.__populateEnvironments()
+        with E5OverrideCursor():
+            self.__populateEnvironments()
+            
+            index = self.environmentsComboBox.findText(
+                currentEnvironment, Qt.MatchExactly | Qt.MatchCaseSensitive)
+            if index != -1:
+                self.environmentsComboBox.setCurrentIndex(index)
         
-        index = self.environmentsComboBox.findText(
-            currentEnvironment, Qt.MatchExactly | Qt.MatchCaseSensitive)
-        if index != -1:
-            self.environmentsComboBox.setCurrentIndex(index)
-        
-        QApplication.restoreOverrideCursor()
         self.__updateActionButtons()
     
     @pyqtSlot()
@@ -355,56 +352,53 @@
         self.searchResultList.clear()
         pattern = self.searchEdit.text()
         if pattern:
-            QApplication.setOverrideCursor(QCursor(Qt.WaitCursor))
-            QApplication.processEvents()
-            
-            if CondaInterface.condaVersion() >= (4, 4, 0):
-                prefix = ""
-            else:
-                prefix = self.environmentsComboBox.itemData(
-                    self.environmentsComboBox.currentIndex())
-            ok, result = self.__conda.searchPackages(
-                pattern,
-                fullNameOnly=self.fullNameButton.isChecked(),
-                packageSpec=self.packageSpecButton.isChecked(),
-                platform=self.platformComboBox.currentText(),
-                prefix=prefix,
-            )
-            
-            if result:
+            with E5OverrideCursor():
+                if CondaInterface.condaVersion() >= (4, 4, 0):
+                    prefix = ""
+                else:
+                    prefix = self.environmentsComboBox.itemData(
+                        self.environmentsComboBox.currentIndex())
+                ok, result = self.__conda.searchPackages(
+                    pattern,
+                    fullNameOnly=self.fullNameButton.isChecked(),
+                    packageSpec=self.packageSpecButton.isChecked(),
+                    platform=self.platformComboBox.currentText(),
+                    prefix=prefix,
+                )
+                
                 if ok:
-                    self.searchResultList.setUpdatesEnabled(False)
-                    for package in result:
-                        itm = QTreeWidgetItem(self.searchResultList, [package])
-                        itm.setExpanded(False)
-                        for detail in result[package]:
-                            version = detail["version"]
-                            build = detail["build"]
-                            if "subdir" in detail:
-                                platform = detail["subdir"]
-                            elif "platform" in detail:
-                                platform = detail["platform"]
-                            else:
-                                platform = ""
-                            citm = QTreeWidgetItem(
-                                itm, ["", version, build, platform])
-                            citm.setData(0, self.PackageDetailedDataRole,
-                                         detail)
-                
-                    self.searchResultList.sortItems(0, Qt.AscendingOrder)
-                    self.searchResultList.resizeColumnToContents(0)
-                    self.searchResultList.setUpdatesEnabled(True)
-                else:
-                    QApplication.restoreOverrideCursor()
-                    try:
-                        message = result["message"]
-                    except KeyError:
-                        message = result["error"]
-                    E5MessageBox.warning(
-                        self,
-                        self.tr("Conda Search Package Error"),
-                        message)
-            QApplication.restoreOverrideCursor()
+                    if result:
+                        self.searchResultList.setUpdatesEnabled(False)
+                        for package in result:
+                            itm = QTreeWidgetItem(self.searchResultList,
+                                                  [package])
+                            itm.setExpanded(False)
+                            for detail in result[package]:
+                                version = detail["version"]
+                                build = detail["build"]
+                                if "subdir" in detail:
+                                    platform = detail["subdir"]
+                                elif "platform" in detail:
+                                    platform = detail["platform"]
+                                else:
+                                    platform = ""
+                                citm = QTreeWidgetItem(
+                                    itm, ["", version, build, platform])
+                                citm.setData(0, self.PackageDetailedDataRole,
+                                             detail)
+                    
+                        self.searchResultList.sortItems(0, Qt.AscendingOrder)
+                        self.searchResultList.resizeColumnToContents(0)
+                        self.searchResultList.setUpdatesEnabled(True)
+            if not ok:
+                try:
+                    message = result["message"]
+                except KeyError:
+                    message = result["error"]
+                E5MessageBox.warning(
+                    self,
+                    self.tr("Conda Search Package Error"),
+                    message)
     
     def __showDetails(self, item):
         """
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/eric6/E5Gui/E5OverrideCursor.py	Sat Oct 10 12:20:51 2020 +0200
@@ -0,0 +1,139 @@
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2020 Detlev Offenbach <detlev@die-offenbachs.de>
+#
+
+"""
+Module implementing a context manager class for an override cursor and a
+QProcess class controlling an override cursor.
+"""
+
+import contextlib
+
+from PyQt5.QtCore import pyqtSlot, Qt, QProcess, QEventLoop
+from PyQt5.QtGui import QCursor, QGuiApplication
+
+
+# TODO: add similar class for QMutexLocker
+class E5OverrideCursor(contextlib.AbstractContextManager):
+    """
+    Class implementing a context manager class for an override cursor.
+    """
+    def __init__(self, cursorShape=Qt.WaitCursor):
+        """
+        Constructor
+        
+        @param cursorShape shape of the override cursor
+        @type Qt.CursorShape
+        """
+        self.__cursorShape = cursorShape
+    
+    def __enter__(self):
+        """
+        Special method called when entering the runtime ccontext.
+        
+        @return reference to the context manager object
+        @rtype E5OverrideCursor
+        """
+        QGuiApplication.setOverrideCursor(QCursor(self.__cursorShape))
+        QGuiApplication.processEvents(QEventLoop.ExcludeUserInputEvents)
+        
+        return self
+    
+    def __exit__(self, exc_type, exc_value, traceback):
+        """
+        Special method called when exiting the runtime ccontext.
+        
+        @param exc_type type of an exception raised in the runtime context
+        @param exc_value value of an exception raised in the runtime context
+        @param traceback traceback of an exception raised in the runtime
+            context
+        @return always returns None to not suppress any exception
+        @rtype None
+        """
+        QGuiApplication.restoreOverrideCursor()
+        QGuiApplication.processEvents(QEventLoop.ExcludeUserInputEvents)
+        
+        return None
+
+
+class E5OverridenCursor(contextlib.AbstractContextManager):
+    """
+    Class implementing a context manager class for an overriden cursor.
+    
+    The cursor is reset upon entering the runtime context and restored
+    upon exiting it.
+    """
+    def __init__(self):
+        """
+        Constructor
+        """
+        self.__cursor = None
+    
+    def __enter__(self):
+        """
+        Special method called when entering the runtime ccontext.
+        
+        @return reference to the context manager object
+        @rtype E5OverrideCursor
+        """
+        self.__cursor = QGuiApplication.overrideCursor()
+        if self.__cursor is not None:
+            QGuiApplication.restoreOverrideCursor()
+            QGuiApplication.processEvents(QEventLoop.ExcludeUserInputEvents)
+        
+        return self
+    
+    def __exit__(self, exc_type, exc_value, traceback):
+        """
+        Special method called when exiting the runtime ccontext.
+        
+        @param exc_type type of an exception raised in the runtime context
+        @param exc_value value of an exception raised in the runtime context
+        @param traceback traceback of an exception raised in the runtime
+            context
+        @return always returns None to not suppress any exception
+        @rtype None
+        """
+        if self.__cursor is not None:
+            QGuiApplication.setOverrideCursor(self.__cursor)
+            QGuiApplication.processEvents(QEventLoop.ExcludeUserInputEvents)
+        
+        return None
+
+
+class E5OverrideCursorProcess(QProcess):
+    """
+    Class implementing a QProcess subclass controlling an override cursor.
+    """
+    def __init__(self, parent=None, cursorShape=Qt.WaitCursor):
+        """
+        Constructor
+        
+        @param parent reference to the parent object
+        @type QObject
+        @param cursorShape shape of the override cursor
+        @type Qt.CursorShape
+        """
+        super(E5OverrideCursorProcess, self).__init__(parent)
+        
+        self.__cursorShape = cursorShape
+        
+        self.started.connect(self.__processStarted)
+        self.finished.connect(self.__processFinished)
+    
+    @pyqtSlot()
+    def __processStarted(self):
+        """
+        Private slot setting the cursor after the process has started.
+        """
+        QGuiApplication.setOverrideCursor(QCursor(self.__cursorShape))
+        QGuiApplication.processEvents(QEventLoop.ExcludeUserInputEvents)
+    
+    @pyqtSlot()
+    def __processFinished(self):
+        """
+        Private slot resetting the cursor when the process finished.
+        """
+        QGuiApplication.restoreOverrideCursor()
+        QGuiApplication.processEvents(QEventLoop.ExcludeUserInputEvents)
--- a/eric6/E5Network/E5XmlRpcClient.py	Fri Oct 09 17:19:29 2020 +0200
+++ b/eric6/E5Network/E5XmlRpcClient.py	Sat Oct 10 12:20:51 2020 +0200
@@ -10,7 +10,8 @@
 
 import xmlrpc.client as xmlrpc
 
-from PyQt5.QtCore import QObject, QUrl, QByteArray
+from PyQt5.QtCore import Qt, QObject, QUrl, QByteArray, QEventLoop
+from PyQt5.QtGui import QGuiApplication, QCursor
 from PyQt5.QtNetwork import (
     QNetworkAccessManager, QNetworkRequest, QNetworkReply
 )
@@ -77,6 +78,9 @@
         if not isinstance(args, tuple):
             raise TypeError("argument 'args' must be tuple")
         
+        QGuiApplication.setOverrideCursor(QCursor(Qt.WaitCursor))
+        QGuiApplication.processEvents(QEventLoop.ExcludeUserInputEvents)
+        
         data = xmlrpc.dumps(args, method).encode("utf-8")
         reply = self.__networkManager.post(
             self.__request, QByteArray(data))
@@ -97,6 +101,9 @@
         @param reply reference to the reply object (QNetworkReply)
         @param errors list of SSL errors (list of QSslError)
         """
+        QGuiApplication.restoreOverrideCursor()
+        QGuiApplication.processEvents(QEventLoop.ExcludeUserInputEvents)
+        
         ignored = self.__sslErrorHandler.sslErrorsReply(reply, errors)[0]
         if ignored == E5SslErrorHandler.NotIgnored and reply in self.__callmap:
             self.__callmap[reply][1](xmlrpc.TRANSPORT_ERROR, self.tr(
@@ -111,6 +118,9 @@
         if reply not in self.__callmap:
             return
         
+        QGuiApplication.restoreOverrideCursor()
+        QGuiApplication.processEvents(QEventLoop.ExcludeUserInputEvents)
+        
         if reply.error() != QNetworkReply.NoError:
             self.__callmap[reply][1](xmlrpc.TRANSPORT_ERROR,
                                      reply.errorString())
--- a/eric6/MultiProject/MultiProject.py	Fri Oct 09 17:19:29 2020 +0200
+++ b/eric6/MultiProject/MultiProject.py	Sat Oct 10 12:20:51 2020 +0200
@@ -12,9 +12,8 @@
 import shutil
 
 from PyQt5.QtCore import (
-    pyqtSignal, pyqtSlot, Qt, QFileInfo, QFile, QIODevice, QObject, QUuid
+    pyqtSignal, pyqtSlot, QFileInfo, QFile, QIODevice, QObject, QUuid
 )
-from PyQt5.QtGui import QCursor
 from PyQt5.QtWidgets import QMenu, QApplication, QDialog, QToolBar
 
 from Globals import recentNameMultiProject
@@ -22,6 +21,7 @@
 from E5Gui.E5Action import E5Action, createActionGroup
 from E5Gui import E5FileDialog, E5MessageBox, E5PathPickerDialog
 from E5Gui.E5PathPickerDialog import E5PathPickerModes
+from E5Gui.E5OverrideCursor import E5OverrideCursor
 
 import UI.PixmapCache
 
@@ -225,14 +225,14 @@
         """
         f = QFile(fn)
         if f.open(QIODevice.ReadOnly):
-            from E5XML.MultiProjectReader import MultiProjectReader
-            reader = MultiProjectReader(f, self)
-            reader.readXML()
-            f.close()
+            with E5OverrideCursor():
+                from E5XML.MultiProjectReader import MultiProjectReader
+                reader = MultiProjectReader(f, self)
+                reader.readXML()
+                f.close()
             if reader.hasError():
                 return False
         else:
-            QApplication.restoreOverrideCursor()
             E5MessageBox.critical(
                 self.ui,
                 self.tr("Read multiproject file"),
@@ -553,13 +553,10 @@
         QApplication.processEvents()
         
         if fn is not None:
-            QApplication.setOverrideCursor(QCursor(Qt.WaitCursor))
-            QApplication.processEvents()
             self.closeMultiProject()
-            if self.__readMultiProject(fn):
+            ok = self.__readMultiProject(fn)
+            if ok:
                 self.opened = True
-                QApplication.restoreOverrideCursor()
-                QApplication.processEvents()
                 
                 self.closeAct.setEnabled(True)
                 self.saveasAct.setEnabled(True)
@@ -571,8 +568,6 @@
                 if openMaster and Preferences.getMultiProject(
                         "OpenMasterAutomatically"):
                     self.__openMasterProject(False)
-            else:
-                QApplication.restoreOverrideCursor()
     
     def saveMultiProject(self):
         """
--- a/eric6/PipInterface/PipFreezeDialog.py	Fri Oct 09 17:19:29 2020 +0200
+++ b/eric6/PipInterface/PipFreezeDialog.py	Sat Oct 10 12:20:51 2020 +0200
@@ -18,6 +18,7 @@
 from E5Gui import E5MessageBox, E5FileDialog
 from E5Gui.E5PathPicker import E5PathPickerModes
 from E5Gui.E5Application import e5App
+from E5Gui.E5OverrideCursor import E5OverrideCursor
 
 from .Ui_PipFreezeDialog import Ui_PipFreezeDialog
 
@@ -62,7 +63,6 @@
         @param e close event
         @type QCloseEvent
         """
-        QApplication.restoreOverrideCursor()
         e.accept()
     
     @pyqtSlot(bool)
@@ -144,17 +144,16 @@
                 args.append("--requirement")
                 args.append(fileName)
         
-        QApplication.setOverrideCursor(Qt.WaitCursor)
-        success, output = self.__pip.runProcess(args, interpreter)
+        with E5OverrideCursor():
+            success, output = self.__pip.runProcess(args, interpreter)
+            
+            if success:
+                self.requirementsEdit.setPlainText(output)
+                self.__requirementsAvailable = True
+            else:
+                self.requirementsEdit.setPlainText(
+                    self.tr("No output generated by 'pip freeze'."))
         
-        if success:
-            self.requirementsEdit.setPlainText(output)
-            self.__requirementsAvailable = True
-        else:
-            self.requirementsEdit.setPlainText(
-                self.tr("No output generated by 'pip freeze'."))
-        
-        QApplication.restoreOverrideCursor()
         self.__updateButtons()
         
         self.__requirementsEdited = False
--- a/eric6/PipInterface/PipPackagesWidget.py	Fri Oct 09 17:19:29 2020 +0200
+++ b/eric6/PipInterface/PipPackagesWidget.py	Sat Oct 10 12:20:51 2020 +0200
@@ -11,8 +11,7 @@
 import textwrap
 import os
 
-from PyQt5.QtCore import pyqtSlot, Qt, QEventLoop, QRegExp
-from PyQt5.QtGui import QCursor
+from PyQt5.QtCore import pyqtSlot, Qt, QRegExp
 from PyQt5.QtWidgets import (
     QWidget, QToolButton, QApplication, QHeaderView, QTreeWidgetItem,
     QInputDialog, QMenu, QDialog
@@ -20,6 +19,7 @@
 
 from E5Gui.E5Application import e5App
 from E5Gui import E5MessageBox
+from E5Gui.E5OverrideCursor import E5OverrideCursor
 
 from E5Network.E5XmlRpcClient import E5XmlRpcClient
 
@@ -237,47 +237,45 @@
         if venvName:
             interpreter = self.__pip.getVirtualenvInterpreter(venvName)
             if interpreter:
-                QApplication.setOverrideCursor(QCursor(Qt.WaitCursor))
                 self.statusLabel.show()
                 self.statusLabel.setText(
                     self.tr("Getting installed packages..."))
-                QApplication.processEvents()
                 
-                # 1. populate with installed packages
-                self.packagesList.setUpdatesEnabled(False)
-                installedPackages = self.__pip.getInstalledPackages(
-                    venvName,
-                    localPackages=self.localCheckBox.isChecked(),
-                    notRequired=self.notRequiredCheckBox.isChecked(),
-                    usersite=self.userCheckBox.isChecked(),
-                )
-                for package, version in installedPackages:
-                    QTreeWidgetItem(self.packagesList, [package, version])
-                self.packagesList.setUpdatesEnabled(True)
-                self.statusLabel.setText(
-                    self.tr("Getting outdated packages..."))
-                QApplication.processEvents()
-                
-                # 2. update with update information
-                self.packagesList.setUpdatesEnabled(False)
-                outdatedPackages = self.__pip.getOutdatedPackages(
-                    venvName,
-                    localPackages=self.localCheckBox.isChecked(),
-                    notRequired=self.notRequiredCheckBox.isChecked(),
-                    usersite=self.userCheckBox.isChecked(),
-                )
-                for package, _version, latest in outdatedPackages:
-                    items = self.packagesList.findItems(
-                        package, Qt.MatchExactly | Qt.MatchCaseSensitive)
-                    if items:
-                        itm = items[0]
-                        itm.setText(2, latest)
-                
-                self.packagesList.sortItems(0, Qt.AscendingOrder)
-                for col in range(self.packagesList.columnCount()):
-                    self.packagesList.resizeColumnToContents(col)
-                self.packagesList.setUpdatesEnabled(True)
-                QApplication.restoreOverrideCursor()
+                with E5OverrideCursor():
+                    # 1. populate with installed packages
+                    self.packagesList.setUpdatesEnabled(False)
+                    installedPackages = self.__pip.getInstalledPackages(
+                        venvName,
+                        localPackages=self.localCheckBox.isChecked(),
+                        notRequired=self.notRequiredCheckBox.isChecked(),
+                        usersite=self.userCheckBox.isChecked(),
+                    )
+                    for package, version in installedPackages:
+                        QTreeWidgetItem(self.packagesList, [package, version])
+                    self.packagesList.setUpdatesEnabled(True)
+                    self.statusLabel.setText(
+                        self.tr("Getting outdated packages..."))
+                    QApplication.processEvents()
+                    
+                    # 2. update with update information
+                    self.packagesList.setUpdatesEnabled(False)
+                    outdatedPackages = self.__pip.getOutdatedPackages(
+                        venvName,
+                        localPackages=self.localCheckBox.isChecked(),
+                        notRequired=self.notRequiredCheckBox.isChecked(),
+                        usersite=self.userCheckBox.isChecked(),
+                    )
+                    for package, _version, latest in outdatedPackages:
+                        items = self.packagesList.findItems(
+                            package, Qt.MatchExactly | Qt.MatchCaseSensitive)
+                        if items:
+                            itm = items[0]
+                            itm.setText(2, latest)
+                    
+                    self.packagesList.sortItems(0, Qt.AscendingOrder)
+                    for col in range(self.packagesList.columnCount()):
+                        self.packagesList.resizeColumnToContents(col)
+                    self.packagesList.setUpdatesEnabled(True)
                 self.statusLabel.hide()
         
         self.__updateActionButtons()
@@ -339,54 +337,55 @@
             if not interpreter:
                 return
             
-            QApplication.setOverrideCursor(Qt.WaitCursor)
-            
             args = ["-m", "pip", "show"]
             if self.verboseCheckBox.isChecked():
                 args.append("--verbose")
             if self.installedFilesCheckBox.isChecked():
                 args.append("--files")
             args.append(itm.text(0))
-            success, output = self.__pip.runProcess(args, interpreter)
             
-            if success and output:
-                mode = self.ShowProcessGeneralMode
-                for line in output.splitlines():
-                    line = line.rstrip()
-                    if line != "---":
-                        if mode != self.ShowProcessGeneralMode:
-                            if line[0] == " ":
-                                QTreeWidgetItem(
-                                    self.infoWidget,
-                                    [" ", line.strip()])
-                            else:
-                                mode = self.ShowProcessGeneralMode
-                        if mode == self.ShowProcessGeneralMode:
-                            try:
-                                label, info = line.split(": ", 1)
-                            except ValueError:
-                                label = line[:-1]
-                                info = ""
-                            label = label.lower()
-                            if label in self.__infoLabels:
-                                QTreeWidgetItem(
-                                    self.infoWidget,
-                                    [self.__infoLabels[label], info])
-                            if label == "files":
-                                mode = self.ShowProcessFilesListMode
-                            elif label == "classifiers":
-                                mode = self.ShowProcessClassifiersMode
-                            elif label == "entry-points":
-                                mode = self.ShowProcessEntryPointsMode
-                self.infoWidget.scrollToTop()
-            
-            header = self.infoWidget.header()
-            header.setStretchLastSection(False)
-            header.resizeSections(QHeaderView.ResizeToContents)
-            if header.sectionSize(0) + header.sectionSize(1) < header.width():
-                header.setStretchLastSection(True)
-            
-            QApplication.restoreOverrideCursor()
+            with E5OverrideCursor():
+                success, output = self.__pip.runProcess(args, interpreter)
+                
+                if success and output:
+                    mode = self.ShowProcessGeneralMode
+                    for line in output.splitlines():
+                        line = line.rstrip()
+                        if line != "---":
+                            if mode != self.ShowProcessGeneralMode:
+                                if line[0] == " ":
+                                    QTreeWidgetItem(
+                                        self.infoWidget,
+                                        [" ", line.strip()])
+                                else:
+                                    mode = self.ShowProcessGeneralMode
+                            if mode == self.ShowProcessGeneralMode:
+                                try:
+                                    label, info = line.split(": ", 1)
+                                except ValueError:
+                                    label = line[:-1]
+                                    info = ""
+                                label = label.lower()
+                                if label in self.__infoLabels:
+                                    QTreeWidgetItem(
+                                        self.infoWidget,
+                                        [self.__infoLabels[label], info])
+                                if label == "files":
+                                    mode = self.ShowProcessFilesListMode
+                                elif label == "classifiers":
+                                    mode = self.ShowProcessClassifiersMode
+                                elif label == "entry-points":
+                                    mode = self.ShowProcessEntryPointsMode
+                    self.infoWidget.scrollToTop()
+                
+                header = self.infoWidget.header()
+                header.setStretchLastSection(False)
+                header.resizeSections(QHeaderView.ResizeToContents)
+                if (
+                    header.sectionSize(0) + header.sectionSize(1) <
+                    header.width()
+                ):
+                    header.setStretchLastSection(True)
         
         self.__updateActionButtons()
     
@@ -444,17 +443,14 @@
         self.environmentsComboBox.clear()
         self.packagesList.clear()
         
-        QApplication.setOverrideCursor(QCursor(Qt.WaitCursor))
-        QApplication.processEvents()
-        
-        self.__populateEnvironments()
+        with E5OverrideCursor():
+            self.__populateEnvironments()
+            
+            index = self.environmentsComboBox.findText(
+                currentEnvironment, Qt.MatchExactly | Qt.MatchCaseSensitive)
+            if index != -1:
+                self.environmentsComboBox.setCurrentIndex(index)
         
-        index = self.environmentsComboBox.findText(
-            currentEnvironment, Qt.MatchExactly | Qt.MatchCaseSensitive)
-        if index != -1:
-            self.environmentsComboBox.setCurrentIndex(index)
-        
-        QApplication.restoreOverrideCursor()
         self.__updateActionButtons()
     
     @pyqtSlot()
@@ -636,8 +632,6 @@
         self.searchInfoLabel.clear()
         
         self.searchButton.setEnabled(False)
-        QApplication.setOverrideCursor(Qt.WaitCursor)
-        QApplication.processEvents(QEventLoop.ExcludeUserInputEvents)
         
         self.__queryName = [
             term for term in self.searchEditName.text().strip().split()
@@ -688,7 +682,6 @@
                         count = 0
                         QApplication.processEvents()
             else:
-                QApplication.restoreOverrideCursor()
                 E5MessageBox.warning(
                     self,
                     self.tr("Search PyPI"),
@@ -698,7 +691,6 @@
                     self.tr("""<p>The package search did not return"""
                             """ anything.</p>"""))
         else:
-            QApplication.restoreOverrideCursor()
             E5MessageBox.warning(
                 self,
                 self.tr("Search PyPI"),
@@ -724,8 +716,6 @@
         """
         Private slot performing the search finishing actions.
         """
-        QApplication.restoreOverrideCursor()
-        
         self.__updateSearchActionButtons()
         self.__updateSearchButton()
         
@@ -900,12 +890,10 @@
         @param packageVersion version of the package
         @type str
         """
-        QApplication.setOverrideCursor(Qt.WaitCursor)
-        QApplication.processEvents(QEventLoop.ExcludeUserInputEvents)
+        with E5OverrideCursor():
+            packageData = self.__pip.getPackageDetails(
+                packageName, packageVersion)
         
-        packageData = self.__pip.getPackageDetails(packageName, packageVersion)
-        
-        QApplication.restoreOverrideCursor()
         if packageData:
             from .PipPackageDetailsDialog import PipPackageDetailsDialog
             
--- a/eric6/Plugins/VcsPlugins/vcsGit/GitBisectLogBrowserDialog.py	Fri Oct 09 17:19:29 2020 +0200
+++ b/eric6/Plugins/VcsPlugins/vcsGit/GitBisectLogBrowserDialog.py	Sat Oct 10 12:20:51 2020 +0200
@@ -11,13 +11,13 @@
 import os
 
 from PyQt5.QtCore import pyqtSlot, Qt, QPoint, QProcess, QTimer
-from PyQt5.QtGui import QCursor
 from PyQt5.QtWidgets import (
     QWidget, QDialogButtonBox, QHeaderView, QTreeWidgetItem, QApplication,
     QLineEdit
 )
 
 from E5Gui import E5MessageBox
+from E5Gui.E5OverrideCursor import E5OverrideCursorProcess
 
 from .Ui_GitBisectLogBrowserDialog import Ui_GitBisectLogBrowserDialog
 
@@ -64,10 +64,10 @@
         self.__initData()
         self.__resetUI()
         
-        self.process = QProcess()
-        self.process.finished.connect(self.__procFinished)
-        self.process.readyReadStandardOutput.connect(self.__readStdout)
-        self.process.readyReadStandardError.connect(self.__readStderr)
+        self.__process = E5OverrideCursorProcess()
+        self.__process.finished.connect(self.__procFinished)
+        self.__process.readyReadStandardOutput.connect(self.__readStdout)
+        self.__process.readyReadStandardError.connect(self.__readStderr)
     
     def __initData(self):
         """
@@ -82,12 +82,12 @@
         @param e close event (QCloseEvent)
         """
         if (
-            self.process is not None and
-            self.process.state() != QProcess.NotRunning
+            self.__process is not None and
+            self.__process.state() != QProcess.NotRunning
         ):
-            self.process.terminate()
-            QTimer.singleShot(2000, self.process.kill)
-            self.process.waitForFinished(3000)
+            self.__process.terminate()
+            QTimer.singleShot(2000, self.__process.kill)
+            self.__process.waitForFinished(3000)
         
         self.__position = self.pos()
         
@@ -145,9 +145,6 @@
         self.inputGroup.show()
         self.refreshButton.setEnabled(False)
         
-        QApplication.setOverrideCursor(QCursor(Qt.WaitCursor))
-        QApplication.processEvents()
-        
         self.buf = []
         self.cancelled = False
         self.errors.clear()
@@ -156,15 +153,15 @@
         args = self.vcs.initCommand("bisect")
         args.append("log")
         
-        self.process.kill()
+        self.__process.kill()
         
-        self.process.setWorkingDirectory(self.repodir)
+        self.__process.setWorkingDirectory(self.repodir)
         
         self.inputGroup.setEnabled(True)
         self.inputGroup.show()
         
-        self.process.start('git', args)
-        procStarted = self.process.waitForStarted(5000)
+        self.__process.start('git', args)
+        procStarted = self.__process.waitForStarted(5000)
         if not procStarted:
             self.inputGroup.setEnabled(False)
             self.inputGroup.hide()
@@ -216,14 +213,12 @@
         the button.
         """
         if (
-            self.process is not None and
-            self.process.state() != QProcess.NotRunning
+            self.__process is not None and
+            self.__process.state() != QProcess.NotRunning
         ):
-            self.process.terminate()
-            QTimer.singleShot(2000, self.process.kill)
-            self.process.waitForFinished(3000)
-        
-        QApplication.restoreOverrideCursor()
+            self.__process.terminate()
+            QTimer.singleShot(2000, self.__process.kill)
+            self.__process.waitForFinished(3000)
         
         self.buttonBox.button(QDialogButtonBox.Close).setEnabled(True)
         self.buttonBox.button(QDialogButtonBox.Cancel).setEnabled(False)
@@ -265,10 +260,10 @@
         
         It reads the output of the process and inserts it into a buffer.
         """
-        self.process.setReadChannel(QProcess.StandardOutput)
+        self.__process.setReadChannel(QProcess.StandardOutput)
         
-        while self.process.canReadLine():
-            line = str(self.process.readLine(),
+        while self.__process.canReadLine():
+            line = str(self.__process.readLine(),
                        Preferences.getSystem("IOEncoding"),
                        'replace')
             self.buf.append(line)
@@ -280,8 +275,8 @@
         It reads the error output of the process and inserts it into the
         error pane.
         """
-        if self.process is not None:
-            s = str(self.process.readAllStandardError(),
+        if self.__process is not None:
+            s = str(self.__process.readAllStandardError(),
                     Preferences.getSystem("IOEncoding"),
                     'replace')
             self.__showError(s)
@@ -351,7 +346,7 @@
             self.errors.ensureCursorVisible()
         self.errorGroup.show()
         
-        self.process.write(strToQByteArray(inputTxt))
+        self.__process.write(strToQByteArray(inputTxt))
         
         self.passwordCheckBox.setChecked(False)
         self.input.clear()
--- a/eric6/Plugins/VcsPlugins/vcsGit/GitDiffDialog.py	Fri Oct 09 17:19:29 2020 +0200
+++ b/eric6/Plugins/VcsPlugins/vcsGit/GitDiffDialog.py	Sat Oct 10 12:20:51 2020 +0200
@@ -10,8 +10,8 @@
 
 
 from PyQt5.QtCore import pyqtSlot, QFileInfo, Qt
-from PyQt5.QtGui import QTextCursor, QCursor
-from PyQt5.QtWidgets import QWidget, QDialogButtonBox, QApplication
+from PyQt5.QtGui import QTextCursor
+from PyQt5.QtWidgets import QWidget, QDialogButtonBox
 
 from E5Gui import E5MessageBox, E5FileDialog
 from E5Gui.E5Application import e5App
@@ -169,11 +169,9 @@
             self.contentsGroup.setTitle(
                 self.tr("Difference ({0})").format(msg))
         
-        QApplication.setOverrideCursor(QCursor(Qt.WaitCursor))
         procStarted = self.__diffGenerator.start(
             fn, versions=versions, diffMode=diffMode, stashName=stashName)
         if not procStarted:
-            QApplication.restoreOverrideCursor()
             E5MessageBox.critical(
                 self,
                 self.tr('Process Generation Error'),
@@ -187,7 +185,6 @@
         """
         Private slot connected to the finished signal.
         """
-        QApplication.restoreOverrideCursor()
         self.refreshButton.setEnabled(True)
         
         diff1, diff2, errors, fileSeparators = self.__diffGenerator.getResult()
--- a/eric6/Plugins/VcsPlugins/vcsGit/GitDiffGenerator.py	Fri Oct 09 17:19:29 2020 +0200
+++ b/eric6/Plugins/VcsPlugins/vcsGit/GitDiffGenerator.py	Sat Oct 10 12:20:51 2020 +0200
@@ -13,6 +13,8 @@
 
 from PyQt5.QtCore import pyqtSignal, QProcess, QTimer, QObject
 
+from E5Gui.E5OverrideCursor import E5OverrideCursorProcess
+
 import Preferences
 
 
@@ -35,25 +37,25 @@
         
         self.vcs = vcs
         
-        self.process = QProcess()
-        self.process.finished.connect(self.__procFinished)
-        self.process.readyReadStandardOutput.connect(
-            lambda: self.__readStdout(self.process))
-        self.process.readyReadStandardError.connect(
-            lambda: self.__readStderr(self.process))
+        self.__process = E5OverrideCursorProcess()
+        self.__process.finished.connect(self.__procFinished)
+        self.__process.readyReadStandardOutput.connect(
+            lambda: self.__readStdout(self.__process))
+        self.__process.readyReadStandardError.connect(
+            lambda: self.__readStderr(self.__process))
         
-        self.process2 = QProcess()
-        self.process2.finished.connect(self.__procFinished)
-        self.process2.readyReadStandardOutput.connect(
-            lambda: self.__readStdout(self.process2))
-        self.process2.readyReadStandardError.connect(
-            lambda: self.__readStderr(self.process2))
+        self.__process2 = E5OverrideCursorProcess()
+        self.__process2.finished.connect(self.__procFinished)
+        self.__process2.readyReadStandardOutput.connect(
+            lambda: self.__readStdout(self.__process2))
+        self.__process2.readyReadStandardError.connect(
+            lambda: self.__readStderr(self.__process2))
     
     def stopProcesses(self):
         """
         Public slot to stop the diff processes.
         """
-        for process in [self.process, self.process2]:
+        for process in [self.__process, self.__process2]:
             if (
                 process is not None and
                 process.state() != QProcess.NotRunning
@@ -139,18 +141,18 @@
             if os.path.splitdrive(repodir)[1] == os.sep:
                 return False
         
-        self.process.kill()
-        self.process.setWorkingDirectory(repodir)
-        self.process.start('git', args)
-        procStarted = self.process.waitForStarted(5000)
+        self.__process.kill()
+        self.__process.setWorkingDirectory(repodir)
+        self.__process.start('git', args)
+        procStarted = self.__process.waitForStarted(5000)
         if not procStarted:
             return False
         
         if diffMode == "work2stage2repo":
-            self.process2.kill()
-            self.process2.setWorkingDirectory(repodir)
-            self.process2.start('git', args2)
-            procStarted = self.process2.waitForStarted(5000)
+            self.__process2.kill()
+            self.__process2.setWorkingDirectory(repodir)
+            self.__process2.start('git', args2)
+            procStarted = self.__process2.waitForStarted(5000)
             if not procStarted:
                 return False
         
@@ -164,8 +166,8 @@
         @param exitStatus exit status of the process (QProcess.ExitStatus)
         """
         if (
-            self.process.state() == QProcess.NotRunning and
-            self.process2.state() == QProcess.NotRunning
+            self.__process.state() == QProcess.NotRunning and
+            self.__process2.state() == QProcess.NotRunning
         ):
             self.finished.emit()
     
@@ -226,7 +228,7 @@
         """
         process.setReadChannel(QProcess.StandardOutput)
         
-        isTopDiff = process == self.process
+        isTopDiff = process == self.__process
         
         while process.canReadLine():
             line = str(process.readLine(), self.__ioEncoding,
--- a/eric6/Plugins/VcsPlugins/vcsGit/GitLogBrowserDialog.py	Fri Oct 09 17:19:29 2020 +0200
+++ b/eric6/Plugins/VcsPlugins/vcsGit/GitLogBrowserDialog.py	Sat Oct 10 12:20:51 2020 +0200
@@ -15,7 +15,7 @@
     pyqtSlot, Qt, QDate, QProcess, QTimer, QRegExp, QSize, QPoint, QFileInfo
 )
 from PyQt5.QtGui import (
-    QCursor, QColor, QPixmap, QPainter, QPen, QIcon, QTextCursor, QPalette
+    QColor, QPixmap, QPainter, QPen, QIcon, QTextCursor, QPalette
 )
 from PyQt5.QtWidgets import (
     QWidget, QDialogButtonBox, QHeaderView, QTreeWidgetItem, QApplication,
@@ -24,6 +24,7 @@
 
 from E5Gui.E5Application import e5App
 from E5Gui import E5MessageBox, E5FileDialog
+from E5Gui.E5OverrideCursor import E5OverrideCursorProcess
 
 from Globals import strToQByteArray
 
@@ -194,10 +195,10 @@
         # roles used in the file tree
         self.__diffFileLineRole = Qt.UserRole
         
-        self.process = QProcess()
-        self.process.finished.connect(self.__procFinished)
-        self.process.readyReadStandardOutput.connect(self.__readStdout)
-        self.process.readyReadStandardError.connect(self.__readStderr)
+        self.__process = E5OverrideCursorProcess()
+        self.__process.finished.connect(self.__procFinished)
+        self.__process.readyReadStandardOutput.connect(self.__readStdout)
+        self.__process.readyReadStandardError.connect(self.__readStderr)
         
         self.flags = {
             'A': self.tr('Added'),
@@ -383,12 +384,12 @@
         @param e close event (QCloseEvent)
         """
         if (
-            self.process is not None and
-            self.process.state() != QProcess.NotRunning
+            self.__process is not None and
+            self.__process.state() != QProcess.NotRunning
         ):
-            self.process.terminate()
-            QTimer.singleShot(2000, self.process.kill)
-            self.process.waitForFinished(3000)
+            self.__process.terminate()
+            QTimer.singleShot(2000, self.__process.kill)
+            self.__process.waitForFinished(3000)
         
         self.vcs.getPlugin().setPreferences(
             "LogBrowserGeometry", self.saveGeometry())
@@ -782,9 +783,6 @@
         self.buttonBox.button(QDialogButtonBox.Cancel).setDefault(True)
         QApplication.processEvents()
         
-        QApplication.setOverrideCursor(QCursor(Qt.WaitCursor))
-        QApplication.processEvents()
-        
         self.buf = []
         self.cancelled = False
         self.errors.clear()
@@ -810,12 +808,12 @@
             args.append('--')
             args.append(self.__filename)
         
-        self.process.kill()
+        self.__process.kill()
         
-        self.process.setWorkingDirectory(self.repodir)
+        self.__process.setWorkingDirectory(self.repodir)
         
-        self.process.start('git', args)
-        procStarted = self.process.waitForStarted(5000)
+        self.__process.start('git', args)
+        procStarted = self.__process.waitForStarted(5000)
         if not procStarted:
             self.inputGroup.setEnabled(False)
             self.inputGroup.hide()
@@ -881,14 +879,12 @@
         the button.
         """
         if (
-            self.process is not None and
-            self.process.state() != QProcess.NotRunning
+            self.__process is not None and
+            self.__process.state() != QProcess.NotRunning
         ):
-            self.process.terminate()
-            QTimer.singleShot(2000, self.process.kill)
-            self.process.waitForFinished(3000)
-        
-        QApplication.restoreOverrideCursor()
+            self.__process.terminate()
+            QTimer.singleShot(2000, self.__process.kill)
+            self.__process.waitForFinished(3000)
         
         self.buttonBox.button(QDialogButtonBox.Close).setEnabled(True)
         self.buttonBox.button(QDialogButtonBox.Cancel).setEnabled(False)
@@ -1052,10 +1048,10 @@
         
         It reads the output of the process and inserts it into a buffer.
         """
-        self.process.setReadChannel(QProcess.StandardOutput)
+        self.__process.setReadChannel(QProcess.StandardOutput)
         
-        while self.process.canReadLine():
-            line = str(self.process.readLine(),
+        while self.__process.canReadLine():
+            line = str(self.__process.readLine(),
                        Preferences.getSystem("IOEncoding"),
                        'replace')
             self.buf.append(line)
@@ -1067,8 +1063,8 @@
         It reads the error output of the process and inserts it into the
         error pane.
         """
-        if self.process is not None:
-            s = str(self.process.readAllStandardError(),
+        if self.__process is not None:
+            s = str(self.__process.readAllStandardError(),
                     Preferences.getSystem("IOEncoding"),
                     'replace')
             self.__showError(s)
@@ -1147,7 +1143,7 @@
             self.errors.ensureCursorVisible()
         self.errorGroup.show()
         
-        self.process.write(strToQByteArray(inputTxt))
+        self.__process.write(strToQByteArray(inputTxt))
         
         self.passwordCheckBox.setChecked(False)
         self.input.clear()
--- a/eric6/Plugins/VcsPlugins/vcsGit/GitReflogBrowserDialog.py	Fri Oct 09 17:19:29 2020 +0200
+++ b/eric6/Plugins/VcsPlugins/vcsGit/GitReflogBrowserDialog.py	Sat Oct 10 12:20:51 2020 +0200
@@ -11,13 +11,13 @@
 import os
 
 from PyQt5.QtCore import pyqtSlot, Qt, QProcess, QTimer, QPoint
-from PyQt5.QtGui import QCursor
 from PyQt5.QtWidgets import (
     QWidget, QDialogButtonBox, QHeaderView, QTreeWidgetItem, QApplication,
     QLineEdit
 )
 
 from E5Gui import E5MessageBox
+from E5Gui.E5OverrideCursor import E5OverrideCursorProcess
 
 from .Ui_GitReflogBrowserDialog import Ui_GitReflogBrowserDialog
 
@@ -75,10 +75,10 @@
         self.__initData()
         self.__resetUI()
         
-        self.process = QProcess()
-        self.process.finished.connect(self.__procFinished)
-        self.process.readyReadStandardOutput.connect(self.__readStdout)
-        self.process.readyReadStandardError.connect(self.__readStderr)
+        self.__process = E5OverrideCursorProcess()
+        self.__process.finished.connect(self.__procFinished)
+        self.__process.readyReadStandardOutput.connect(self.__readStdout)
+        self.__process.readyReadStandardError.connect(self.__readStderr)
     
     def __initData(self):
         """
@@ -95,12 +95,12 @@
         @param e close event (QCloseEvent)
         """
         if (
-            self.process is not None and
-            self.process.state() != QProcess.NotRunning
+            self.__process is not None and
+            self.__process.state() != QProcess.NotRunning
         ):
-            self.process.terminate()
-            QTimer.singleShot(2000, self.process.kill)
-            self.process.waitForFinished(3000)
+            self.__process.terminate()
+            QTimer.singleShot(2000, self.__process.kill)
+            self.__process.waitForFinished(3000)
         
         self.__position = self.pos()
         
@@ -165,9 +165,6 @@
         self.buttonBox.button(QDialogButtonBox.Cancel).setDefault(True)
         QApplication.processEvents()
         
-        QApplication.setOverrideCursor(QCursor(Qt.WaitCursor))
-        QApplication.processEvents()
-        
         self.buf = []
         self.cancelled = False
         self.errors.clear()
@@ -181,15 +178,15 @@
         args.append('--format={0}'.format(self.__formatTemplate))
         args.append('--skip={0}'.format(skip))
         
-        self.process.kill()
+        self.__process.kill()
         
-        self.process.setWorkingDirectory(self.repodir)
+        self.__process.setWorkingDirectory(self.repodir)
         
         self.inputGroup.setEnabled(True)
         self.inputGroup.show()
         
-        self.process.start('git', args)
-        procStarted = self.process.waitForStarted(5000)
+        self.__process.start('git', args)
+        procStarted = self.__process.waitForStarted(5000)
         if not procStarted:
             self.inputGroup.setEnabled(False)
             self.inputGroup.hide()
@@ -242,14 +239,12 @@
         the button.
         """
         if (
-            self.process is not None and
-            self.process.state() != QProcess.NotRunning
+            self.__process is not None and
+            self.__process.state() != QProcess.NotRunning
         ):
-            self.process.terminate()
-            QTimer.singleShot(2000, self.process.kill)
-            self.process.waitForFinished(3000)
-        
-        QApplication.restoreOverrideCursor()
+            self.__process.terminate()
+            QTimer.singleShot(2000, self.__process.kill)
+            self.__process.waitForFinished(3000)
         
         self.buttonBox.button(QDialogButtonBox.Close).setEnabled(True)
         self.buttonBox.button(QDialogButtonBox.Cancel).setEnabled(False)
@@ -313,10 +308,10 @@
         
         It reads the output of the process and inserts it into a buffer.
         """
-        self.process.setReadChannel(QProcess.StandardOutput)
+        self.__process.setReadChannel(QProcess.StandardOutput)
         
-        while self.process.canReadLine():
-            line = str(self.process.readLine(),
+        while self.__process.canReadLine():
+            line = str(self.__process.readLine(),
                        Preferences.getSystem("IOEncoding"),
                        'replace')
             self.buf.append(line)
@@ -328,8 +323,8 @@
         It reads the error output of the process and inserts it into the
         error pane.
         """
-        if self.process is not None:
-            s = str(self.process.readAllStandardError(),
+        if self.__process is not None:
+            s = str(self.__process.readAllStandardError(),
                     Preferences.getSystem("IOEncoding"),
                     'replace')
             self.__showError(s)
@@ -399,7 +394,7 @@
             self.errors.ensureCursorVisible()
         self.errorGroup.show()
         
-        self.process.write(strToQByteArray(inputTxt))
+        self.__process.write(strToQByteArray(inputTxt))
         
         self.passwordCheckBox.setChecked(False)
         self.input.clear()
--- a/eric6/Plugins/VcsPlugins/vcsGit/GitStashBrowserDialog.py	Fri Oct 09 17:19:29 2020 +0200
+++ b/eric6/Plugins/VcsPlugins/vcsGit/GitStashBrowserDialog.py	Sat Oct 10 12:20:51 2020 +0200
@@ -11,13 +11,13 @@
 import os
 
 from PyQt5.QtCore import pyqtSlot, Qt, QPoint, QProcess, QTimer
-from PyQt5.QtGui import QCursor
 from PyQt5.QtWidgets import (
     QWidget, QDialogButtonBox, QTreeWidgetItem, QAbstractButton, QMenu,
     QHeaderView, QApplication, QLineEdit
 )
 
 from E5Gui import E5MessageBox
+from E5Gui.E5OverrideCursor import E5OverrideCursorProcess
 
 from .Ui_GitStashBrowserDialog import Ui_GitStashBrowserDialog
 
@@ -69,10 +69,10 @@
         
         self.__ioEncoding = Preferences.getSystem("IOEncoding")
         
-        self.process = QProcess()
-        self.process.finished.connect(self.__procFinished)
-        self.process.readyReadStandardOutput.connect(self.__readStdout)
-        self.process.readyReadStandardError.connect(self.__readStderr)
+        self.__process = E5OverrideCursorProcess()
+        self.__process.finished.connect(self.__procFinished)
+        self.__process.readyReadStandardOutput.connect(self.__readStdout)
+        self.__process.readyReadStandardError.connect(self.__readStderr)
         
         self.__contextMenu = QMenu()
         self.__differencesAct = self.__contextMenu.addAction(
@@ -98,12 +98,12 @@
         @param e close event (QCloseEvent)
         """
         if (
-            self.process is not None and
-            self.process.state() != QProcess.NotRunning
+            self.__process is not None and
+            self.__process.state() != QProcess.NotRunning
         ):
-            self.process.terminate()
-            QTimer.singleShot(2000, self.process.kill)
-            self.process.waitForFinished(3000)
+            self.__process.terminate()
+            QTimer.singleShot(2000, self.__process.kill)
+            self.__process.waitForFinished(3000)
         
         self.__position = self.pos()
         
@@ -154,9 +154,6 @@
         self.inputGroup.show()
         self.refreshButton.setEnabled(False)
         
-        QApplication.setOverrideCursor(QCursor(Qt.WaitCursor))
-        QApplication.processEvents()
-        
         self.buf = []
         self.errors.clear()
         self.intercept = False
@@ -165,15 +162,15 @@
         args.append("list")
         args.append("--format=format:%gd{0}%ai{0}%gs%n".format(self.Separator))
         
-        self.process.kill()
+        self.__process.kill()
         
-        self.process.setWorkingDirectory(self.repodir)
+        self.__process.setWorkingDirectory(self.repodir)
         
         self.inputGroup.setEnabled(True)
         self.inputGroup.show()
         
-        self.process.start('git', args)
-        procStarted = self.process.waitForStarted(5000)
+        self.__process.start('git', args)
+        procStarted = self.__process.waitForStarted(5000)
         if not procStarted:
             self.inputGroup.setEnabled(False)
             self.inputGroup.hide()
@@ -226,14 +223,12 @@
         the button.
         """
         if (
-            self.process is not None and
-            self.process.state() != QProcess.NotRunning
+            self.__process is not None and
+            self.__process.state() != QProcess.NotRunning
         ):
-            self.process.terminate()
-            QTimer.singleShot(2000, self.process.kill)
-            self.process.waitForFinished(3000)
-        
-        QApplication.restoreOverrideCursor()
+            self.__process.terminate()
+            QTimer.singleShot(2000, self.__process.kill)
+            self.__process.waitForFinished(3000)
         
         self.buttonBox.button(QDialogButtonBox.Close).setEnabled(True)
         self.buttonBox.button(QDialogButtonBox.Cancel).setEnabled(False)
@@ -264,10 +259,10 @@
         
         It reads the output of the process and inserts it into a buffer.
         """
-        self.process.setReadChannel(QProcess.StandardOutput)
+        self.__process.setReadChannel(QProcess.StandardOutput)
         
-        while self.process.canReadLine():
-            line = str(self.process.readLine(), self.__ioEncoding,
+        while self.__process.canReadLine():
+            line = str(self.__process.readLine(), self.__ioEncoding,
                        'replace').strip()
             if line:
                 self.buf.append(line)
@@ -279,8 +274,8 @@
         It reads the error output of the process and inserts it into the
         error pane.
         """
-        if self.process is not None:
-            s = str(self.process.readAllStandardError(),
+        if self.__process is not None:
+            s = str(self.__process.readAllStandardError(),
                     self.__ioEncoding, 'replace')
             self.errorGroup.show()
             self.errors.insertPlainText(s)
@@ -413,7 +408,7 @@
             self.errors.ensureCursorVisible()
         self.errorGroup.show()
         
-        self.process.write(strToQByteArray(inputTxt))
+        self.__process.write(strToQByteArray(inputTxt))
         
         self.passwordCheckBox.setChecked(False)
         self.input.clear()
--- a/eric6/Plugins/VcsPlugins/vcsMercurial/HgConflictsListDialog.py	Fri Oct 09 17:19:29 2020 +0200
+++ b/eric6/Plugins/VcsPlugins/vcsMercurial/HgConflictsListDialog.py	Sat Oct 10 12:20:51 2020 +0200
@@ -132,8 +132,6 @@
         Private slot called when the process finished or the user pressed
         the button.
         """
-        QApplication.restoreOverrideCursor()
-        
         self.buttonBox.button(QDialogButtonBox.Close).setEnabled(True)
         self.buttonBox.button(QDialogButtonBox.Cancel).setEnabled(False)
         self.buttonBox.button(QDialogButtonBox.Close).setDefault(True)
--- a/eric6/Plugins/VcsPlugins/vcsMercurial/HgDiffDialog.py	Fri Oct 09 17:19:29 2020 +0200
+++ b/eric6/Plugins/VcsPlugins/vcsMercurial/HgDiffDialog.py	Sat Oct 10 12:20:51 2020 +0200
@@ -9,8 +9,8 @@
 
 
 from PyQt5.QtCore import pyqtSlot, QFileInfo, Qt
-from PyQt5.QtGui import QTextCursor, QCursor
-from PyQt5.QtWidgets import QWidget, QDialogButtonBox, QApplication
+from PyQt5.QtGui import QTextCursor
+from PyQt5.QtWidgets import QWidget, QDialogButtonBox
 
 from E5Gui import E5MessageBox, E5FileDialog
 from E5Gui.E5Application import e5App
@@ -95,7 +95,6 @@
         self.raise_()
         self.activateWindow()
         
-        QApplication.setOverrideCursor(QCursor(Qt.WaitCursor))
         procStarted = self.__diffGenerator.start(
             fn, versions=versions, bundle=bundle, qdiff=qdiff)
         if not procStarted:
@@ -111,7 +110,6 @@
         """
         Private slot connected to the finished signal.
         """
-        QApplication.restoreOverrideCursor()
         self.refreshButton.setEnabled(True)
         
         diff, errors, fileSeparators = self.__diffGenerator.getResult()
--- a/eric6/Plugins/VcsPlugins/vcsMercurial/HgDiffGenerator.py	Fri Oct 09 17:19:29 2020 +0200
+++ b/eric6/Plugins/VcsPlugins/vcsMercurial/HgDiffGenerator.py	Sat Oct 10 12:20:51 2020 +0200
@@ -11,6 +11,8 @@
 
 from PyQt5.QtCore import pyqtSignal, QObject
 
+from E5Gui.E5OverrideCursor import E5OverrideCursor
+
 
 class HgDiffGenerator(QObject):
     """
@@ -64,59 +66,60 @@
         @return flag indicating a successful start of the diff command
             (boolean)
         """
-        if qdiff:
-            args = self.vcs.initCommand("qdiff")
-        else:
-            args = self.vcs.initCommand("diff")
-            
-            if self.vcs.hasSubrepositories():
-                args.append("--subrepos")
-            
-            if bundle:
-                args.append('--repository')
-                args.append(bundle)
-            elif self.vcs.bundleFile and os.path.exists(self.vcs.bundleFile):
-                args.append('--repository')
-                args.append(self.vcs.bundleFile)
-            
-            if versions is not None:
-                rev1 = self.__getVersionArg(versions[0])
-                rev2 = None
-                if len(versions) == 2:
-                    rev2 = self.__getVersionArg(versions[1])
+        with E5OverrideCursor():
+            if qdiff:
+                args = self.vcs.initCommand("qdiff")
+            else:
+                args = self.vcs.initCommand("diff")
+                
+                if self.vcs.hasSubrepositories():
+                    args.append("--subrepos")
+                
+                if bundle:
+                    args.append('--repository')
+                    args.append(bundle)
+                elif self.vcs.bundleFile and os.path.exists(self.vcs.bundleFile):
+                    args.append('--repository')
+                    args.append(self.vcs.bundleFile)
                 
-                if rev1 is not None or rev2 is not None:
-                    args.append('-r')
-                    if rev1 is not None and rev2 is not None:
-                        args.append('{0}:{1}'.format(rev1, rev2))
-                    elif rev2 is None:
-                        args.append(rev1)
-                    elif rev1 is None:
-                        args.append(':{0}'.format(rev2))
-        
-        if isinstance(fn, list):
-            dname, fnames = self.vcs.splitPathList(fn)
-            self.vcs.addArguments(args, fn)
-        else:
-            dname, fname = self.vcs.splitPath(fn)
-            args.append(fn)
-        
-        self.__oldFile = ""
-        self.__oldFileLine = -1
-        self.__fileSeparators = []
-        self.__output = []
-        self.__errors = []
-        
-        out, err = self.__hgClient.runcommand(args)
-        
-        if err:
-            self.__errors = err.splitlines(True)
-        
-        if out:
-            for line in out.splitlines(True):
-                self.__processOutputLine(line)
-                if self.__hgClient.wasCanceled():
-                    break
+                if versions is not None:
+                    rev1 = self.__getVersionArg(versions[0])
+                    rev2 = None
+                    if len(versions) == 2:
+                        rev2 = self.__getVersionArg(versions[1])
+                    
+                    if rev1 is not None or rev2 is not None:
+                        args.append('-r')
+                        if rev1 is not None and rev2 is not None:
+                            args.append('{0}:{1}'.format(rev1, rev2))
+                        elif rev2 is None:
+                            args.append(rev1)
+                        elif rev1 is None:
+                            args.append(':{0}'.format(rev2))
+            
+            if isinstance(fn, list):
+                dname, fnames = self.vcs.splitPathList(fn)
+                self.vcs.addArguments(args, fn)
+            else:
+                dname, fname = self.vcs.splitPath(fn)
+                args.append(fn)
+            
+            self.__oldFile = ""
+            self.__oldFileLine = -1
+            self.__fileSeparators = []
+            self.__output = []
+            self.__errors = []
+            
+            out, err = self.__hgClient.runcommand(args)
+            
+            if err:
+                self.__errors = err.splitlines(True)
+            
+            if out:
+                for line in out.splitlines(True):
+                    self.__processOutputLine(line)
+                    if self.__hgClient.wasCanceled():
+                        break
         
         self.__finish()
         
--- a/eric6/Plugins/VcsPlugins/vcsMercurial/HgLogBrowserDialog.py	Fri Oct 09 17:19:29 2020 +0200
+++ b/eric6/Plugins/VcsPlugins/vcsMercurial/HgLogBrowserDialog.py	Sat Oct 10 12:20:51 2020 +0200
@@ -13,8 +13,7 @@
 
 from PyQt5.QtCore import pyqtSlot, Qt, QDate, QRegExp, QSize, QPoint, QFileInfo
 from PyQt5.QtGui import (
-    QCursor, QColor, QPixmap, QPainter, QPen, QBrush, QIcon, QTextCursor,
-    QPalette
+    QColor, QPixmap, QPainter, QPen, QBrush, QIcon, QTextCursor, QPalette
 )
 from PyQt5.QtWidgets import (
     QWidget, QDialogButtonBox, QHeaderView, QTreeWidgetItem, QApplication,
@@ -23,6 +22,7 @@
 
 from E5Gui.E5Application import e5App
 from E5Gui import E5MessageBox, E5FileDialog
+from E5Gui.E5OverrideCursor import E5OverrideCursor
 
 from .Ui_HgLogBrowserDialog import Ui_HgLogBrowserDialog
 
@@ -968,89 +968,87 @@
         self.buttonBox.button(QDialogButtonBox.Cancel).setDefault(True)
         QApplication.processEvents()
         
-        QApplication.setOverrideCursor(QCursor(Qt.WaitCursor))
-        QApplication.processEvents()
-        
-        self.buf = []
-        self.cancelled = False
-        self.errors.clear()
-        self.intercept = False
-        
-        if noEntries == 0:
-            noEntries = self.limitSpinBox.value()
-        
-        preargs = []
-        args = self.vcs.initCommand(self.commandMode)
-        args.append('--verbose')
-        if self.commandMode not in ("incoming", "outgoing"):
-            args.append('--limit')
-            args.append(str(noEntries))
-        if self.commandMode in ("incoming", "outgoing"):
-            args.append("--newest-first")
-            if self.vcs.hasSubrepositories():
-                args.append("--subrepos")
-        if startRev is not None:
-            args.append('--rev')
-            args.append('{0}:0'.format(startRev))
-        if (
-            not self.projectMode and
-            not self.fname == "." and
-            not self.stopCheckBox.isChecked()
-        ):
-            args.append('--follow')
-        if self.commandMode == "log":
-            args.append('--copies')
-        args.append('--template')
-        args.append(os.path.join(os.path.dirname(__file__),
-                                 "templates",
-                                 "logBrowserBookmarkPhase.tmpl"))
-        if self.commandMode == "incoming":
-            if self.__bundle:
-                args.append(self.__bundle)
-            elif not self.vcs.hasSubrepositories():
-                project = e5App().getObject("Project")
-                self.vcs.bundleFile = os.path.join(
-                    project.getProjectManagementDir(), "hg-bundle.hg")
-                if os.path.exists(self.vcs.bundleFile):
-                    os.remove(self.vcs.bundleFile)
-                preargs = args[:]
-                preargs.append("--quiet")
-                preargs.append('--bundle')
-                preargs.append(self.vcs.bundleFile)
-                args.append(self.vcs.bundleFile)
-        if not self.projectMode:
-            args.append(self.__filename)
-        
-        if preargs:
-            out, err = self.__hgClient.runcommand(preargs)
-        else:
-            err = ""
-        if err:
+        with E5OverrideCursor():
+            self.buf = []
+            self.cancelled = False
+            self.errors.clear()
+            self.intercept = False
+            
+            if noEntries == 0:
+                noEntries = self.limitSpinBox.value()
+            
+            preargs = []
+            args = self.vcs.initCommand(self.commandMode)
+            args.append('--verbose')
+            if self.commandMode not in ("incoming", "outgoing"):
+                args.append('--limit')
+                args.append(str(noEntries))
+            if self.commandMode in ("incoming", "outgoing"):
+                args.append("--newest-first")
+                if self.vcs.hasSubrepositories():
+                    args.append("--subrepos")
+            if startRev is not None:
+                args.append('--rev')
+                args.append('{0}:0'.format(startRev))
             if (
+                not self.projectMode and
+                not self.fname == "." and
+                not self.stopCheckBox.isChecked()
+            ):
+                args.append('--follow')
+            if self.commandMode == "log":
+                args.append('--copies')
+            args.append('--template')
+            args.append(os.path.join(os.path.dirname(__file__),
+                                     "templates",
+                                     "logBrowserBookmarkPhase.tmpl"))
+            if self.commandMode == "incoming":
+                if self.__bundle:
+                    args.append(self.__bundle)
+                elif not self.vcs.hasSubrepositories():
+                    project = e5App().getObject("Project")
+                    self.vcs.bundleFile = os.path.join(
+                        project.getProjectManagementDir(), "hg-bundle.hg")
+                    if os.path.exists(self.vcs.bundleFile):
+                        os.remove(self.vcs.bundleFile)
+                    preargs = args[:]
+                    preargs.append("--quiet")
+                    preargs.append('--bundle')
+                    preargs.append(self.vcs.bundleFile)
+                    args.append(self.vcs.bundleFile)
+            if not self.projectMode:
+                args.append(self.__filename)
+            
+            if preargs:
+                out, err = self.__hgClient.runcommand(preargs)
+            else:
+                err = ""
+            if err:
+                if (
+                    self.commandMode == "incoming" and
+                    self.initialCommandMode == "full_log"
+                ):
+                    # ignore the error
+                    self.commandMode = "log"
+                else:
+                    self.__showError(err)
+            elif (
+                self.commandMode != "incoming" or
+                (self.vcs.bundleFile and
+                 os.path.exists(self.vcs.bundleFile)) or
+                self.__bundle
+            ):
+                out, err = self.__hgClient.runcommand(args)
+                self.buf = out.splitlines(True)
+                if err:
+                    self.__showError(err)
+                self.__processBuffer()
+            elif (
                 self.commandMode == "incoming" and
                 self.initialCommandMode == "full_log"
             ):
-                # ignore the error
+                # no incoming changesets, just switch to log mode
                 self.commandMode = "log"
-            else:
-                self.__showError(err)
-        elif (
-            self.commandMode != "incoming" or
-            (self.vcs.bundleFile and
-             os.path.exists(self.vcs.bundleFile)) or
-            self.__bundle
-        ):
-            out, err = self.__hgClient.runcommand(args)
-            self.buf = out.splitlines(True)
-            if err:
-                self.__showError(err)
-            self.__processBuffer()
-        elif (
-            self.commandMode == "incoming" and
-            self.initialCommandMode == "full_log"
-        ):
-            # no incoming changesets, just switch to log mode
-            self.commandMode = "log"
         self.__finish()
     
     def start(self, fn, bundle=None, isFile=False, noEntries=0):
@@ -1109,8 +1107,6 @@
         Private slot called when the process finished or the user pressed
         the button.
         """
-        QApplication.restoreOverrideCursor()
-        
         self.buttonBox.button(QDialogButtonBox.Close).setEnabled(True)
         self.buttonBox.button(QDialogButtonBox.Cancel).setEnabled(False)
         self.buttonBox.button(QDialogButtonBox.Close).setDefault(True)
--- a/eric6/Plugins/VcsPlugins/vcsMercurial/ShelveExtension/HgShelveBrowserDialog.py	Fri Oct 09 17:19:29 2020 +0200
+++ b/eric6/Plugins/VcsPlugins/vcsMercurial/ShelveExtension/HgShelveBrowserDialog.py	Sat Oct 10 12:20:51 2020 +0200
@@ -10,12 +10,13 @@
 import os
 
 from PyQt5.QtCore import pyqtSlot, Qt, QPoint
-from PyQt5.QtGui import QCursor
 from PyQt5.QtWidgets import (
     QWidget, QDialogButtonBox, QTreeWidgetItem, QAbstractButton, QMenu,
     QHeaderView, QApplication
 )
 
+from E5Gui.E5OverrideCursor import E5OverrideCursor
+
 from .Ui_HgShelveBrowserDialog import Ui_HgShelveBrowserDialog
 
 
@@ -129,9 +130,6 @@
         self.buttonBox.button(QDialogButtonBox.Cancel).setDefault(True)
         QApplication.processEvents()
         
-        QApplication.setOverrideCursor(QCursor(Qt.WaitCursor))
-        QApplication.processEvents()
-        
         self.buf = []
         self.errors.clear()
         self.intercept = False
@@ -140,11 +138,12 @@
         args.append("--list")
         args.append("--stat")
         
-        out, err = self.__hgClient.runcommand(args)
-        self.buf = out.splitlines(True)
-        if err:
-            self.__showError(err)
-        self.__processBuffer()
+        with E5OverrideCursor():
+            out, err = self.__hgClient.runcommand(args)
+            self.buf = out.splitlines(True)
+            if err:
+                self.__showError(err)
+            self.__processBuffer()
         self.__finish()
     
     def start(self, projectDir):
@@ -177,8 +176,6 @@
         Private slot called when the process finished or the user pressed
         the button.
         """
-        QApplication.restoreOverrideCursor()
-        
         self.buttonBox.button(QDialogButtonBox.Close).setEnabled(True)
         self.buttonBox.button(QDialogButtonBox.Cancel).setEnabled(False)
         self.buttonBox.button(QDialogButtonBox.Close).setDefault(True)
--- a/eric6/Plugins/VcsPlugins/vcsPySvn/SvnChangeListsDialog.py	Fri Oct 09 17:19:29 2020 +0200
+++ b/eric6/Plugins/VcsPlugins/vcsPySvn/SvnChangeListsDialog.py	Sat Oct 10 12:20:51 2020 +0200
@@ -7,16 +7,14 @@
 Module implementing a dialog to browse the change lists.
 """
 
-
 import os
 
 import pysvn
 
 from PyQt5.QtCore import pyqtSlot, Qt, QMutexLocker
-from PyQt5.QtGui import QCursor
-from PyQt5.QtWidgets import (
-    QDialog, QDialogButtonBox, QListWidgetItem, QApplication
-)
+from PyQt5.QtWidgets import QDialog, QDialogButtonBox, QListWidgetItem
+
+from E5Gui.E5OverrideCursor import E5OverrideCursor
 
 from .SvnDialogMixin import SvnDialogMixin
 
@@ -78,24 +76,22 @@
         self.filesLabel.setText(
             self.tr("Files (relative to {0}):").format(path))
         
-        QApplication.setOverrideCursor(QCursor(Qt.WaitCursor))
-        QApplication.processEvents()
-        
-        locker = QMutexLocker(self.vcs.vcsExecutionMutex)
-        try:
-            entries = self.client.get_changelist(
-                path, depth=pysvn.depth.infinity)
-            for entry in entries:
-                file = entry[0]
-                changelist = entry[1]
-                if changelist not in self.changeListsDict:
-                    self.changeListsDict[changelist] = []
-                filename = file.replace(path + os.sep, "")
-                if filename not in self.changeListsDict[changelist]:
-                    self.changeListsDict[changelist].append(filename)
-        except pysvn.ClientError as e:
-            locker.unlock()
-            self.__showError(e.args[0])
+        with E5OverrideCursor():
+            locker = QMutexLocker(self.vcs.vcsExecutionMutex)
+            try:
+                entries = self.client.get_changelist(
+                    path, depth=pysvn.depth.infinity)
+                for entry in entries:
+                    file = entry[0]
+                    changelist = entry[1]
+                    if changelist not in self.changeListsDict:
+                        self.changeListsDict[changelist] = []
+                    filename = file.replace(path + os.sep, "")
+                    if filename not in self.changeListsDict[changelist]:
+                        self.changeListsDict[changelist].append(filename)
+            except pysvn.ClientError as e:
+                locker.unlock()
+                self.__showError(e.args[0])
         self.__finish()
     
     def __finish(self):
@@ -103,7 +99,6 @@
         Private slot called when the user pressed the button.
         """
         self.changeLists.addItems(sorted(self.changeListsDict.keys()))
-        QApplication.restoreOverrideCursor()
         
         self.buttonBox.button(QDialogButtonBox.Close).setEnabled(True)
         self.buttonBox.button(QDialogButtonBox.Cancel).setEnabled(False)
--- a/eric6/Plugins/VcsPlugins/vcsPySvn/SvnDialogMixin.py	Fri Oct 09 17:19:29 2020 +0200
+++ b/eric6/Plugins/VcsPlugins/vcsPySvn/SvnDialogMixin.py	Sat Oct 10 12:20:51 2020 +0200
@@ -8,9 +8,9 @@
 the pysvn client.
 """
 
+from PyQt5.QtWidgets import QApplication, QDialog, QWidget
 
-from PyQt5.QtCore import Qt
-from PyQt5.QtWidgets import QApplication, QDialog, QWidget
+from E5Gui.E5OverrideCursor import E5OverridenCursor
 
 
 class SvnDialogMixin(object):
@@ -63,14 +63,12 @@
             password should be saved.
         """
         from .SvnLoginDialog import SvnLoginDialog
-        cursor = QApplication.overrideCursor()
-        if cursor is not None:
-            QApplication.restoreOverrideCursor()
-        parent = isinstance(self, QWidget) and self or None
-        dlg = SvnLoginDialog(realm, username, may_save, parent)
-        res = dlg.exec()
-        if cursor is not None:
-            QApplication.setOverrideCursor(Qt.WaitCursor)
+        
+        with E5OverridenCursor():
+            parent = isinstance(self, QWidget) and self or None
+            dlg = SvnLoginDialog(realm, username, may_save, parent)
+            res = dlg.exec()
+        
         if res == QDialog.Accepted:
             loginData = dlg.getData()
             return (True, loginData[0], loginData[1], loginData[2])
@@ -90,37 +88,34 @@
         """
         from E5Gui import E5MessageBox
 
-        cursor = QApplication.overrideCursor()
-        if cursor is not None:
-            QApplication.restoreOverrideCursor()
-        parent = isinstance(self, QWidget) and self or None
-        msgBox = E5MessageBox.E5MessageBox(
-            E5MessageBox.Question,
-            self.tr("Subversion SSL Server Certificate"),
-            self.tr("""<p>Accept the following SSL certificate?</p>"""
-                    """<table>"""
-                    """<tr><td>Realm:</td><td>{0}</td></tr>"""
-                    """<tr><td>Hostname:</td><td>{1}</td></tr>"""
-                    """<tr><td>Fingerprint:</td><td>{2}</td></tr>"""
-                    """<tr><td>Valid from:</td><td>{3}</td></tr>"""
-                    """<tr><td>Valid until:</td><td>{4}</td></tr>"""
-                    """<tr><td>Issuer name:</td><td>{5}</td></tr>"""
-                    """</table>""")
-                .format(trust_dict["realm"],
-                        trust_dict["hostname"],
-                        trust_dict["finger_print"],
-                        trust_dict["valid_from"],
-                        trust_dict["valid_until"],
-                        trust_dict["issuer_dname"]),
-            modal=True, parent=parent)
-        permButton = msgBox.addButton(self.tr("&Permanent accept"),
-                                      E5MessageBox.AcceptRole)
-        tempButton = msgBox.addButton(self.tr("&Temporary accept"),
-                                      E5MessageBox.AcceptRole)
-        msgBox.addButton(self.tr("&Reject"), E5MessageBox.RejectRole)
-        msgBox.exec()
-        if cursor is not None:
-            QApplication.setOverrideCursor(Qt.WaitCursor)
+        with E5OverridenCursor():
+            parent = isinstance(self, QWidget) and self or None
+            msgBox = E5MessageBox.E5MessageBox(
+                E5MessageBox.Question,
+                self.tr("Subversion SSL Server Certificate"),
+                self.tr("""<p>Accept the following SSL certificate?</p>"""
+                        """<table>"""
+                        """<tr><td>Realm:</td><td>{0}</td></tr>"""
+                        """<tr><td>Hostname:</td><td>{1}</td></tr>"""
+                        """<tr><td>Fingerprint:</td><td>{2}</td></tr>"""
+                        """<tr><td>Valid from:</td><td>{3}</td></tr>"""
+                        """<tr><td>Valid until:</td><td>{4}</td></tr>"""
+                        """<tr><td>Issuer name:</td><td>{5}</td></tr>"""
+                        """</table>""")
+                    .format(trust_dict["realm"],
+                            trust_dict["hostname"],
+                            trust_dict["finger_print"],
+                            trust_dict["valid_from"],
+                            trust_dict["valid_until"],
+                            trust_dict["issuer_dname"]),
+                modal=True, parent=parent)
+            permButton = msgBox.addButton(self.tr("&Permanent accept"),
+                                          E5MessageBox.AcceptRole)
+            tempButton = msgBox.addButton(self.tr("&Temporary accept"),
+                                          E5MessageBox.AcceptRole)
+            msgBox.addButton(self.tr("&Reject"), E5MessageBox.RejectRole)
+            msgBox.exec()
+        
         if msgBox.clickedButton() == permButton:
             return (True, trust_dict["failures"], True)
         elif msgBox.clickedButton() == tempButton:
--- a/eric6/Plugins/VcsPlugins/vcsPySvn/SvnDiffDialog.py	Fri Oct 09 17:19:29 2020 +0200
+++ b/eric6/Plugins/VcsPlugins/vcsPySvn/SvnDiffDialog.py	Sat Oct 10 12:20:51 2020 +0200
@@ -14,11 +14,12 @@
 import pysvn
 
 from PyQt5.QtCore import QMutexLocker, QFileInfo, QDateTime, Qt, pyqtSlot
-from PyQt5.QtGui import QCursor, QTextCursor
-from PyQt5.QtWidgets import QWidget, QApplication, QDialogButtonBox
+from PyQt5.QtGui import QTextCursor
+from PyQt5.QtWidgets import QWidget, QDialogButtonBox
 
 from E5Gui.E5Application import e5App
 from E5Gui import E5MessageBox, E5FileDialog
+from E5Gui.E5OverrideCursor import E5OverrideCursor
 
 from .SvnDialogMixin import SvnDialogMixin
 from .Ui_SvnDiffDialog import Ui_SvnDiffDialog
@@ -138,8 +139,6 @@
         self._reset()
         self.errorGroup.hide()
         
-        QApplication.setOverrideCursor(QCursor(Qt.WaitCursor))
-        QApplication.processEvents()
         self.filename = fn
         
         self.contents.clear()
@@ -200,67 +199,68 @@
             dname, fname = self.vcs.splitPath(fn)
             fnames = [fname]
         
-        locker = QMutexLocker(self.vcs.vcsExecutionMutex)
-        cwd = os.getcwd()
-        os.chdir(dname)
-        try:
-            dname = e5App().getObject('Project').getRelativePath(dname)
-            if dname:
-                dname += "/"
-            for name in fnames:
-                self.__showError(
-                    self.tr("Processing file '{0}'...\n").format(name))
-                if urls is not None:
-                    url1 = "{0}/{1}{2}".format(urls[0], dname, name)
-                    url2 = "{0}/{1}{2}".format(urls[1], dname, name)
-                    if summary:
-                        diff_summary = self.client.diff_summarize(
-                            url1, revision1=rev1,
-                            url_or_path2=url2, revision2=rev2,
-                            recurse=recurse)
-                        diff_list = []
-                        for diff_sum in diff_summary:
-                            path = diff_sum['path']
-                            diff_list.append("{0} {1}".format(
-                                self.__getDiffSummaryKind(
-                                    diff_sum['summarize_kind']),
-                                path))
-                        diffText = os.linesep.join(diff_list)
+        with E5OverrideCursor():
+            locker = QMutexLocker(self.vcs.vcsExecutionMutex)
+            cwd = os.getcwd()
+            os.chdir(dname)
+            try:
+                dname = e5App().getObject('Project').getRelativePath(dname)
+                if dname:
+                    dname += "/"
+                for name in fnames:
+                    self.__showError(
+                        self.tr("Processing file '{0}'...\n").format(name))
+                    if urls is not None:
+                        url1 = "{0}/{1}{2}".format(urls[0], dname, name)
+                        url2 = "{0}/{1}{2}".format(urls[1], dname, name)
+                        if summary:
+                            diff_summary = self.client.diff_summarize(
+                                url1, revision1=rev1,
+                                url_or_path2=url2, revision2=rev2,
+                                recurse=recurse)
+                            diff_list = []
+                            for diff_sum in diff_summary:
+                                path = diff_sum['path']
+                                diff_list.append("{0} {1}".format(
+                                    self.__getDiffSummaryKind(
+                                        diff_sum['summarize_kind']),
+                                    path))
+                            diffText = os.linesep.join(diff_list)
+                        else:
+                            diffText = self.client.diff(
+                                tmpdir,
+                                url1, revision1=rev1,
+                                url_or_path2=url2, revision2=rev2,
+                                recurse=recurse)
                     else:
-                        diffText = self.client.diff(
-                            tmpdir,
-                            url1, revision1=rev1,
-                            url_or_path2=url2, revision2=rev2,
-                            recurse=recurse)
-                else:
-                    if pegRev is not None:
-                        diffText = self.client.diff_peg(
-                            tmpdir, name,
-                            peg_revision=self.__getVersionArg(pegRev),
-                            revision_start=rev1, revision_end=rev2,
-                            recurse=recurse)
-                    else:
-                        diffText = self.client.diff(
-                            tmpdir, name,
-                            revision1=rev1, revision2=rev2, recurse=recurse)
-                counter = 0
-                for line in diffText.splitlines():
-                    if line.startswith("--- ") or line.startswith("+++ "):
-                        self.__processFileLine(line)
-                    
-                    self.__appendText("{0}{1}".format(line, os.linesep))
-                    counter += 1
-                    if counter == 30:
-                        # check for cancel every 30 lines
-                        counter = 0
-                        if self._clientCancelCallback():
-                            break
-                if self._clientCancelCallback():
-                    break
-        except pysvn.ClientError as e:
-            self.__showError(e.args[0])
-        locker.unlock()
-        os.chdir(cwd)
+                        if pegRev is not None:
+                            diffText = self.client.diff_peg(
+                                tmpdir, name,
+                                peg_revision=self.__getVersionArg(pegRev),
+                                revision_start=rev1, revision_end=rev2,
+                                recurse=recurse)
+                        else:
+                            diffText = self.client.diff(
+                                tmpdir, name,
+                                revision1=rev1, revision2=rev2, recurse=recurse)
+                    counter = 0
+                    for line in diffText.splitlines():
+                        if line.startswith("--- ") or line.startswith("+++ "):
+                            self.__processFileLine(line)
+                        
+                        self.__appendText("{0}{1}".format(line, os.linesep))
+                        counter += 1
+                        if counter == 30:
+                            # check for cancel every 30 lines
+                            counter = 0
+                            if self._clientCancelCallback():
+                                break
+                    if self._clientCancelCallback():
+                        break
+            except pysvn.ClientError as e:
+                self.__showError(e.args[0])
+            locker.unlock()
+            os.chdir(cwd)
         self.__finish()
         
         if self.paras == 0:
@@ -309,8 +309,6 @@
         """
         Private slot called when the user pressed the button.
         """
-        QApplication.restoreOverrideCursor()
-        
         self.refreshButton.setEnabled(True)
         self.buttonBox.button(QDialogButtonBox.Cancel).setEnabled(False)
         self.buttonBox.button(QDialogButtonBox.Close).setEnabled(True)
--- a/eric6/Plugins/VcsPlugins/vcsPySvn/SvnLogBrowserDialog.py	Fri Oct 09 17:19:29 2020 +0200
+++ b/eric6/Plugins/VcsPlugins/vcsPySvn/SvnLogBrowserDialog.py	Sat Oct 10 12:20:51 2020 +0200
@@ -13,12 +13,12 @@
 import pysvn
 
 from PyQt5.QtCore import QMutexLocker, QDate, QRegExp, Qt, pyqtSlot, QPoint
-from PyQt5.QtGui import QCursor
 from PyQt5.QtWidgets import (
     QHeaderView, QWidget, QApplication, QDialogButtonBox, QTreeWidgetItem
 )
 
 from E5Gui import E5MessageBox
+from E5Gui.E5OverrideCursor import E5OverrideCursor
 
 from .SvnUtilities import formatTime, dateFromTime_t
 from .SvnDialogMixin import SvnDialogMixin
@@ -264,9 +264,6 @@
         fetchLimit = 10
         self._reset()
         
-        QApplication.setOverrideCursor(QCursor(Qt.WaitCursor))
-        QApplication.processEvents()
-        
         limit = self.limitSpinBox.value()
         if startRev is None:
             start = pysvn.Revision(pysvn.opt_revision_kind.head)
@@ -277,70 +274,71 @@
             except TypeError:
                 start = pysvn.Revision(pysvn.opt_revision_kind.head)
         
-        locker = QMutexLocker(self.vcs.vcsExecutionMutex)
-        cwd = os.getcwd()
-        os.chdir(self.dname)
-        try:
-            nextRev = 0
-            fetched = 0
-            logs = []
-            while fetched < limit:
-                flimit = min(fetchLimit, limit - fetched)
-                if fetched == 0:
-                    revstart = start
-                else:
-                    revstart = pysvn.Revision(
-                        pysvn.opt_revision_kind.number, nextRev)
-                allLogs = self.client.log(
-                    self.fname, revision_start=revstart,
-                    discover_changed_paths=True, limit=flimit + 1,
-                    strict_node_history=self.stopCheckBox.isChecked())
-                if len(allLogs) <= flimit or self._clientCancelCallback():
-                    logs.extend(allLogs)
-                    break
-                else:
-                    logs.extend(allLogs[:-1])
-                    nextRev = allLogs[-1]["revision"].number
-                    fetched += fetchLimit
-            locker.unlock()
-            
-            for log in logs:
-                author = log["author"]
-                message = log["message"]
-                self.__generateLogItem(
-                    author, log["date"], message,
-                    log["revision"], log['changed_paths'])
-                dt = dateFromTime_t(log["date"])
-                if (
-                    not self.__maxDate.isValid() and
-                    not self.__minDate.isValid()
-                ):
-                    self.__maxDate = dt
-                    self.__minDate = dt
-                else:
-                    if self.__maxDate < dt:
+        with E5OverrideCursor():
+            locker = QMutexLocker(self.vcs.vcsExecutionMutex)
+            cwd = os.getcwd()
+            os.chdir(self.dname)
+            try:
+                nextRev = 0
+                fetched = 0
+                logs = []
+                while fetched < limit:
+                    flimit = min(fetchLimit, limit - fetched)
+                    if fetched == 0:
+                        revstart = start
+                    else:
+                        revstart = pysvn.Revision(
+                            pysvn.opt_revision_kind.number, nextRev)
+                    allLogs = self.client.log(
+                        self.fname, revision_start=revstart,
+                        discover_changed_paths=True, limit=flimit + 1,
+                        strict_node_history=self.stopCheckBox.isChecked())
+                    if len(allLogs) <= flimit or self._clientCancelCallback():
+                        logs.extend(allLogs)
+                        break
+                    else:
+                        logs.extend(allLogs[:-1])
+                        nextRev = allLogs[-1]["revision"].number
+                        fetched += fetchLimit
+                locker.unlock()
+                
+                for log in logs:
+                    author = log["author"]
+                    message = log["message"]
+                    self.__generateLogItem(
+                        author, log["date"], message,
+                        log["revision"], log['changed_paths'])
+                    dt = dateFromTime_t(log["date"])
+                    if (
+                        not self.__maxDate.isValid() and
+                        not self.__minDate.isValid()
+                    ):
                         self.__maxDate = dt
-                    if self.__minDate > dt:
                         self.__minDate = dt
-            if len(logs) < limit and not self.cancelled:
-                self.nextButton.setEnabled(False)
-                self.limitSpinBox.setEnabled(False)
-            self.__filterLogsEnabled = False
-            self.fromDate.setMinimumDate(self.__minDate)
-            self.fromDate.setMaximumDate(self.__maxDate)
-            self.fromDate.setDate(self.__minDate)
-            self.toDate.setMinimumDate(self.__minDate)
-            self.toDate.setMaximumDate(self.__maxDate)
-            self.toDate.setDate(self.__maxDate)
-            self.__filterLogsEnabled = True
-            
-            self.__resizeColumnsLog()
-            self.__resortLog()
-            self.__filterLogs()
-        except pysvn.ClientError as e:
-            locker.unlock()
-            self.__showError(e.args[0])
-        os.chdir(cwd)
+                    else:
+                        if self.__maxDate < dt:
+                            self.__maxDate = dt
+                        if self.__minDate > dt:
+                            self.__minDate = dt
+                if len(logs) < limit and not self.cancelled:
+                    self.nextButton.setEnabled(False)
+                    self.limitSpinBox.setEnabled(False)
+                self.__filterLogsEnabled = False
+                self.fromDate.setMinimumDate(self.__minDate)
+                self.fromDate.setMaximumDate(self.__maxDate)
+                self.fromDate.setDate(self.__minDate)
+                self.toDate.setMinimumDate(self.__minDate)
+                self.toDate.setMaximumDate(self.__maxDate)
+                self.toDate.setDate(self.__maxDate)
+                self.__filterLogsEnabled = True
+                
+                self.__resizeColumnsLog()
+                self.__resortLog()
+                self.__filterLogs()
+            except pysvn.ClientError as e:
+                locker.unlock()
+                self.__showError(e.args[0])
+            os.chdir(cwd)
         self.__finish()
     
     def start(self, fn, isFile=False):
@@ -370,8 +368,6 @@
         """
         Private slot called when the user pressed the button.
         """
-        QApplication.restoreOverrideCursor()
-        
         self.buttonBox.button(QDialogButtonBox.Close).setEnabled(True)
         self.buttonBox.button(QDialogButtonBox.Cancel).setEnabled(False)
         self.buttonBox.button(QDialogButtonBox.Close).setDefault(True)
--- a/eric6/Plugins/VcsPlugins/vcsPySvn/SvnRepoBrowserDialog.py	Fri Oct 09 17:19:29 2020 +0200
+++ b/eric6/Plugins/VcsPlugins/vcsPySvn/SvnRepoBrowserDialog.py	Sat Oct 10 12:20:51 2020 +0200
@@ -11,12 +11,12 @@
 import pysvn
 
 from PyQt5.QtCore import QMutexLocker, Qt, pyqtSlot
-from PyQt5.QtGui import QCursor
 from PyQt5.QtWidgets import (
     QHeaderView, QDialog, QApplication, QDialogButtonBox, QTreeWidgetItem
 )
 
 from E5Gui import E5MessageBox
+from E5Gui.E5OverrideCursor import E5OverrideCursor
 
 from .SvnUtilities import formatTime
 from .SvnDialogMixin import SvnDialogMixin
@@ -150,65 +150,62 @@
         @param parent reference to the item, the data should be appended to
             (QTreeWidget or QTreeWidgetItem)
         """
-        QApplication.setOverrideCursor(QCursor(Qt.WaitCursor))
-        QApplication.processEvents()
-        
         if parent is None:
             parent = self.repoTree
         
-        locker = QMutexLocker(self.vcs.vcsExecutionMutex)
-        
-        try:
+        with E5OverrideCursor():
+            locker = QMutexLocker(self.vcs.vcsExecutionMutex)
             try:
-                entries = self.client.list(url, recurse=False)
-                firstTime = parent == self.repoTree
-                for dirent, _lock in entries:
-                    if (
-                        (firstTime and dirent["path"] != url) or
-                        (parent != self.repoTree and dirent["path"] == url)
-                    ):
-                        continue
-                    if firstTime:
-                        if dirent["repos_path"] != "/":
-                            repoUrl = dirent["path"].replace(
-                                dirent["repos_path"], "")
-                        else:
-                            repoUrl = dirent["path"]
-                        if repoUrl != url:
-                            self.__ignoreExpand = True
-                            itm = self.__generateItem(
-                                parent, "/", "", "", 0, "",
-                                pysvn.node_kind.dir, repoUrl)
-                            itm.setExpanded(True)
-                            parent = itm
-                            urlPart = repoUrl
-                            for element in (
-                                dirent["repos_path"].split("/")[:-1]
-                            ):
-                                if element:
-                                    urlPart = "{0}/{1}".format(urlPart,
-                                                               element)
-                                    itm = self.__generateItem(
-                                        parent, element, "", "", 0, "",
-                                        pysvn.node_kind.dir, urlPart)
-                                    itm.setExpanded(True)
-                                    parent = itm
-                            self.__ignoreExpand = False
-                    itm = self.__generateItem(
-                        parent, dirent["repos_path"], dirent["created_rev"],
-                        dirent["last_author"], dirent["size"], dirent["time"],
-                        dirent["kind"], dirent["path"])
-                self.__resort()
-                self.__resizeColumns()
-            except pysvn.ClientError as e:
-                self.__showError(e.args[0])
-            except AttributeError:
-                self.__showError(
-                    self.tr("The installed version of PySvn should be "
-                            "1.4.0 or better."))
-        finally:
-            locker.unlock()
-            QApplication.restoreOverrideCursor()
+                try:
+                    entries = self.client.list(url, recurse=False)
+                    firstTime = parent == self.repoTree
+                    for dirent, _lock in entries:
+                        if (
+                            (firstTime and dirent["path"] != url) or
+                            (parent != self.repoTree and dirent["path"] == url)
+                        ):
+                            continue
+                        if firstTime:
+                            if dirent["repos_path"] != "/":
+                                repoUrl = dirent["path"].replace(
+                                    dirent["repos_path"], "")
+                            else:
+                                repoUrl = dirent["path"]
+                            if repoUrl != url:
+                                self.__ignoreExpand = True
+                                itm = self.__generateItem(
+                                    parent, "/", "", "", 0, "",
+                                    pysvn.node_kind.dir, repoUrl)
+                                itm.setExpanded(True)
+                                parent = itm
+                                urlPart = repoUrl
+                                for element in (
+                                    dirent["repos_path"].split("/")[:-1]
+                                ):
+                                    if element:
+                                        urlPart = "{0}/{1}".format(urlPart,
+                                                                   element)
+                                        itm = self.__generateItem(
+                                            parent, element, "", "", 0, "",
+                                            pysvn.node_kind.dir, urlPart)
+                                        itm.setExpanded(True)
+                                        parent = itm
+                                self.__ignoreExpand = False
+                        itm = self.__generateItem(
+                            parent, dirent["repos_path"],
+                            dirent["created_rev"], dirent["last_author"],
+                            dirent["size"], dirent["time"], dirent["kind"],
+                            dirent["path"])
+                    self.__resort()
+                    self.__resizeColumns()
+                except pysvn.ClientError as e:
+                    self.__showError(e.args[0])
+                except AttributeError:
+                    self.__showError(
+                        self.tr("The installed version of PySvn should be "
+                                "1.4.0 or better."))
+            finally:
+                locker.unlock()
     
     def __normalizeUrl(self, url):
         """
--- a/eric6/Plugins/VcsPlugins/vcsPySvn/SvnStatusDialog.py	Fri Oct 09 17:19:29 2020 +0200
+++ b/eric6/Plugins/VcsPlugins/vcsPySvn/SvnStatusDialog.py	Sat Oct 10 12:20:51 2020 +0200
@@ -14,7 +14,6 @@
 import pysvn
 
 from PyQt5.QtCore import QMutexLocker, Qt, pyqtSlot
-from PyQt5.QtGui import QCursor
 from PyQt5.QtWidgets import (
     QWidget, QHeaderView, QApplication, QMenu, QDialogButtonBox,
     QTreeWidgetItem
@@ -22,6 +21,7 @@
 
 from E5Gui.E5Application import e5App
 from E5Gui import E5MessageBox
+from E5Gui.E5OverrideCursor import E5OverrideCursor
 
 from .SvnConst import svnStatusMap
 from .SvnDialogMixin import SvnDialogMixin
@@ -285,9 +285,6 @@
         self.buttonBox.button(QDialogButtonBox.Cancel).setDefault(True)
         self.refreshButton.setEnabled(False)
         
-        QApplication.setOverrideCursor(QCursor(Qt.WaitCursor))
-        QApplication.processEvents()
-        
         self.args = fn
         
         self.setWindowTitle(self.tr('Subversion Status'))
@@ -312,136 +309,142 @@
         hideHistoryColumn = True
         hideSwitchedColumn = True
         
-        locker = QMutexLocker(self.vcs.vcsExecutionMutex)
-        cwd = os.getcwd()
-        os.chdir(self.dname)
-        try:
-            for name in fnames:
-                # step 1: determine changelists and their files
-                changelistsDict = {}
-                if hasattr(self.client, 'get_changelist'):
-                    if recurse:
-                        depth = pysvn.depth.infinity
-                    else:
-                        depth = pysvn.depth.immediate
-                    changelists = self.client.get_changelist(name, depth=depth)
-                    for fpath, changelist in changelists:
-                        fpath = Utilities.normcasepath(fpath)
-                        changelistsDict[fpath] = changelist
-                hideChangelistColumn = (
-                    hideChangelistColumn and len(changelistsDict) == 0
-                )
-                
-                # step 2: determine status of files
-                allFiles = self.client.status(name, recurse=recurse,
-                                              get_all=verbose, ignore=True,
-                                              update=update)
-                counter = 0
-                for file in allFiles:
-                    uptodate = True
-                    if file.repos_text_status != pysvn.wc_status_kind.none:
-                        uptodate = (
-                            uptodate and
-                            file.repos_text_status !=
-                            pysvn.wc_status_kind.modified
-                        )
-                    if file.repos_prop_status != pysvn.wc_status_kind.none:
-                        uptodate = (
-                            uptodate and
-                            file.repos_prop_status !=
-                            pysvn.wc_status_kind.modified
-                        )
-                    
-                    lockState = " "
-                    if (
-                        file.entry is not None and
-                        hasattr(file.entry, 'lock_token') and
-                        file.entry.lock_token is not None
-                    ):
-                        lockState = "L"
-                    if hasattr(file, 'repos_lock') and update:
-                        if lockState == "L" and file.repos_lock is None:
-                            lockState = "B"
-                        elif lockState == " " and file.repos_lock is not None:
-                            lockState = "O"
-                        elif (
-                            lockState == "L" and
-                            file.repos_lock is not None and
-                            file.entry.lock_token !=
-                                file.repos_lock["token"]
-                        ):
-                            lockState = "S"
-                    
-                    fpath = Utilities.normcasepath(
-                        os.path.join(self.dname, file.path))
-                    if fpath in changelistsDict:
-                        changelist = changelistsDict[fpath]
-                    else:
-                        changelist = ""
-                    
-                    hidePropertyStatusColumn = (
-                        hidePropertyStatusColumn and
-                        file.prop_status in [
-                            pysvn.wc_status_kind.none,
-                            pysvn.wc_status_kind.normal
-                        ]
-                    )
-                    hideLockColumns = (
-                        hideLockColumns and
-                        not file.is_locked and
-                        lockState == " "
-                    )
-                    hideUpToDateColumn = hideUpToDateColumn and uptodate
-                    hideHistoryColumn = (
-                        hideHistoryColumn and
-                        not file.is_copied
-                    )
-                    hideSwitchedColumn = (
-                        hideSwitchedColumn and
-                        not file.is_switched
+        with E5OverrideCursor():
+            locker = QMutexLocker(self.vcs.vcsExecutionMutex)
+            cwd = os.getcwd()
+            os.chdir(self.dname)
+            try:
+                for name in fnames:
+                    # step 1: determine changelists and their files
+                    changelistsDict = {}
+                    if hasattr(self.client, 'get_changelist'):
+                        if recurse:
+                            depth = pysvn.depth.infinity
+                        else:
+                            depth = pysvn.depth.immediate
+                        changelists = self.client.get_changelist(
+                            name, depth=depth)
+                        for fpath, changelist in changelists:
+                            fpath = Utilities.normcasepath(fpath)
+                            changelistsDict[fpath] = changelist
+                    hideChangelistColumn = (
+                        hideChangelistColumn and len(changelistsDict) == 0
                     )
                     
-                    self.__generateItem(
-                        changelist,
-                        file.text_status,
-                        file.prop_status,
-                        file.is_locked,
-                        file.is_copied,
-                        file.is_switched,
-                        lockState,
-                        uptodate,
-                        file.entry and file.entry.revision.number or "",
-                        file.entry and file.entry.commit_revision.number or "",
-                        file.entry and file.entry.commit_author or "",
-                        file.path
-                    )
-                    counter += 1
-                    if counter == 30:
-                        # check for cancel every 30 items
-                        counter = 0
-                        if self._clientCancelCallback():
-                            break
-                if self._clientCancelCallback():
-                    break
-        except pysvn.ClientError as e:
-            self.__showError(e.args[0] + '\n')
-        
-        self.statusList.setColumnHidden(self.__propStatusColumn,
-                                        hidePropertyStatusColumn)
-        self.statusList.setColumnHidden(self.__lockedColumn,
-                                        hideLockColumns)
-        self.statusList.setColumnHidden(self.__lockinfoColumn,
-                                        hideLockColumns)
-        self.statusList.setColumnHidden(self.__upToDateColumn,
-                                        hideUpToDateColumn)
-        self.statusList.setColumnHidden(self.__historyColumn,
-                                        hideHistoryColumn)
-        self.statusList.setColumnHidden(self.__switchedColumn,
-                                        hideSwitchedColumn)
-        self.statusList.setColumnHidden(self.__changelistColumn,
-                                        hideChangelistColumn)
-        
-        locker.unlock()
+                    # step 2: determine status of files
+                    allFiles = self.client.status(name, recurse=recurse,
+                                                  get_all=verbose, ignore=True,
+                                                  update=update)
+                    counter = 0
+                    for file in allFiles:
+                        uptodate = True
+                        if file.repos_text_status != pysvn.wc_status_kind.none:
+                            uptodate = (
+                                uptodate and
+                                file.repos_text_status !=
+                                pysvn.wc_status_kind.modified
+                            )
+                        if file.repos_prop_status != pysvn.wc_status_kind.none:
+                            uptodate = (
+                                uptodate and
+                                file.repos_prop_status !=
+                                pysvn.wc_status_kind.modified
+                            )
+                        
+                        lockState = " "
+                        if (
+                            file.entry is not None and
+                            hasattr(file.entry, 'lock_token') and
+                            file.entry.lock_token is not None
+                        ):
+                            lockState = "L"
+                        if hasattr(file, 'repos_lock') and update:
+                            if lockState == "L" and file.repos_lock is None:
+                                lockState = "B"
+                            elif (
+                                lockState == " " and
+                                file.repos_lock is not None
+                            ):
+                                lockState = "O"
+                            elif (
+                                lockState == "L" and
+                                file.repos_lock is not None and
+                                file.entry.lock_token !=
+                                    file.repos_lock["token"]
+                            ):
+                                lockState = "S"
+                        
+                        fpath = Utilities.normcasepath(
+                            os.path.join(self.dname, file.path))
+                        if fpath in changelistsDict:
+                            changelist = changelistsDict[fpath]
+                        else:
+                            changelist = ""
+                        
+                        hidePropertyStatusColumn = (
+                            hidePropertyStatusColumn and
+                            file.prop_status in [
+                                pysvn.wc_status_kind.none,
+                                pysvn.wc_status_kind.normal
+                            ]
+                        )
+                        hideLockColumns = (
+                            hideLockColumns and
+                            not file.is_locked and
+                            lockState == " "
+                        )
+                        hideUpToDateColumn = hideUpToDateColumn and uptodate
+                        hideHistoryColumn = (
+                            hideHistoryColumn and
+                            not file.is_copied
+                        )
+                        hideSwitchedColumn = (
+                            hideSwitchedColumn and
+                            not file.is_switched
+                        )
+                        
+                        self.__generateItem(
+                            changelist,
+                            file.text_status,
+                            file.prop_status,
+                            file.is_locked,
+                            file.is_copied,
+                            file.is_switched,
+                            lockState,
+                            uptodate,
+                            file.entry.revision.number if file.entry else "",
+                            file.entry.commit_revision.number
+                            if file.entry else "",
+                            file.entry.commit_author if file.entry else "",
+                            file.path
+                        )
+                        counter += 1
+                        if counter == 30:
+                            # check for cancel every 30 items
+                            counter = 0
+                            if self._clientCancelCallback():
+                                break
+                    if self._clientCancelCallback():
+                        break
+            except pysvn.ClientError as e:
+                self.__showError(e.args[0] + '\n')
+            
+            self.statusList.setColumnHidden(self.__propStatusColumn,
+                                            hidePropertyStatusColumn)
+            self.statusList.setColumnHidden(self.__lockedColumn,
+                                            hideLockColumns)
+            self.statusList.setColumnHidden(self.__lockinfoColumn,
+                                            hideLockColumns)
+            self.statusList.setColumnHidden(self.__upToDateColumn,
+                                            hideUpToDateColumn)
+            self.statusList.setColumnHidden(self.__historyColumn,
+                                            hideHistoryColumn)
+            self.statusList.setColumnHidden(self.__switchedColumn,
+                                            hideSwitchedColumn)
+            self.statusList.setColumnHidden(self.__changelistColumn,
+                                            hideChangelistColumn)
+            
+            locker.unlock()
         self.__finish()
         os.chdir(cwd)
         
@@ -450,8 +453,6 @@
         Private slot called when the process finished or the user pressed
         the button.
         """
-        QApplication.restoreOverrideCursor()
-        
         self.buttonBox.button(QDialogButtonBox.Close).setEnabled(True)
         self.buttonBox.button(QDialogButtonBox.Cancel).setEnabled(False)
         self.buttonBox.button(QDialogButtonBox.Close).setDefault(True)
--- a/eric6/Plugins/VcsPlugins/vcsSubversion/SvnLogBrowserDialog.py	Fri Oct 09 17:19:29 2020 +0200
+++ b/eric6/Plugins/VcsPlugins/vcsSubversion/SvnLogBrowserDialog.py	Sat Oct 10 12:20:51 2020 +0200
@@ -13,13 +13,13 @@
 from PyQt5.QtCore import (
     QTimer, QDate, QProcess, QRegExp, Qt, pyqtSlot, QPoint
 )
-from PyQt5.QtGui import QCursor
 from PyQt5.QtWidgets import (
     QHeaderView, QLineEdit, QWidget, QApplication, QDialogButtonBox,
     QTreeWidgetItem
 )
 
 from E5Gui import E5MessageBox
+from E5Gui.E5OverrideCursor import E5OverrideCursorProcess
 
 from .Ui_SvnLogBrowserDialog import Ui_SvnLogBrowserDialog
 
@@ -64,10 +64,10 @@
         self.__messageRole = Qt.UserRole
         self.__changesRole = Qt.UserRole + 1
         
-        self.process = QProcess()
-        self.process.finished.connect(self.__procFinished)
-        self.process.readyReadStandardOutput.connect(self.__readStdout)
-        self.process.readyReadStandardError.connect(self.__readStderr)
+        self.__process = E5OverrideCursorProcess()
+        self.__process.finished.connect(self.__procFinished)
+        self.__process.readyReadStandardOutput.connect(self.__readStdout)
+        self.__process.readyReadStandardError.connect(self.__readStderr)
         
         self.rx_sep1 = QRegExp('\\-+\\s*')
         self.rx_sep2 = QRegExp('=+\\s*')
@@ -136,12 +136,12 @@
         @param e close event (QCloseEvent)
         """
         if (
-            self.process is not None and
-            self.process.state() != QProcess.NotRunning
+            self.__process is not None and
+            self.__process.state() != QProcess.NotRunning
         ):
-            self.process.terminate()
-            QTimer.singleShot(2000, self.process.kill)
-            self.process.waitForFinished(3000)
+            self.__process.terminate()
+            QTimer.singleShot(2000, self.__process.kill)
+            self.__process.waitForFinished(3000)
         
         self.__position = self.pos()
         
@@ -277,11 +277,8 @@
         self.buttonBox.button(QDialogButtonBox.Cancel).setDefault(True)
         QApplication.processEvents()
         
-        QApplication.setOverrideCursor(QCursor(Qt.WaitCursor))
-        QApplication.processEvents()
-        
         self.intercept = False
-        self.process.kill()
+        self.__process.kill()
         
         self.buf = []
         self.cancelled = False
@@ -301,13 +298,13 @@
             args.append('--stop-on-copy')
         args.append(self.fname)
         
-        self.process.setWorkingDirectory(self.dname)
+        self.__process.setWorkingDirectory(self.dname)
         
         self.inputGroup.setEnabled(True)
         self.inputGroup.show()
         
-        self.process.start('svn', args)
-        procStarted = self.process.waitForStarted(5000)
+        self.__process.start('svn', args)
+        procStarted = self.__process.waitForStarted(5000)
         if not procStarted:
             self.inputGroup.setEnabled(False)
             self.inputGroup.hide()
@@ -361,14 +358,12 @@
         button.
         """
         if (
-            self.process is not None and
-            self.process.state() != QProcess.NotRunning
+            self.__process is not None and
+            self.__process.state() != QProcess.NotRunning
         ):
-            self.process.terminate()
-            QTimer.singleShot(2000, self.process.kill)
-            self.process.waitForFinished(3000)
-        
-        QApplication.restoreOverrideCursor()
+            self.__process.terminate()
+            QTimer.singleShot(2000, self.__process.kill)
+            self.__process.waitForFinished(3000)
         
         self.buttonBox.button(QDialogButtonBox.Close).setEnabled(True)
         self.buttonBox.button(QDialogButtonBox.Cancel).setEnabled(False)
@@ -471,10 +466,10 @@
         
         It reads the output of the process and inserts it into a buffer.
         """
-        self.process.setReadChannel(QProcess.StandardOutput)
+        self.__process.setReadChannel(QProcess.StandardOutput)
         
-        while self.process.canReadLine():
-            line = str(self.process.readLine(),
+        while self.__process.canReadLine():
+            line = str(self.__process.readLine(),
                        Preferences.getSystem("IOEncoding"),
                        'replace')
             self.buf.append(line)
@@ -486,9 +481,9 @@
         It reads the error output of the process and inserts it into the
         error pane.
         """
-        if self.process is not None:
+        if self.__process is not None:
             self.errorGroup.show()
-            s = str(self.process.readAllStandardError(),
+            s = str(self.__process.readAllStandardError(),
                     Preferences.getSystem("IOEncoding"),
                     'replace')
             self.errors.insertPlainText(s)
@@ -753,7 +748,7 @@
             self.errors.ensureCursorVisible()
         self.errorGroup.show()
         
-        self.process.write(strToQByteArray(inputTxt))
+        self.__process.write(strToQByteArray(inputTxt))
         
         self.passwordCheckBox.setChecked(False)
         self.input.clear()
--- a/eric6/Plugins/VcsPlugins/vcsSubversion/SvnRepoBrowserDialog.py	Fri Oct 09 17:19:29 2020 +0200
+++ b/eric6/Plugins/VcsPlugins/vcsSubversion/SvnRepoBrowserDialog.py	Sat Oct 10 12:20:51 2020 +0200
@@ -10,7 +10,6 @@
 
 import os
 
-from PyQt5.QtGui import QCursor
 from PyQt5.QtWidgets import (
     QHeaderView, QLineEdit, QDialog, QApplication, QDialogButtonBox,
     QTreeWidgetItem
@@ -18,6 +17,7 @@
 from PyQt5.QtCore import QTimer, QProcess, QRegExp, Qt, pyqtSlot
 
 from E5Gui import E5MessageBox
+from E5Gui.E5OverrideCursor import E5OverrideCursorProcess
 
 from .Ui_SvnRepoBrowserDialog import Ui_SvnRepoBrowserDialog
 
@@ -49,10 +49,10 @@
         self.vcs = vcs
         self.mode = mode
         
-        self.process = QProcess()
-        self.process.finished.connect(self.__procFinished)
-        self.process.readyReadStandardOutput.connect(self.__readStdout)
-        self.process.readyReadStandardError.connect(self.__readStderr)
+        self.__process = E5OverrideCursorProcess()
+        self.__process.finished.connect(self.__procFinished)
+        self.__process.readyReadStandardOutput.connect(self.__readStdout)
+        self.__process.readyReadStandardError.connect(self.__readStderr)
         
         if self.mode == "select":
             self.buttonBox.button(QDialogButtonBox.Ok).setEnabled(False)
@@ -82,12 +82,12 @@
         @param e close event (QCloseEvent)
         """
         if (
-            self.process is not None and
-            self.process.state() != QProcess.NotRunning
+            self.__process is not None and
+            self.__process.state() != QProcess.NotRunning
         ):
-            self.process.terminate()
-            QTimer.singleShot(2000, self.process.kill)
-            self.process.waitForFinished(3000)
+            self.__process.terminate()
+            QTimer.singleShot(2000, self.__process.kill)
+            self.__process.waitForFinished(3000)
         
         e.accept()
         
@@ -195,7 +195,6 @@
                     self.errors.insertPlainText(error)
                     self.errors.ensureCursorVisible()
         else:
-            QApplication.restoreOverrideCursor()
             E5MessageBox.critical(
                 self,
                 self.tr('Process Generation Error'),
@@ -215,9 +214,6 @@
         """
         self.errorGroup.hide()
         
-        QApplication.setOverrideCursor(QCursor(Qt.WaitCursor))
-        QApplication.processEvents()
-        
         self.repoUrl = url
         
         if parent is None:
@@ -250,7 +246,7 @@
         
         self.intercept = False
         
-        self.process.kill()
+        self.__process.kill()
         
         args = []
         args.append('list')
@@ -259,8 +255,8 @@
             args.append('--verbose')
         args.append(url)
         
-        self.process.start('svn', args)
-        procStarted = self.process.waitForStarted(5000)
+        self.__process.start('svn', args)
+        procStarted = self.__process.waitForStarted(5000)
         if not procStarted:
             self.__finish()
             self.inputGroup.setEnabled(False)
@@ -370,19 +366,18 @@
         button.
         """
         if (
-            self.process is not None and
-            self.process.state() != QProcess.NotRunning
+            self.__process is not None and
+            self.__process.state() != QProcess.NotRunning
         ):
-            self.process.terminate()
-            QTimer.singleShot(2000, self.process.kill)
-            self.process.waitForFinished(3000)
+            self.__process.terminate()
+            QTimer.singleShot(2000, self.__process.kill)
+            self.__process.waitForFinished(3000)
         
         self.inputGroup.setEnabled(False)
         self.inputGroup.hide()
         
         self.__resizeColumns()
         self.__resort()
-        QApplication.restoreOverrideCursor()
     
     def __procFinished(self, exitCode, exitStatus):
         """
@@ -400,11 +395,11 @@
         It reads the output of the process, formats it and inserts it into
         the contents pane.
         """
-        if self.process is not None:
-            self.process.setReadChannel(QProcess.StandardOutput)
+        if self.__process is not None:
+            self.__process.setReadChannel(QProcess.StandardOutput)
             
-            while self.process.canReadLine():
-                s = str(self.process.readLine(),
+            while self.__process.canReadLine():
+                s = str(self.__process.readLine(),
                         Preferences.getSystem("IOEncoding"),
                         'replace')
                 if self.__rx_dir.exactMatch(s):
@@ -438,8 +433,8 @@
         It reads the error output of the process and inserts it into the
         error pane.
         """
-        if self.process is not None:
-            s = str(self.process.readAllStandardError(),
+        if self.__process is not None:
+            s = str(self.__process.readAllStandardError(),
                     Preferences.getSystem("IOEncoding"),
                     'replace')
             self.errors.insertPlainText(s)
@@ -472,7 +467,7 @@
             self.errors.insertPlainText(inputTxt)
             self.errors.ensureCursorVisible()
         
-        self.process.write(strToQByteArray(inputTxt))
+        self.__process.write(strToQByteArray(inputTxt))
         
         self.passwordCheckBox.setChecked(False)
         self.input.clear()
--- a/eric6/Plugins/WizardPlugins/SetupWizard/SetupWizardDialog.py	Fri Oct 09 17:19:29 2020 +0200
+++ b/eric6/Plugins/WizardPlugins/SetupWizard/SetupWizardDialog.py	Sat Oct 10 12:20:51 2020 +0200
@@ -13,13 +13,14 @@
 
 from PyQt5.QtCore import pyqtSlot, Qt, QUrl
 from PyQt5.QtWidgets import (
-    QDialog, QDialogButtonBox, QTreeWidgetItem, QListWidgetItem, QApplication
+    QDialog, QDialogButtonBox, QTreeWidgetItem, QListWidgetItem
 )
 from PyQt5.QtNetwork import QNetworkRequest, QNetworkReply
 
 from E5Gui.E5Application import e5App
 from E5Gui import E5MessageBox, E5FileDialog
 from E5Gui.E5Completers import E5DirCompleter
+from E5Gui.E5OverrideCursor import E5OverrideCursor
 
 from .Ui_SetupWizardDialog import Ui_SetupWizardDialog
 
@@ -555,16 +556,15 @@
         """
         Private slot to discover packages automatically.
         """
-        self.autodiscoverPackagesButton.setEnabled(False)
-        QApplication.setOverrideCursor(Qt.WaitCursor)
-        startDir = self.packageRootEdit.text() or self.__getStartDir()
-        if startDir:
-            self.packagesList.clear()
-            for dirpath, _dirnames, filenames in os.walk(startDir):
-                if "__init__.py" in filenames:
-                    self.__addPackage(dirpath)
-        self.autodiscoverPackagesButton.setEnabled(True)
-        QApplication.restoreOverrideCursor()
+        with E5OverrideCursor():
+            self.autodiscoverPackagesButton.setEnabled(False)
+            startDir = self.packageRootEdit.text() or self.__getStartDir()
+            if startDir:
+                self.packagesList.clear()
+                for dirpath, _dirnames, filenames in os.walk(startDir):
+                    if "__init__.py" in filenames:
+                        self.__addPackage(dirpath)
+            self.autodiscoverPackagesButton.setEnabled(True)
     
     @pyqtSlot()
     def on_packageRootDirButton_clicked(self):
--- a/eric6/Preferences/ConfigurationPages/EmailPage.py	Fri Oct 09 17:19:29 2020 +0200
+++ b/eric6/Preferences/ConfigurationPages/EmailPage.py	Sat Oct 10 12:20:51 2020 +0200
@@ -12,12 +12,11 @@
 import socket
 import sys
 
-from PyQt5.QtCore import pyqtSlot, Qt
-from PyQt5.QtGui import QCursor
-from PyQt5.QtWidgets import QApplication
+from PyQt5.QtCore import pyqtSlot
 
 from E5Gui import E5MessageBox
 from E5Gui.E5Application import e5App
+from E5Gui.E5OverrideCursor import E5OverrideCursor
 
 from E5Network.E5GoogleMailHelpers import getInstallCommand, RequiredPackages
 
@@ -200,49 +199,26 @@
         """
         Private slot to test the mail server login data.
         """
-        QApplication.setOverrideCursor(QCursor(Qt.WaitCursor))
-        QApplication.processEvents()
         try:
-            if self.useSslButton.isChecked():
-                server = smtplib.SMTP_SSL(self.mailServerEdit.text(),
+            with E5OverrideCursor():
+                if self.useSslButton.isChecked():
+                    server = smtplib.SMTP_SSL(self.mailServerEdit.text(),
+                                              self.portSpin.value(),
+                                              timeout=10)
+                else:
+                    server = smtplib.SMTP(self.mailServerEdit.text(),
                                           self.portSpin.value(),
                                           timeout=10)
-            else:
-                server = smtplib.SMTP(self.mailServerEdit.text(),
-                                      self.portSpin.value(),
-                                      timeout=10)
-                if self.useTlsButton.isChecked():
-                    server.starttls()
-            try:
+                    if self.useTlsButton.isChecked():
+                        server.starttls()
                 server.login(self.mailUserEdit.text(),
                              self.mailPasswordEdit.text())
-                QApplication.restoreOverrideCursor()
-                E5MessageBox.information(
-                    self,
-                    self.tr("Login Test"),
-                    self.tr("""The login test succeeded."""))
-            except (smtplib.SMTPException, socket.error) as e:
-                QApplication.restoreOverrideCursor()
-                if isinstance(e, smtplib.SMTPResponseException):
-                    errorStr = e.smtp_error.decode()
-                elif isinstance(e, socket.timeout):
-                    errorStr = str(e)
-                elif isinstance(e, socket.error):
-                    try:
-                        errorStr = e[1]
-                    except TypeError:
-                        errorStr = str(e)
-                else:
-                    errorStr = str(e)
-                E5MessageBox.critical(
-                    self,
-                    self.tr("Login Test"),
-                    self.tr(
-                        """<p>The login test failed.<br>Reason: {0}</p>""")
-                    .format(errorStr))
-            server.quit()
+                server.quit()
+            E5MessageBox.information(
+                self,
+                self.tr("Login Test"),
+                self.tr("""The login test succeeded."""))
         except (smtplib.SMTPException, socket.error) as e:
-            QApplication.restoreOverrideCursor()
             if isinstance(e, smtplib.SMTPResponseException):
                 errorStr = e.smtp_error.decode()
             elif isinstance(e, socket.timeout):
@@ -257,7 +233,8 @@
             E5MessageBox.critical(
                 self,
                 self.tr("Login Test"),
-                self.tr("""<p>The login test failed.<br>Reason: {0}</p>""")
+                self.tr(
+                    """<p>The login test failed.<br>Reason: {0}</p>""")
                 .format(errorStr))
     
     @pyqtSlot()
--- a/eric6/Preferences/ProgramsDialog.py	Fri Oct 09 17:19:29 2020 +0200
+++ b/eric6/Preferences/ProgramsDialog.py	Sat Oct 10 12:20:51 2020 +0200
@@ -13,12 +13,12 @@
 import sys
 
 from PyQt5.QtCore import pyqtSlot, Qt, QProcess
-from PyQt5.QtGui import QCursor
 from PyQt5.QtWidgets import (
     QApplication, QTreeWidgetItem, QHeaderView, QDialog, QDialogButtonBox
 )
 
 from E5Gui.E5Application import e5App
+from E5Gui.E5OverrideCursor import E5OverrideCursor
 
 from .Ui_ProgramsDialog import Ui_ProgramsDialog
 
@@ -81,224 +81,224 @@
         """
         Private slot to search for all supported/required programs.
         """
-        QApplication.setOverrideCursor(QCursor(Qt.WaitCursor))
-        QApplication.processEvents()
-        
         self.programsList.clear()
         header = self.programsList.header()
         header.setSortIndicator(0, Qt.AscendingOrder)
         header.setSortIndicatorShown(False)
         
-        # 1. do the Qt5 programs
-        # 1a. Translation Converter
-        exe = (
-            Utilities.isWindowsPlatform() and
-            "{0}.exe".format(Utilities.generateQtToolName("lrelease")) or
-            Utilities.generateQtToolName("lrelease")
-        )
-        exe = os.path.join(Utilities.getQtBinariesPath(), exe)
-        version = self.__createProgramEntry(
-            self.tr("Translation Converter (Qt)"), exe, '-version',
-            'lrelease', -1)
-        # 1b. Qt Designer
-        if Utilities.isWindowsPlatform():
-            exe = os.path.join(
-                Utilities.getQtBinariesPath(),
-                "{0}.exe".format(Utilities.generateQtToolName("designer")))
-        elif Utilities.isMacPlatform():
-            exe = Utilities.getQtMacBundle("designer")
-        else:
-            exe = os.path.join(
-                Utilities.getQtBinariesPath(),
-                Utilities.generateQtToolName("designer"))
-        self.__createProgramEntry(
-            self.tr("Qt Designer"), exe, version=version)
-        # 1c. Qt Linguist
-        if Utilities.isWindowsPlatform():
-            exe = os.path.join(
-                Utilities.getQtBinariesPath(),
-                "{0}.exe".format(Utilities.generateQtToolName("linguist")))
-        elif Utilities.isMacPlatform():
-            exe = Utilities.getQtMacBundle("linguist")
-        else:
-            exe = os.path.join(
-                Utilities.getQtBinariesPath(),
-                Utilities.generateQtToolName("linguist"))
-        self.__createProgramEntry(
-            self.tr("Qt Linguist"), exe, version=version)
-        # 1d. Qt Assistant
-        if Utilities.isWindowsPlatform():
-            exe = os.path.join(
-                Utilities.getQtBinariesPath(),
-                "{0}.exe".format(Utilities.generateQtToolName("assistant")))
-        elif Utilities.isMacPlatform():
-            exe = Utilities.getQtMacBundle("assistant")
-        else:
-            exe = os.path.join(
-                Utilities.getQtBinariesPath(),
-                Utilities.generateQtToolName("assistant"))
-        self.__createProgramEntry(
-            self.tr("Qt Assistant"), exe, version=version)
-        
-        # 2. do the PyQt programs
-        # 2.1 do the PyQt5 programs
-        # 2.1a. Translation Extractor PyQt5
-        self.__createProgramEntry(
-            self.tr("Translation Extractor (Python, PyQt5)"),
-            Utilities.generatePyQtToolPath("pylupdate5"),
-            '-version', 'pylupdate', -1)
-        # 2.1b. Forms Compiler PyQt5
-        self.__createProgramEntry(
-            self.tr("Forms Compiler (Python, PyQt5)"),
-            Utilities.generatePyQtToolPath("pyuic5", ["py3uic5"]),
-            '--version', 'Python User', 4)
-        # 2.1c. Resource Compiler PyQt5
-        self.__createProgramEntry(
-            self.tr("Resource Compiler (Python, PyQt5)"),
-            Utilities.generatePyQtToolPath("pyrcc5"),
-            '-version', '', -1, versionRe='Resource Compiler|pyrcc5')
-        
-        # 3. do the PySide programs
-        # 3.1 do the PySide2 programs
-        # 3.1a. Translation Extractor PySide2
-        self.__createProgramEntry(
-            self.tr("Translation Extractor (Python, PySide2)"),
-            Utilities.generatePySideToolPath("pyside2-lupdate"),
-            '-version', '', -1, versionRe='lupdate')
-        # 3.1b. Forms Compiler PySide2
-        self.__createProgramEntry(
-            self.tr("Forms Compiler (Python, PySide2)"),
-            Utilities.generatePySideToolPath("pyside2-uic"),
-            '--version', '', -1, versionRe='uic')
-        # 3.1c Resource Compiler PySide2
-        self.__createProgramEntry(
-            self.tr("Resource Compiler (Python, PySide2)"),
-            Utilities.generatePySideToolPath("pyside2-rcc"),
-            '-version', '', -1, versionRe='rcc')
-        
-        # 4. do the Conda program(s)
-        exe = Preferences.getConda("CondaExecutable")
-        if not exe:
-            exe = "conda"
+        with E5OverrideCursor():
+            # 1. do the Qt5 programs
+            # 1a. Translation Converter
+            exe = (
+                Utilities.isWindowsPlatform() and
+                "{0}.exe".format(Utilities.generateQtToolName("lrelease")) or
+                Utilities.generateQtToolName("lrelease")
+            )
+            exe = os.path.join(Utilities.getQtBinariesPath(), exe)
+            version = self.__createProgramEntry(
+                self.tr("Translation Converter (Qt)"), exe, '-version',
+                'lrelease', -1)
+            # 1b. Qt Designer
+            if Utilities.isWindowsPlatform():
+                exe = os.path.join(
+                    Utilities.getQtBinariesPath(),
+                    "{0}.exe".format(Utilities.generateQtToolName("designer")))
+            elif Utilities.isMacPlatform():
+                exe = Utilities.getQtMacBundle("designer")
+            else:
+                exe = os.path.join(
+                    Utilities.getQtBinariesPath(),
+                    Utilities.generateQtToolName("designer"))
+            self.__createProgramEntry(
+                self.tr("Qt Designer"), exe, version=version)
+            # 1c. Qt Linguist
+            if Utilities.isWindowsPlatform():
+                exe = os.path.join(
+                    Utilities.getQtBinariesPath(),
+                    "{0}.exe".format(Utilities.generateQtToolName("linguist")))
+            elif Utilities.isMacPlatform():
+                exe = Utilities.getQtMacBundle("linguist")
+            else:
+                exe = os.path.join(
+                    Utilities.getQtBinariesPath(),
+                    Utilities.generateQtToolName("linguist"))
+            self.__createProgramEntry(
+                self.tr("Qt Linguist"), exe, version=version)
+            # 1d. Qt Assistant
             if Utilities.isWindowsPlatform():
-                exe += ".exe"
-        self.__createProgramEntry(
-            self.tr("conda Manager"), exe, '--version', 'conda', -1)
-        
-        # 5. do the pip program(s)
-        virtualenvManager = e5App().getObject("VirtualEnvManager")
-        for venvName in virtualenvManager.getVirtualenvNames():
-            interpreter = virtualenvManager.getVirtualenvInterpreter(venvName)
+                exe = os.path.join(
+                    Utilities.getQtBinariesPath(),
+                    "{0}.exe".format(
+                        Utilities.generateQtToolName("assistant")))
+            elif Utilities.isMacPlatform():
+                exe = Utilities.getQtMacBundle("assistant")
+            else:
+                exe = os.path.join(
+                    Utilities.getQtBinariesPath(),
+                    Utilities.generateQtToolName("assistant"))
+            self.__createProgramEntry(
+                self.tr("Qt Assistant"), exe, version=version)
+            
+            # 2. do the PyQt programs
+            # 2.1 do the PyQt5 programs
+            # 2.1a. Translation Extractor PyQt5
+            self.__createProgramEntry(
+                self.tr("Translation Extractor (Python, PyQt5)"),
+                Utilities.generatePyQtToolPath("pylupdate5"),
+                '-version', 'pylupdate', -1)
+            # 2.1b. Forms Compiler PyQt5
+            self.__createProgramEntry(
+                self.tr("Forms Compiler (Python, PyQt5)"),
+                Utilities.generatePyQtToolPath("pyuic5", ["py3uic5"]),
+                '--version', 'Python User', 4)
+            # 2.1c. Resource Compiler PyQt5
+            self.__createProgramEntry(
+                self.tr("Resource Compiler (Python, PyQt5)"),
+                Utilities.generatePyQtToolPath("pyrcc5"),
+                '-version', '', -1, versionRe='Resource Compiler|pyrcc5')
+            
+            # 3. do the PySide programs
+            # 3.1 do the PySide2 programs
+            # 3.1a. Translation Extractor PySide2
+            self.__createProgramEntry(
+                self.tr("Translation Extractor (Python, PySide2)"),
+                Utilities.generatePySideToolPath("pyside2-lupdate"),
+                '-version', '', -1, versionRe='lupdate')
+            # 3.1b. Forms Compiler PySide2
+            self.__createProgramEntry(
+                self.tr("Forms Compiler (Python, PySide2)"),
+                Utilities.generatePySideToolPath("pyside2-uic"),
+                '--version', '', -1, versionRe='uic')
+            # 3.1c Resource Compiler PySide2
+            self.__createProgramEntry(
+                self.tr("Resource Compiler (Python, PySide2)"),
+                Utilities.generatePySideToolPath("pyside2-rcc"),
+                '-version', '', -1, versionRe='rcc')
+            
+            # 4. do the Conda program(s)
+            exe = Preferences.getConda("CondaExecutable")
+            if not exe:
+                exe = "conda"
+                if Utilities.isWindowsPlatform():
+                    exe += ".exe"
             self.__createProgramEntry(
-                self.tr("PyPI Package Management"), interpreter, '--version',
-                'pip', 1, exeModule=["-m", "pip"])
-        
-        # 6. do the CORBA and Protobuf programs
-        # 6a. omniORB
-        exe = Preferences.getCorba("omniidl")
-        if not exe:
-            exe = "omniidl"
-            if Utilities.isWindowsPlatform():
-                exe += ".exe"
-        self.__createProgramEntry(
-            self.tr("CORBA IDL Compiler"), exe, '-V', 'omniidl', -1)
-        # 6b. protobuf
-        exe = Preferences.getProtobuf("protoc")
-        if not exe:
-            exe = "protoc"
-            if Utilities.isWindowsPlatform():
-                exe += ".exe"
-        self.__createProgramEntry(
-            self.tr("Protobuf Compiler"), exe, '--version', 'libprotoc', -1)
-        # 6c. grpc
-        exe = Preferences.getProtobuf("grpcPython")
-        if not exe:
-            exe = sys.executable
-        self.__createProgramEntry(
-            self.tr("gRPC Compiler"), exe, '--version', 'libprotoc', -1,
-            exeModule=['-m', 'grpc_tools.protoc'])
-        
-        # 7. do the spell checking entry
-        try:
-            import enchant
+                self.tr("conda Manager"), exe, '--version', 'conda', -1)
+            
+            # 5. do the pip program(s)
+            virtualenvManager = e5App().getObject("VirtualEnvManager")
+            for venvName in virtualenvManager.getVirtualenvNames():
+                interpreter = virtualenvManager.getVirtualenvInterpreter(
+                    venvName)
+                self.__createProgramEntry(
+                    self.tr("PyPI Package Management"), interpreter,
+                    '--version', 'pip', 1, exeModule=["-m", "pip"])
+            
+            # 6. do the CORBA and Protobuf programs
+            # 6a. omniORB
+            exe = Preferences.getCorba("omniidl")
+            if not exe:
+                exe = "omniidl"
+                if Utilities.isWindowsPlatform():
+                    exe += ".exe"
+            self.__createProgramEntry(
+                self.tr("CORBA IDL Compiler"), exe, '-V', 'omniidl', -1)
+            # 6b. protobuf
+            exe = Preferences.getProtobuf("protoc")
+            if not exe:
+                exe = "protoc"
+                if Utilities.isWindowsPlatform():
+                    exe += ".exe"
+            self.__createProgramEntry(
+                self.tr("Protobuf Compiler"), exe, '--version', 'libprotoc',
+                -1)
+            # 6c. grpc
+            exe = Preferences.getProtobuf("grpcPython")
+            if not exe:
+                exe = sys.executable
+            self.__createProgramEntry(
+                self.tr("gRPC Compiler"), exe, '--version', 'libprotoc', -1,
+                exeModule=['-m', 'grpc_tools.protoc'])
+            
+            # 7. do the spell checking entry
             try:
-                text = os.path.dirname(enchant.__file__)
-            except AttributeError:
+                import enchant
+                try:
+                    text = os.path.dirname(enchant.__file__)
+                except AttributeError:
+                    text = "enchant"
+                try:
+                    version = enchant.__version__
+                except AttributeError:
+                    version = self.tr("(unknown)")
+            except (ImportError, AttributeError, OSError):
                 text = "enchant"
-            try:
-                version = enchant.__version__
-            except AttributeError:
-                version = self.tr("(unknown)")
-        except (ImportError, AttributeError, OSError):
-            text = "enchant"
-            version = ""
-        self.__createEntry(
-            self.tr("Spell Checker - PyEnchant"), text, version)
-        
-        # 8. do the pygments entry
-        try:
-            import pygments
-            try:
-                text = os.path.dirname(pygments.__file__)
-            except AttributeError:
-                text = "pygments"
+                version = ""
+            self.__createEntry(
+                self.tr("Spell Checker - PyEnchant"), text, version)
+            
+            # 8. do the pygments entry
             try:
-                version = pygments.__version__
-            except AttributeError:
-                version = self.tr("(unknown)")
-        except (ImportError, AttributeError, OSError):
-            text = "pygments"
-            version = ""
-        self.__createEntry(
-            self.tr("Source Highlighter - Pygments"), text, version)
-        
-        # 9. do the MicroPython related entries
-        exe = Preferences.getMicroPython("MpyCrossCompiler")
-        if not exe:
-            exe = "mpy-cross"
-        self.__createProgramEntry(
-            self.tr("MicroPython - MPY Cross Compiler"), exe, '--version',
-            'MicroPython', 1)
-        self.__createProgramEntry(
-            self.tr("MicroPython - ESP Tool"), sys.executable, 'version',
-            'esptool', -1, exeModule=['-m', 'esptool'])
-        exe = Preferences.getMicroPython("DfuUtilPath")
-        if not exe:
-            exe = "dfu-util"
-        self.__createProgramEntry(
-            self.tr("MicroPython - PyBoard Flasher"), exe, '--version',
-            'dfu-util', -1)
-        
-        # 10. do the plugin related programs
-        pm = e5App().getObject("PluginManager")
-        for info in pm.getPluginExeDisplayData():
-            if info["programEntry"]:
-                if "exeModule" not in info:
-                    info["exeModule"] = None
-                if "versionRe" not in info:
-                    info["versionRe"] = None
-                self.__createProgramEntry(
-                    info["header"],
-                    info["exe"],
-                    versionCommand=info["versionCommand"],
-                    versionStartsWith=info["versionStartsWith"],
-                    versionPosition=info["versionPosition"],
-                    version=info["version"],
-                    versionCleanup=info["versionCleanup"],
-                    versionRe=info["versionRe"],
-                    exeModule=info["exeModule"],
-                )
-            else:
-                self.__createEntry(
-                    info["header"],
-                    info["text"],
-                    info["version"]
-                )
-        
-        self.programsList.sortByColumn(0, Qt.AscendingOrder)
-        self.on_showComboBox_currentIndexChanged(
-            self.showComboBox.currentIndex())
-        QApplication.restoreOverrideCursor()
+                import pygments
+                try:
+                    text = os.path.dirname(pygments.__file__)
+                except AttributeError:
+                    text = "pygments"
+                try:
+                    version = pygments.__version__
+                except AttributeError:
+                    version = self.tr("(unknown)")
+            except (ImportError, AttributeError, OSError):
+                text = "pygments"
+                version = ""
+            self.__createEntry(
+                self.tr("Source Highlighter - Pygments"), text, version)
+            
+            # 9. do the MicroPython related entries
+            exe = Preferences.getMicroPython("MpyCrossCompiler")
+            if not exe:
+                exe = "mpy-cross"
+            self.__createProgramEntry(
+                self.tr("MicroPython - MPY Cross Compiler"), exe, '--version',
+                'MicroPython', 1)
+            self.__createProgramEntry(
+                self.tr("MicroPython - ESP Tool"), sys.executable, 'version',
+                'esptool', -1, exeModule=['-m', 'esptool'])
+            exe = Preferences.getMicroPython("DfuUtilPath")
+            if not exe:
+                exe = "dfu-util"
+            self.__createProgramEntry(
+                self.tr("MicroPython - PyBoard Flasher"), exe, '--version',
+                'dfu-util', -1)
+            
+            # 10. do the plugin related programs
+            pm = e5App().getObject("PluginManager")
+            for info in pm.getPluginExeDisplayData():
+                if info["programEntry"]:
+                    if "exeModule" not in info:
+                        info["exeModule"] = None
+                    if "versionRe" not in info:
+                        info["versionRe"] = None
+                    self.__createProgramEntry(
+                        info["header"],
+                        info["exe"],
+                        versionCommand=info["versionCommand"],
+                        versionStartsWith=info["versionStartsWith"],
+                        versionPosition=info["versionPosition"],
+                        version=info["version"],
+                        versionCleanup=info["versionCleanup"],
+                        versionRe=info["versionRe"],
+                        exeModule=info["exeModule"],
+                    )
+                else:
+                    self.__createEntry(
+                        info["header"],
+                        info["text"],
+                        info["version"]
+                    )
+            
+            self.programsList.sortByColumn(0, Qt.AscendingOrder)
+            self.on_showComboBox_currentIndexChanged(
+                self.showComboBox.currentIndex())
         
         self.__hasSearched = True
 
--- a/eric6/Project/Project.py	Fri Oct 09 17:19:29 2020 +0200
+++ b/eric6/Project/Project.py	Sat Oct 10 12:20:51 2020 +0200
@@ -18,9 +18,9 @@
 
 from PyQt5.QtCore import (
     pyqtSlot, QFile, QFileInfo, pyqtSignal, QCryptographicHash, QIODevice,
-    QByteArray, QObject, Qt, QProcess
+    QByteArray, QObject, QProcess
 )
-from PyQt5.QtGui import QCursor, QKeySequence
+from PyQt5.QtGui import QKeySequence
 from PyQt5.QtWidgets import (
     QLineEdit, QToolBar, QDialog, QInputDialog, QApplication, QMenu, QAction
 )
@@ -30,6 +30,7 @@
 from E5Gui import E5FileDialog, E5MessageBox
 from E5Gui.E5ListSelectionDialog import E5ListSelectionDialog
 from E5Gui.E5ProgressDialog import E5ProgressDialog
+from E5Gui.E5OverrideCursor import E5OverrideCursor, E5OverridenCursor
 
 from Globals import recentNameProject
 
@@ -778,7 +779,6 @@
             res = not reader.hasError()
             f.close()
         else:
-            QApplication.restoreOverrideCursor()
             E5MessageBox.critical(
                 self.ui,
                 self.tr("Read project file"),
@@ -2617,91 +2617,90 @@
         # Show the file type associations for the user to change
         self.__showFiletypeAssociations()
         
-        QApplication.setOverrideCursor(QCursor(Qt.WaitCursor))
-        QApplication.processEvents()
-        
-        # search the project directory for files with known extensions
-        filespecs = list(self.pdata["FILETYPES"].keys())
-        for filespec in filespecs:
-            files = Utilities.direntries(self.ppath, True, filespec)
-            for file in files:
-                self.appendFile(file)
-        
-        # special handling for translation files
-        if self.translationsRoot:
-            tpd = os.path.join(self.ppath, self.translationsRoot)
-            if not self.translationsRoot.endswith(os.sep):
-                tpd = os.path.dirname(tpd)
-        else:
-            tpd = self.ppath
-        tslist = []
-        if self.pdata["TRANSLATIONPATTERN"]:
-            pattern = os.path.basename(self.pdata["TRANSLATIONPATTERN"])
-            if "%language%" in pattern:
-                pattern = pattern.replace("%language%", "*")
+        with E5OverrideCursor():
+            # search the project directory for files with known extensions
+            filespecs = list(self.pdata["FILETYPES"].keys())
+            for filespec in filespecs:
+                files = Utilities.direntries(self.ppath, True, filespec)
+                for file in files:
+                    self.appendFile(file)
+            
+            # special handling for translation files
+            if self.translationsRoot:
+                tpd = os.path.join(self.ppath, self.translationsRoot)
+                if not self.translationsRoot.endswith(os.sep):
+                    tpd = os.path.dirname(tpd)
             else:
-                tpd = self.pdata["TRANSLATIONPATTERN"].split(
-                    "%language%")[0]
-        else:
-            pattern = "*.ts"
-        tslist.extend(Utilities.direntries(tpd, True, pattern))
-        pattern = self.__binaryTranslationFile(pattern)
-        if pattern:
+                tpd = self.ppath
+            tslist = []
+            if self.pdata["TRANSLATIONPATTERN"]:
+                pattern = os.path.basename(self.pdata["TRANSLATIONPATTERN"])
+                if "%language%" in pattern:
+                    pattern = pattern.replace("%language%", "*")
+                else:
+                    tpd = self.pdata["TRANSLATIONPATTERN"].split(
+                        "%language%")[0]
+            else:
+                pattern = "*.ts"
             tslist.extend(Utilities.direntries(tpd, True, pattern))
-        if tslist:
-            if '_' in os.path.basename(tslist[0]):
-                # the first entry determines the mainscript name
-                mainscriptname = (
-                    os.path.splitext(mainscript)[0] or
-                    os.path.basename(tslist[0]).split('_')[0]
-                )
-                self.pdata["TRANSLATIONPATTERN"] = os.path.join(
-                    os.path.dirname(tslist[0]),
-                    "{0}_%language%{1}".format(
-                        os.path.basename(tslist[0]).split('_')[0],
-                        os.path.splitext(tslist[0])[1]))
-            else:
-                mainscriptname = ""
-                pattern, ok = QInputDialog.getText(
-                    None,
-                    self.tr("Translation Pattern"),
-                    self.tr(
-                        "Enter the path pattern for translation files "
-                        "(use '%language%' in place of the language code):"),
-                    # __IGNORE_WARNING_M601__
-                    QLineEdit.Normal,
-                    tslist[0])
-                if pattern:
-                    self.pdata["TRANSLATIONPATTERN"] = pattern
-            if self.pdata["TRANSLATIONPATTERN"]:
-                self.pdata["TRANSLATIONPATTERN"] = self.getRelativePath(
-                    self.pdata["TRANSLATIONPATTERN"])
-                pattern = self.pdata["TRANSLATIONPATTERN"].replace(
-                    "%language%", "*")
-                for ts in tslist:
-                    if fnmatch.fnmatch(ts, pattern):
-                        self.pdata["TRANSLATIONS"].append(ts)
-                        self.projectLanguageAdded.emit(ts)
-                if self.pdata["TRANSLATIONSBINPATH"]:
-                    tpd = os.path.join(self.ppath,
-                                       self.pdata["TRANSLATIONSBINPATH"])
-                    pattern = os.path.basename(
-                        self.pdata["TRANSLATIONPATTERN"]).replace(
+            pattern = self.__binaryTranslationFile(pattern)
+            if pattern:
+                tslist.extend(Utilities.direntries(tpd, True, pattern))
+            if tslist:
+                if '_' in os.path.basename(tslist[0]):
+                    # the first entry determines the mainscript name
+                    mainscriptname = (
+                        os.path.splitext(mainscript)[0] or
+                        os.path.basename(tslist[0]).split('_')[0]
+                    )
+                    self.pdata["TRANSLATIONPATTERN"] = os.path.join(
+                        os.path.dirname(tslist[0]),
+                        "{0}_%language%{1}".format(
+                            os.path.basename(tslist[0]).split('_')[0],
+                            os.path.splitext(tslist[0])[1]))
+                else:
+                    mainscriptname = ""
+                    pattern, ok = QInputDialog.getText(
+                        None,
+                        self.tr("Translation Pattern"),
+                        self.tr(
+                            "Enter the path pattern for translation files "
+                            "(use '%language%' in place of the language"
+                            " code):"),
+                        QLineEdit.Normal,
+                        tslist[0])
+                    if pattern:
+                        self.pdata["TRANSLATIONPATTERN"] = pattern
+                if self.pdata["TRANSLATIONPATTERN"]:
+                    self.pdata["TRANSLATIONPATTERN"] = self.getRelativePath(
+                        self.pdata["TRANSLATIONPATTERN"])
+                    pattern = self.pdata["TRANSLATIONPATTERN"].replace(
                         "%language%", "*")
-                    pattern = self.__binaryTranslationFile(pattern)
-                    qmlist = Utilities.direntries(tpd, True, pattern)
-                    for qm in qmlist:
-                        self.pdata["TRANSLATIONS"].append(qm)
-                        self.projectLanguageAdded.emit(qm)
-            if not self.pdata["MAINSCRIPT"] and bool(mainscriptname):
-                if self.pdata["PROGLANGUAGE"] in [
-                    "Python3", "MicroPython"
-                ]:
-                    self.pdata["MAINSCRIPT"] = '{0}.py'.format(mainscriptname)
-                elif self.pdata["PROGLANGUAGE"] == "Ruby":
-                    self.pdata["MAINSCRIPT"] = '{0}.rb'.format(mainscriptname)
-        self.setDirty(True)
-        QApplication.restoreOverrideCursor()
+                    for ts in tslist:
+                        if fnmatch.fnmatch(ts, pattern):
+                            self.pdata["TRANSLATIONS"].append(ts)
+                            self.projectLanguageAdded.emit(ts)
+                    if self.pdata["TRANSLATIONSBINPATH"]:
+                        tpd = os.path.join(self.ppath,
+                                           self.pdata["TRANSLATIONSBINPATH"])
+                        pattern = os.path.basename(
+                            self.pdata["TRANSLATIONPATTERN"]).replace(
+                            "%language%", "*")
+                        pattern = self.__binaryTranslationFile(pattern)
+                        qmlist = Utilities.direntries(tpd, True, pattern)
+                        for qm in qmlist:
+                            self.pdata["TRANSLATIONS"].append(qm)
+                            self.projectLanguageAdded.emit(qm)
+                if not self.pdata["MAINSCRIPT"] and bool(mainscriptname):
+                    if self.pdata["PROGLANGUAGE"] in [
+                        "Python3", "MicroPython"
+                    ]:
+                        self.pdata["MAINSCRIPT"] = '{0}.py'.format(
+                            mainscriptname)
+                    elif self.pdata["PROGLANGUAGE"] == "Ruby":
+                        self.pdata["MAINSCRIPT"] = '{0}.rb'.format(
+                            mainscriptname)
+            self.setDirty(True)
     
     def __showProperties(self):
         """
@@ -2895,18 +2894,15 @@
         
         if fn:
             if self.closeProject():
-                QApplication.setOverrideCursor(QCursor(Qt.WaitCursor))
-                QApplication.processEvents()
-                if self.__readProject(fn):
+                with E5OverrideCursor():
+                    ok = self.__readProject(fn)
+                if ok:
                     self.opened = True
                     if not self.pdata["FILETYPES"]:
                         self.initFileTypes()
                     else:
                         self.updateFileTypes()
                     
-                    QApplication.restoreOverrideCursor()
-                    QApplication.processEvents()
-                    
                     try:
                         # create management directory if not present
                         self.createProjectManagementDir()
@@ -2923,94 +2919,88 @@
                     # read a user specific project file
                     self.__readUserProperties()
                     
-                    QApplication.setOverrideCursor(QCursor(Qt.WaitCursor))
-                    QApplication.processEvents()
-                    
-                    oldState = self.isDirty()
-                    self.vcs = self.initVCS()
-                    if self.vcs is None and self.isDirty() == oldState:
-                        # check, if project is version controlled
-                        pluginManager = e5App().getObject("PluginManager")
-                        for indicator, vcsData in (
-                            pluginManager.getVcsSystemIndicators().items()
-                        ):
-                            if os.path.exists(
-                                    os.path.join(self.ppath, indicator)):
-                                if len(vcsData) > 1:
-                                    vcsList = []
-                                    for _vcsSystemStr, vcsSystemDisplay in (
-                                        vcsData
-                                    ):
-                                        vcsList.append(vcsSystemDisplay)
-                                    QApplication.restoreOverrideCursor()
-                                    res, vcs_ok = QInputDialog.getItem(
-                                        None,
-                                        self.tr("New Project"),
-                                        self.tr(
-                                            "Select Version Control System"),
-                                        vcsList,
-                                        0, False)
-                                    QApplication.setOverrideCursor(
-                                        QCursor(Qt.WaitCursor))
-                                    QApplication.processEvents()
-                                    if vcs_ok:
-                                        for vcsSystemStr, vcsSystemDisplay in (
-                                            vcsData
-                                        ):
-                                            if res == vcsSystemDisplay:
-                                                vcsSystem = vcsSystemStr
-                                                break
+                    with E5OverrideCursor():
+                        oldState = self.isDirty()
+                        self.vcs = self.initVCS()
+                        if self.vcs is None and self.isDirty() == oldState:
+                            # check, if project is version controlled
+                            pluginManager = e5App().getObject("PluginManager")
+                            for indicator, vcsData in (
+                                pluginManager.getVcsSystemIndicators().items()
+                            ):
+                                if os.path.exists(
+                                        os.path.join(self.ppath, indicator)):
+                                    if len(vcsData) > 1:
+                                        vcsList = []
+                                        for (
+                                            _vcsSystemStr, vcsSystemDisplay
+                                        ) in vcsData:
+                                            vcsList.append(vcsSystemDisplay)
+                                        with E5OverridenCursor():
+                                            res, vcs_ok = QInputDialog.getItem(
+                                                None,
+                                                self.tr("New Project"),
+                                                self.tr(
+                                                    "Select Version Control"
+                                                    " System"),
+                                                vcsList,
+                                                0, False)
+                                        if vcs_ok:
+                                            for (
+                                                vcsSystemStr, vcsSystemDisplay
+                                            ) in vcsData:
+                                                if res == vcsSystemDisplay:
+                                                    vcsSystem = vcsSystemStr
+                                                    break
+                                            else:
+                                                vcsSystem = "None"
                                         else:
                                             vcsSystem = "None"
                                     else:
-                                        vcsSystem = "None"
-                                else:
-                                    vcsSystem = vcsData[0][0]
-                                self.pdata["VCS"] = vcsSystem
-                                self.vcs = self.initVCS()
-                                self.setDirty(True)
-                    if (
-                        self.vcs is not None and
-                        (self.vcs.vcsRegisteredState(self.ppath) !=
-                            self.vcs.canBeCommitted)
-                    ):
-                        self.pdata["VCS"] = 'None'
-                        self.vcs = self.initVCS()
-                    self.closeAct.setEnabled(True)
-                    self.saveasAct.setEnabled(True)
-                    self.actGrp2.setEnabled(True)
-                    self.propsAct.setEnabled(True)
-                    self.userPropsAct.setEnabled(True)
-                    self.filetypesAct.setEnabled(True)
-                    self.lexersAct.setEnabled(True)
-                    self.sessActGrp.setEnabled(True)
-                    self.dbgActGrp.setEnabled(True)
-                    self.menuDebuggerAct.setEnabled(True)
-                    self.menuSessionAct.setEnabled(True)
-                    self.menuCheckAct.setEnabled(True)
-                    self.menuShowAct.setEnabled(True)
-                    self.menuDiagramAct.setEnabled(True)
-                    self.menuApidocAct.setEnabled(True)
-                    self.menuPackagersAct.setEnabled(True)
-                    self.pluginGrp.setEnabled(
-                        self.pdata["PROJECTTYPE"] in ["E6Plugin"])
-                    self.addLanguageAct.setEnabled(
-                        bool(self.pdata["TRANSLATIONPATTERN"]))
-                    self.makeGrp.setEnabled(
-                        self.pdata["MAKEPARAMS"]["MakeEnabled"])
-                    self.menuMakeAct.setEnabled(
-                        self.pdata["MAKEPARAMS"]["MakeEnabled"])
-                    
-                    # open a project debugger properties file being quiet
-                    # about errors
-                    if Preferences.getProject("AutoLoadDbgProperties"):
-                        self.__readDebugProperties(True)
-                    
-                    self.__model.projectOpened()
-                    self.projectOpenedHooks.emit()
-                    self.projectOpened.emit()
-                    
-                    QApplication.restoreOverrideCursor()
+                                        vcsSystem = vcsData[0][0]
+                                    self.pdata["VCS"] = vcsSystem
+                                    self.vcs = self.initVCS()
+                                    self.setDirty(True)
+                        if (
+                            self.vcs is not None and
+                            (self.vcs.vcsRegisteredState(self.ppath) !=
+                                self.vcs.canBeCommitted)
+                        ):
+                            self.pdata["VCS"] = 'None'
+                            self.vcs = self.initVCS()
+                        self.closeAct.setEnabled(True)
+                        self.saveasAct.setEnabled(True)
+                        self.actGrp2.setEnabled(True)
+                        self.propsAct.setEnabled(True)
+                        self.userPropsAct.setEnabled(True)
+                        self.filetypesAct.setEnabled(True)
+                        self.lexersAct.setEnabled(True)
+                        self.sessActGrp.setEnabled(True)
+                        self.dbgActGrp.setEnabled(True)
+                        self.menuDebuggerAct.setEnabled(True)
+                        self.menuSessionAct.setEnabled(True)
+                        self.menuCheckAct.setEnabled(True)
+                        self.menuShowAct.setEnabled(True)
+                        self.menuDiagramAct.setEnabled(True)
+                        self.menuApidocAct.setEnabled(True)
+                        self.menuPackagersAct.setEnabled(True)
+                        self.pluginGrp.setEnabled(
+                            self.pdata["PROJECTTYPE"] in ["E6Plugin"])
+                        self.addLanguageAct.setEnabled(
+                            bool(self.pdata["TRANSLATIONPATTERN"]))
+                        self.makeGrp.setEnabled(
+                            self.pdata["MAKEPARAMS"]["MakeEnabled"])
+                        self.menuMakeAct.setEnabled(
+                            self.pdata["MAKEPARAMS"]["MakeEnabled"])
+                        
+                        # open a project debugger properties file being quiet
+                        # about errors
+                        if Preferences.getProject("AutoLoadDbgProperties"):
+                            self.__readDebugProperties(True)
+                        
+                        self.__model.projectOpened()
+                        self.projectOpenedHooks.emit()
+                        self.projectOpened.emit()
                     
                     if Preferences.getProject("SearchNewFiles"):
                         self.__doSearchNewFiles()
@@ -3050,8 +3040,6 @@
                             self.vcsStatusMonitorInfo)
                         self.vcs.vcsStatusChanged.connect(
                             self.__vcsStatusChanged)
-                else:
-                    QApplication.restoreOverrideCursor()
         
     def reopenProject(self):
         """
@@ -4774,10 +4762,11 @@
         if not self.isOpen():
             return
         
-        name = self.getRelativePath(fullname)
-        self.prepareRepopulateItem.emit(name)
-        self.__model.repopulateItem(name)
-        self.completeRepopulateItem.emit(name)
+        with E5OverrideCursor():
+            name = self.getRelativePath(fullname)
+            self.prepareRepopulateItem.emit(name)
+            self.__model.repopulateItem(name)
+            self.completeRepopulateItem.emit(name)
     
     ##############################################################
     ## Below is the VCS interface
@@ -4825,25 +4814,26 @@
             if not vcsExists:
                 if override:
                     # override failed, revert to original
-                    QApplication.restoreOverrideCursor()
+                    with E5OverridenCursor():
+                        E5MessageBox.critical(
+                            self.ui,
+                            self.tr("Version Control System"),
+                            self.tr(
+                                "<p>The selected VCS <b>{0}</b> could not be"
+                                " found. <br/>Reverting override.</p><p>{1}"
+                                "</p>")
+                            .format(vcsSystem, msg))
+                        self.pudata["VCSOVERRIDE"] = ""
+                    return self.initVCS(nooverride=True)
+                
+                with E5OverridenCursor():
                     E5MessageBox.critical(
                         self.ui,
                         self.tr("Version Control System"),
                         self.tr(
                             "<p>The selected VCS <b>{0}</b> could not be"
-                            " found. <br/>Reverting override.</p><p>{1}</p>")
-                        .format(vcsSystem, msg))
-                    self.pudata["VCSOVERRIDE"] = ""
-                    return self.initVCS(nooverride=True)
-                
-                QApplication.restoreOverrideCursor()
-                E5MessageBox.critical(
-                    self.ui,
-                    self.tr("Version Control System"),
-                    self.tr(
-                        "<p>The selected VCS <b>{0}</b> could not be"
-                        " found.<br/>Disabling version control.</p>"
-                        "<p>{1}</p>").format(vcsSystem, msg))
+                            " found.<br/>Disabling version control.</p>"
+                            "<p>{1}</p>").format(vcsSystem, msg))
                 vcs = None
                 if forProject:
                     self.pdata["VCS"] = 'None'
@@ -5843,3 +5833,6 @@
             "CompressionDisable": False,
             "PathPrefix": "",
         }
+
+#
+# eflag: noqa = M601
--- a/eric6/Project/ProjectBaseBrowser.py	Fri Oct 09 17:19:29 2020 +0200
+++ b/eric6/Project/ProjectBaseBrowser.py	Sat Oct 10 12:20:51 2020 +0200
@@ -14,13 +14,13 @@
     QModelIndex, pyqtSignal, Qt, QCoreApplication, QItemSelectionModel,
     QItemSelection, QElapsedTimer
 )
-from PyQt5.QtGui import QCursor
 from PyQt5.QtWidgets import (
     QTreeView, QApplication, QMenu, QDialog, QAbstractItemView
 )
 
 from E5Gui.E5Application import e5App
 from E5Gui import E5MessageBox
+from E5Gui.E5OverrideCursor import E5OverrideCursor
 
 from UI.Browser import Browser
 from UI.BrowserModel import BrowserDirectoryItem, BrowserFileItem
@@ -366,54 +366,50 @@
         Protected slot to handle the 'Expand all directories' menu action.
         """
         self._disconnectExpandedCollapsed()
-        QApplication.setOverrideCursor(QCursor(Qt.WaitCursor))
-        QApplication.processEvents()
-        index = self.model().index(0, 0)
-        while index.isValid():
-            itm = self.model().item(index)
-            if (
-                isinstance(
-                    itm,
-                    (ProjectBrowserSimpleDirectoryItem,
-                     ProjectBrowserDirectoryItem)) and
-                not self.isExpanded(index)
-            ):
-                self.expand(index)
-            index = self.indexBelow(index)
-        self.layoutDisplay()
+        with E5OverrideCursor():
+            index = self.model().index(0, 0)
+            while index.isValid():
+                itm = self.model().item(index)
+                if (
+                    isinstance(
+                        itm,
+                        (ProjectBrowserSimpleDirectoryItem,
+                         ProjectBrowserDirectoryItem)) and
+                    not self.isExpanded(index)
+                ):
+                    self.expand(index)
+                index = self.indexBelow(index)
+            self.layoutDisplay()
         self._connectExpandedCollapsed()
-        QApplication.restoreOverrideCursor()
         
     def _collapseAllDirs(self):
         """
         Protected slot to handle the 'Collapse all directories' menu action.
         """
         self._disconnectExpandedCollapsed()
-        QApplication.setOverrideCursor(QCursor(Qt.WaitCursor))
-        QApplication.processEvents()
-        # step 1: find last valid index
-        vindex = QModelIndex()
-        index = self.model().index(0, 0)
-        while index.isValid():
-            vindex = index
-            index = self.indexBelow(index)
-        
-        # step 2: go up collapsing all directory items
-        index = vindex
-        while index.isValid():
-            itm = self.model().item(index)
-            if (
-                isinstance(
-                    itm,
-                    (ProjectBrowserSimpleDirectoryItem,
-                     ProjectBrowserDirectoryItem)) and
-                self.isExpanded(index)
-            ):
-                self.collapse(index)
-            index = self.indexAbove(index)
-        self.layoutDisplay()
+        with E5OverrideCursor():
+            # step 1: find last valid index
+            vindex = QModelIndex()
+            index = self.model().index(0, 0)
+            while index.isValid():
+                vindex = index
+                index = self.indexBelow(index)
+            
+            # step 2: go up collapsing all directory items
+            index = vindex
+            while index.isValid():
+                itm = self.model().item(index)
+                if (
+                    isinstance(
+                        itm,
+                        (ProjectBrowserSimpleDirectoryItem,
+                         ProjectBrowserDirectoryItem)) and
+                    self.isExpanded(index)
+                ):
+                    self.collapse(index)
+                index = self.indexAbove(index)
+            self.layoutDisplay()
         self._connectExpandedCollapsed()
-        QApplication.restoreOverrideCursor()
         
     def _showContextMenu(self, menu):
         """
@@ -506,41 +502,37 @@
         # expand all directories in order to iterate over all entries
         self._expandAllDirs()
         
-        QApplication.setOverrideCursor(QCursor(Qt.WaitCursor))
-        QApplication.processEvents()
         self.selectionModel().clear()
-        QApplication.processEvents()
         
-        # now iterate over all entries
-        startIndex = None
-        endIndex = None
-        selectedEntries = 0
-        index = self.model().index(0, 0)
-        while index.isValid():
-            itm = self.model().item(index)
-            if (
-                self.wantedItem(itm, filterList) and
-                compareString == itm.data(1)
-            ):
+        with E5OverrideCursor():
+            # now iterate over all entries
+            startIndex = None
+            endIndex = None
+            selectedEntries = 0
+            index = self.model().index(0, 0)
+            while index.isValid():
+                itm = self.model().item(index)
                 if (
-                    startIndex is not None and
-                    startIndex.parent() != index.parent()
+                    self.wantedItem(itm, filterList) and
+                    compareString == itm.data(1)
                 ):
-                    self._setItemRangeSelected(startIndex, endIndex, True)
-                    startIndex = None
-                selectedEntries += 1
-                if startIndex is None:
-                    startIndex = index
-                endIndex = index
-            else:
-                if startIndex is not None:
-                    self._setItemRangeSelected(startIndex, endIndex, True)
-                    startIndex = None
-            index = self.indexBelow(index)
-        if startIndex is not None:
-            self._setItemRangeSelected(startIndex, endIndex, True)
-        QApplication.restoreOverrideCursor()
-        QApplication.processEvents()
+                    if (
+                        startIndex is not None and
+                        startIndex.parent() != index.parent()
+                    ):
+                        self._setItemRangeSelected(startIndex, endIndex, True)
+                        startIndex = None
+                    selectedEntries += 1
+                    if startIndex is None:
+                        startIndex = index
+                    endIndex = index
+                else:
+                    if startIndex is not None:
+                        self._setItemRangeSelected(startIndex, endIndex, True)
+                        startIndex = None
+                index = self.indexBelow(index)
+            if startIndex is not None:
+                self._setItemRangeSelected(startIndex, endIndex, True)
         
         if selectedEntries == 0:
             E5MessageBox.information(
@@ -628,8 +620,6 @@
         
         @param name relative name of file item to be repopulated (string)
         """
-        QApplication.setOverrideCursor(QCursor(Qt.WaitCursor))
-        QApplication.processEvents()
         itm = self.currentItem()
         if itm is not None:
             self.currentItemName = itm.data(0)
@@ -684,8 +674,6 @@
                     self._selectSingleItem(index)
                 self.expandedNames = []
         self.currentItemName = None
-        QApplication.restoreOverrideCursor()
-        QApplication.processEvents()
         self._resort()
         
     def currentItem(self):
--- a/eric6/QScintilla/Editor.py	Fri Oct 09 17:19:29 2020 +0200
+++ b/eric6/QScintilla/Editor.py	Sat Oct 10 12:20:51 2020 +0200
@@ -16,7 +16,7 @@
     QDir, QTimer, QModelIndex, QFileInfo, pyqtSignal, pyqtSlot,
     QCryptographicHash, QEvent, QDateTime, QRegExp, Qt, QPoint
 )
-from PyQt5.QtGui import QCursor, QPalette, QFont, QPixmap, QPainter
+from PyQt5.QtGui import QPalette, QFont, QPixmap, QPainter
 from PyQt5.QtWidgets import (
     QLineEdit, QActionGroup, QDialog, QInputDialog, QApplication, QMenu
 )
@@ -25,6 +25,8 @@
 
 from E5Gui.E5Application import e5App
 from E5Gui import E5FileDialog, E5MessageBox
+from E5Gui.E5OverrideCursor import E5OverrideCursor
+
 from E5Utilities.E5Cache import E5Cache
 
 from .QsciScintillaCompat import QsciScintillaCompat
@@ -3077,56 +3079,52 @@
         @keyparam encoding encoding to be used to read the file (string)
             (Note: this parameter overrides encoding detection)
         """
-        QApplication.setOverrideCursor(QCursor(Qt.WaitCursor))
-        
         self.__loadEditorConfig(fileName=fn)
         
         try:
-            if createIt and not os.path.exists(fn):
-                f = open(fn, "w")
-                f.close()
-            if encoding == "":
-                encoding = self.__getEditorConfig("DefaultEncoding",
-                                                  nodefault=True)
-            if encoding:
-                txt, self.encoding = Utilities.readEncodedFileWithEncoding(
-                    fn, encoding)
-            else:
-                txt, self.encoding = Utilities.readEncodedFile(fn)
+            with E5OverrideCursor():
+                if createIt and not os.path.exists(fn):
+                    f = open(fn, "w")
+                    f.close()
+                if encoding == "":
+                    encoding = self.__getEditorConfig("DefaultEncoding",
+                                                      nodefault=True)
+                if encoding:
+                    txt, self.encoding = Utilities.readEncodedFileWithEncoding(
+                        fn, encoding)
+                else:
+                    txt, self.encoding = Utilities.readEncodedFile(fn)
         except (UnicodeDecodeError, IOError) as why:
-            QApplication.restoreOverrideCursor()
             E5MessageBox.critical(
                 self.vm,
                 self.tr('Open File'),
                 self.tr('<p>The file <b>{0}</b> could not be opened.</p>'
                         '<p>Reason: {1}</p>')
                     .format(fn, str(why)))
-            QApplication.restoreOverrideCursor()
             raise
         
-        modified = False
-        
-        self.setText(txt)
-        
-        # get eric specific flags
-        self.__processFlags()
-        
-        # perform automatic EOL conversion
-        if (
-            self.__getEditorConfig("EOLMode", nodefault=True) or
-            Preferences.getEditor("AutomaticEOLConversion")
-        ):
-            self.convertEols(self.eolMode())
-        else:
-            fileEol = self.detectEolString(txt)
-            self.setEolModeByEolString(fileEol)
-        
-        self.extractTasks()
-        
-        QApplication.restoreOverrideCursor()
-        
-        self.setModified(modified)
-        self.lastModified = QFileInfo(self.fileName).lastModified()
+        with E5OverrideCursor():
+            modified = False
+            
+            self.setText(txt)
+            
+            # get eric specific flags
+            self.__processFlags()
+            
+            # perform automatic EOL conversion
+            if (
+                self.__getEditorConfig("EOLMode", nodefault=True) or
+                Preferences.getEditor("AutomaticEOLConversion")
+            ):
+                self.convertEols(self.eolMode())
+            else:
+                fileEol = self.detectEolString(txt)
+                self.setEolModeByEolString(fileEol)
+            
+            self.extractTasks()
+            
+            self.setModified(modified)
+            self.lastModified = QFileInfo(self.fileName).lastModified()
     
     def __convertTabs(self):
         """
--- a/eric6/QScintilla/Exporters/ExporterHTML.py	Fri Oct 09 17:19:29 2020 +0200
+++ b/eric6/QScintilla/Exporters/ExporterHTML.py	Sat Oct 10 12:20:51 2020 +0200
@@ -15,12 +15,12 @@
 import sys
 import io
 
-from PyQt5.QtCore import Qt
-from PyQt5.QtGui import QCursor, QFontInfo
-from PyQt5.QtWidgets import QApplication, QInputDialog
+from PyQt5.QtGui import QFontInfo
+from PyQt5.QtWidgets import QInputDialog
 from PyQt5.Qsci import QsciScintilla
 
 from E5Gui import E5MessageBox
+from E5Gui.E5OverrideCursor import E5OverrideCursor
 
 from .ExporterBase import ExporterBase
 
@@ -392,60 +392,56 @@
         if not filename:
             return
         
-        try:
-            QApplication.setOverrideCursor(QCursor(Qt.WaitCursor))
-            QApplication.processEvents()
-            
-            fn = self.editor.getFileName()
-            if fn:
-                extension = os.path.normcase(os.path.splitext(fn)[1][1:])
+        fn = self.editor.getFileName()
+        if fn:
+            extension = os.path.normcase(os.path.splitext(fn)[1][1:])
+        else:
+            extension = ""
+        
+        if (
+            extension in Preferences.getEditor(
+                "PreviewMarkdownFileNameExtensions") or
+            self.editor.getLanguage().lower() == "markdown"
+        ):
+            # export markdown to HTML
+            colorSchemes = [
+                self.tr("Light Background Color"),
+                self.tr("Dark Background Color"),
+            ]
+            colorScheme, ok = QInputDialog.getItem(
+                None,
+                self.tr("Markdown Export"),
+                self.tr("Select color scheme:"),
+                colorSchemes,
+                0, False)
+            if ok:
+                colorSchemeIndex = colorSchemes.index(colorScheme)
             else:
-                extension = ""
+                # light background as default
+                colorSchemeIndex = 0
+            with E5OverrideCursor():
+                html = self.__generateFromMarkdown(colorSchemeIndex == 1)
+        elif (
+            extension in Preferences.getEditor(
+                "PreviewRestFileNameExtensions") or
+            self.editor.getLanguage().lower() == "restructuredtext"
+        ):
+            # export ReST to HTML
+            with E5OverrideCursor():
+                html = self.__generateFromReSTDocutils()
+        else:
+            tabSize = self.editor.getEditorConfig("TabWidth")
+            if tabSize == 0:
+                tabSize = 4
+            wysiwyg = Preferences.getEditorExporter("HTML/WYSIWYG")
+            folding = Preferences.getEditorExporter("HTML/Folding")
+            onlyStylesUsed = Preferences.getEditorExporter(
+                "HTML/OnlyStylesUsed")
+            titleFullPath = Preferences.getEditorExporter(
+                "HTML/FullPathAsTitle")
+            tabs = Preferences.getEditorExporter("HTML/UseTabs")
             
-            if (
-                extension in Preferences.getEditor(
-                    "PreviewMarkdownFileNameExtensions") or
-                self.editor.getLanguage().lower() == "markdown"
-            ):
-                # export markdown to HTML
-                colorSchemes = [
-                    self.tr("Light Background Color"),
-                    self.tr("Dark Background Color"),
-                ]
-                QApplication.restoreOverrideCursor()
-                colorScheme, ok = QInputDialog.getItem(
-                    None,
-                    self.tr("Markdown Export"),
-                    self.tr("Select color scheme:"),
-                    colorSchemes,
-                    0, False)
-                if ok:
-                    colorSchemeIndex = colorSchemes.index(colorScheme)
-                else:
-                    # light background as default
-                    colorSchemeIndex = 0
-                QApplication.setOverrideCursor(QCursor(Qt.WaitCursor))
-                QApplication.processEvents()
-                html = self.__generateFromMarkdown(colorSchemeIndex == 1)
-            elif (
-                extension in Preferences.getEditor(
-                    "PreviewRestFileNameExtensions") or
-                self.editor.getLanguage().lower() == "restructuredtext"
-            ):
-                # export ReST to HTML
-                html = self.__generateFromReSTDocutils()
-            else:
-                tabSize = self.editor.getEditorConfig("TabWidth")
-                if tabSize == 0:
-                    tabSize = 4
-                wysiwyg = Preferences.getEditorExporter("HTML/WYSIWYG")
-                folding = Preferences.getEditorExporter("HTML/Folding")
-                onlyStylesUsed = Preferences.getEditorExporter(
-                    "HTML/OnlyStylesUsed")
-                titleFullPath = Preferences.getEditorExporter(
-                    "HTML/FullPathAsTitle")
-                tabs = Preferences.getEditorExporter("HTML/UseTabs")
-                
+            with E5OverrideCursor():
                 generator = HTMLGenerator(self.editor)
                 html = generator.generate(
                     tabSize=tabSize,
@@ -455,33 +451,30 @@
                     onlyStylesUsed=onlyStylesUsed,
                     titleFullPath=titleFullPath
                 )
-            
-            if html:
-                try:
+        
+        if html:
+            try:
+                with E5OverrideCursor():
                     f = open(filename, "w", encoding="utf-8")
                     f.write(html)
                     f.close()
-                except IOError as err:
-                    QApplication.restoreOverrideCursor()
-                    E5MessageBox.critical(
-                        self.editor,
-                        self.tr("Export source"),
-                        self.tr(
-                            """<p>The source could not be exported to"""
-                            """ <b>{0}</b>.</p><p>Reason: {1}</p>""")
-                        .format(filename, str(err)))
-            else:
-                QApplication.restoreOverrideCursor()
+            except IOError as err:
                 E5MessageBox.critical(
                     self.editor,
                     self.tr("Export source"),
                     self.tr(
                         """<p>The source could not be exported to"""
-                        """ <b>{0}</b>.</p><p>Reason: No HTML code"""
-                        """ generated.</p>""")
-                    .format(filename))
-        finally:
-            QApplication.restoreOverrideCursor()
+                        """ <b>{0}</b>.</p><p>Reason: {1}</p>""")
+                    .format(filename, str(err)))
+        else:
+            E5MessageBox.critical(
+                self.editor,
+                self.tr("Export source"),
+                self.tr(
+                    """<p>The source could not be exported to"""
+                    """ <b>{0}</b>.</p><p>Reason: No HTML code"""
+                    """ generated.</p>""")
+                .format(filename))
     
     def __generateFromReSTDocutils(self):
         """
--- a/eric6/QScintilla/Exporters/ExporterODT.py	Fri Oct 09 17:19:29 2020 +0200
+++ b/eric6/QScintilla/Exporters/ExporterODT.py	Sat Oct 10 12:20:51 2020 +0200
@@ -8,11 +8,10 @@
 """
 
 
-from PyQt5.QtCore import Qt
-from PyQt5.QtGui import QCursor, QTextDocument, QTextDocumentWriter
-from PyQt5.QtWidgets import QApplication
+from PyQt5.QtGui import QTextDocument, QTextDocumentWriter
 
 from E5Gui import E5MessageBox
+from E5Gui.E5OverrideCursor import E5OverrideCursor
 
 from .ExporterBase import ExporterBase
 from .ExporterHTML import HTMLGenerator
@@ -41,9 +40,6 @@
         if not filename:
             return
         
-        QApplication.setOverrideCursor(QCursor(Qt.WaitCursor))
-        QApplication.processEvents()
-        
         tabSize = self.editor.getEditorConfig("TabWidth")
         if tabSize == 0:
             tabSize = 4
@@ -51,23 +47,24 @@
         onlyStylesUsed = Preferences.getEditorExporter("ODT/OnlyStylesUsed")
         tabs = Preferences.getEditorExporter("ODT/UseTabs")
         
-        # generate HTML of the source
-        generator = HTMLGenerator(self.editor)
-        html = generator.generate(
-            tabSize=tabSize,
-            useTabs=tabs,
-            wysiwyg=wysiwyg,
-            folding=False,
-            onlyStylesUsed=onlyStylesUsed,
-            titleFullPath=False
-        )
+        with E5OverrideCursor():
+            # generate HTML of the source
+            generator = HTMLGenerator(self.editor)
+            html = generator.generate(
+                tabSize=tabSize,
+                useTabs=tabs,
+                wysiwyg=wysiwyg,
+                folding=False,
+                onlyStylesUsed=onlyStylesUsed,
+                titleFullPath=False
+            )
+            
+            # convert HTML to ODT
+            doc = QTextDocument()
+            doc.setHtml(html)
+            writer = QTextDocumentWriter(filename)
+            ok = writer.write(doc)
         
-        # convert HTML to ODT
-        doc = QTextDocument()
-        doc.setHtml(html)
-        writer = QTextDocumentWriter(filename)
-        ok = writer.write(doc)
-        QApplication.restoreOverrideCursor()
         if not ok:
             E5MessageBox.critical(
                 self.editor,
--- a/eric6/QScintilla/Exporters/ExporterPDF.py	Fri Oct 09 17:19:29 2020 +0200
+++ b/eric6/QScintilla/Exporters/ExporterPDF.py	Sat Oct 10 12:20:51 2020 +0200
@@ -11,12 +11,11 @@
 # This code is a port of the C++ code found in SciTE 1.74
 # Original code: Copyright 1998-2006 by Neil Hodgson <neilh@scintilla.org>
 
-from PyQt5.QtCore import Qt
-from PyQt5.QtGui import QCursor, QFontInfo
-from PyQt5.QtWidgets import QApplication
+from PyQt5.QtGui import QFontInfo
 from PyQt5.Qsci import QsciScintilla
 
 from E5Gui import E5MessageBox
+from E5Gui.E5OverrideCursor import E5OverrideCursor
 
 from .ExporterBase import ExporterBase
 
@@ -437,116 +436,113 @@
         if not filename:
             return
         
+        self.editor.recolor(0, -1)
+        lex = self.editor.getLexer()
+        
+        tabSize = self.editor.getEditorConfig("TabWidth")
+        if tabSize == 0:
+            tabSize = 4
+        
+        # get magnification value to add to default screen font size
+        self.pr.fontSize = Preferences.getEditorExporter(
+            "PDF/Magnification")
+        
+        # set font family according to face name
+        fontName = Preferences.getEditorExporter("PDF/Font")
+        self.pr.fontSet = PDF_FONT_DEFAULT
+        if fontName == "Courier":
+            self.pr.fontSet = 0
+        elif fontName == "Helvetica":
+            self.pr.fontSet = 1
+        elif fontName == "Times":
+            self.pr.fontSet = 2
+        
+        # page size: height, width,
+        pageSize = Preferences.getEditorExporter("PDF/PageSize")
         try:
-            QApplication.setOverrideCursor(QCursor(Qt.WaitCursor))
-            QApplication.processEvents()
-            
-            self.editor.recolor(0, -1)
-            lex = self.editor.getLexer()
-            
-            tabSize = self.editor.getEditorConfig("TabWidth")
-            if tabSize == 0:
-                tabSize = 4
-            
-            # get magnification value to add to default screen font size
-            self.pr.fontSize = Preferences.getEditorExporter(
-                "PDF/Magnification")
-            
-            # set font family according to face name
-            fontName = Preferences.getEditorExporter("PDF/Font")
-            self.pr.fontSet = PDF_FONT_DEFAULT
-            if fontName == "Courier":
-                self.pr.fontSet = 0
-            elif fontName == "Helvetica":
-                self.pr.fontSet = 1
-            elif fontName == "Times":
-                self.pr.fontSet = 2
+            pageDimensions = PDFpageSizes[pageSize]
+        except KeyError:
+            pageDimensions = PDFpageSizes["A4"]
+        self.pr.pageHeight = pageDimensions[0]
+        self.pr.pageWidth = pageDimensions[1]
+        
+        # page margins: left, right, top, bottom
+        # < 0 to use PDF default values
+        val = Preferences.getEditorExporter("PDF/MarginLeft")
+        if val < 0:
+            self.pr.pageMargins["left"] = PDF_MARGIN_DEFAULT
+        else:
+            self.pr.pageMargins["left"] = val
+        val = Preferences.getEditorExporter("PDF/MarginRight")
+        if val < 0:
+            self.pr.pageMargins["right"] = PDF_MARGIN_DEFAULT
+        else:
+            self.pr.pageMargins["right"] = val
+        val = Preferences.getEditorExporter("PDF/MarginTop")
+        if val < 0:
+            self.pr.pageMargins["top"] = PDF_MARGIN_DEFAULT
+        else:
+            self.pr.pageMargins["top"] = val
+        val = Preferences.getEditorExporter("PDF/MarginBottom")
+        if val < 0:
+            self.pr.pageMargins["bottom"] = PDF_MARGIN_DEFAULT
+        else:
+            self.pr.pageMargins["bottom"] = val
+        
+        # collect all styles available for that 'language'
+        # or the default style if no language is available...
+        if lex:
+            istyle = 0
+            while istyle <= QsciScintilla.STYLE_MAX:
+                if (istyle <= QsciScintilla.STYLE_DEFAULT or
+                        istyle > QsciScintilla.STYLE_LASTPREDEFINED):
+                    if (
+                        lex.description(istyle) or
+                        istyle == QsciScintilla.STYLE_DEFAULT
+                    ):
+                        style = PDFStyle()
+                        
+                        font = lex.font(istyle)
+                        if font.italic():
+                            style.font |= 2
+                        if font.bold():
+                            style.font |= 1
+                        
+                        colour = lex.color(istyle)
+                        style.fore = self.__getPDFRGB(colour)
+                        self.pr.style[istyle] = style
+                    
+                    # grab font size from default style
+                    if istyle == QsciScintilla.STYLE_DEFAULT:
+                        fontSize = QFontInfo(font).pointSize()
+                        if fontSize > 0:
+                            self.pr.fontSize += fontSize
+                        else:
+                            self.pr.fontSize = PDF_FONTSIZE_DEFAULT
+                
+                istyle += 1
+        else:
+            style = PDFStyle()
             
-            # page size: height, width,
-            pageSize = Preferences.getEditorExporter("PDF/PageSize")
-            try:
-                pageDimensions = PDFpageSizes[pageSize]
-            except KeyError:
-                pageDimensions = PDFpageSizes["A4"]
-            self.pr.pageHeight = pageDimensions[0]
-            self.pr.pageWidth = pageDimensions[1]
+            font = Preferences.getEditorOtherFonts("DefaultFont")
+            if font.italic():
+                style.font |= 2
+            if font.bold():
+                style.font |= 1
             
-            # page margins: left, right, top, bottom
-            # < 0 to use PDF default values
-            val = Preferences.getEditorExporter("PDF/MarginLeft")
-            if val < 0:
-                self.pr.pageMargins["left"] = PDF_MARGIN_DEFAULT
-            else:
-                self.pr.pageMargins["left"] = val
-            val = Preferences.getEditorExporter("PDF/MarginRight")
-            if val < 0:
-                self.pr.pageMargins["right"] = PDF_MARGIN_DEFAULT
-            else:
-                self.pr.pageMargins["right"] = val
-            val = Preferences.getEditorExporter("PDF/MarginTop")
-            if val < 0:
-                self.pr.pageMargins["top"] = PDF_MARGIN_DEFAULT
-            else:
-                self.pr.pageMargins["top"] = val
-            val = Preferences.getEditorExporter("PDF/MarginBottom")
-            if val < 0:
-                self.pr.pageMargins["bottom"] = PDF_MARGIN_DEFAULT
+            colour = self.editor.color()
+            style.fore = self.__getPDFRGB(colour)
+            self.pr.style[0] = style
+            self.pr.style[QsciScintilla.STYLE_DEFAULT] = style
+            
+            fontSize = QFontInfo(font).pointSize()
+            if fontSize > 0:
+                self.pr.fontSize += fontSize
             else:
-                self.pr.pageMargins["bottom"] = val
-            
-            # collect all styles available for that 'language'
-            # or the default style if no language is available...
-            if lex:
-                istyle = 0
-                while istyle <= QsciScintilla.STYLE_MAX:
-                    if (istyle <= QsciScintilla.STYLE_DEFAULT or
-                            istyle > QsciScintilla.STYLE_LASTPREDEFINED):
-                        if (
-                            lex.description(istyle) or
-                            istyle == QsciScintilla.STYLE_DEFAULT
-                        ):
-                            style = PDFStyle()
-                            
-                            font = lex.font(istyle)
-                            if font.italic():
-                                style.font |= 2
-                            if font.bold():
-                                style.font |= 1
-                            
-                            colour = lex.color(istyle)
-                            style.fore = self.__getPDFRGB(colour)
-                            self.pr.style[istyle] = style
-                        
-                        # grab font size from default style
-                        if istyle == QsciScintilla.STYLE_DEFAULT:
-                            fontSize = QFontInfo(font).pointSize()
-                            if fontSize > 0:
-                                self.pr.fontSize += fontSize
-                            else:
-                                self.pr.fontSize = PDF_FONTSIZE_DEFAULT
-                    
-                    istyle += 1
-            else:
-                style = PDFStyle()
-                
-                font = Preferences.getEditorOtherFonts("DefaultFont")
-                if font.italic():
-                    style.font |= 2
-                if font.bold():
-                    style.font |= 1
-                
-                colour = self.editor.color()
-                style.fore = self.__getPDFRGB(colour)
-                self.pr.style[0] = style
-                self.pr.style[QsciScintilla.STYLE_DEFAULT] = style
-                
-                fontSize = QFontInfo(font).pointSize()
-                if fontSize > 0:
-                    self.pr.fontSize += fontSize
-                else:
-                    self.pr.fontSize = PDF_FONTSIZE_DEFAULT
-            
-            try:
+                self.pr.fontSize = PDF_FONTSIZE_DEFAULT
+        
+        try:
+            with E5OverrideCursor():
                 # save file in win ansi using cp1250
                 f = open(filename, "w", encoding="cp1250",
                          errors="backslashreplace")
@@ -616,14 +612,11 @@
                 # write required stuff and close the PDF file
                 self.pr.endPDF()
                 f.close()
-            except IOError as err:
-                QApplication.restoreOverrideCursor()
-                E5MessageBox.critical(
-                    self.editor,
-                    self.tr("Export source"),
-                    self.tr(
-                        """<p>The source could not be exported to"""
-                        """ <b>{0}</b>.</p><p>Reason: {1}</p>""")
-                    .format(filename, str(err)))
-        finally:
-            QApplication.restoreOverrideCursor()
+        except IOError as err:
+            E5MessageBox.critical(
+                self.editor,
+                self.tr("Export source"),
+                self.tr(
+                    """<p>The source could not be exported to"""
+                    """ <b>{0}</b>.</p><p>Reason: {1}</p>""")
+                .format(filename, str(err)))
--- a/eric6/QScintilla/Exporters/ExporterRTF.py	Fri Oct 09 17:19:29 2020 +0200
+++ b/eric6/QScintilla/Exporters/ExporterRTF.py	Sat Oct 10 12:20:51 2020 +0200
@@ -13,12 +13,11 @@
 
 import time
 
-from PyQt5.QtCore import Qt
-from PyQt5.QtGui import QCursor, QFontInfo
-from PyQt5.QtWidgets import QApplication
+from PyQt5.QtGui import QFontInfo
 from PyQt5.Qsci import QsciScintilla
 
 from E5Gui import E5MessageBox
+from E5Gui.E5OverrideCursor import E5OverrideCursor
 
 from .ExporterBase import ExporterBase
 
@@ -120,40 +119,37 @@
         if not filename:
             return
         
+        self.editor.recolor(0, -1)
+        lex = self.editor.getLexer()
+        
+        tabSize = self.editor.getEditorConfig("TabWidth")
+        if tabSize == 0:
+            tabSize = 4
+        wysiwyg = Preferences.getEditorExporter("RTF/WYSIWYG")
+        if wysiwyg:
+            if lex:
+                defaultFont = lex.font(QsciScintilla.STYLE_DEFAULT)
+            else:
+                defaultFont = Preferences.getEditorOtherFonts(
+                    "DefaultFont")
+        else:
+            defaultFont = Preferences.getEditorExporter("RTF/Font")
+        fontface = defaultFont.family()
+        fontsize = QFontInfo(defaultFont).pointSize() << 1
+        if fontsize == 0:
+            fontsize = 10 << 1
+        characterset = QsciScintilla.SC_CHARSET_DEFAULT
+        tabs = Preferences.getEditorExporter("RTF/UseTabs")
+        
+        if lex:
+            fgColour = lex.color(QsciScintilla.STYLE_DEFAULT)
+            bgColour = lex.paper(QsciScintilla.STYLE_DEFAULT)
+        else:
+            fgColour = self.editor.color()
+            bgColour = self.editor.paper()
+        
         try:
-            QApplication.setOverrideCursor(QCursor(Qt.WaitCursor))
-            QApplication.processEvents()
-            
-            self.editor.recolor(0, -1)
-            lex = self.editor.getLexer()
-            
-            tabSize = self.editor.getEditorConfig("TabWidth")
-            if tabSize == 0:
-                tabSize = 4
-            wysiwyg = Preferences.getEditorExporter("RTF/WYSIWYG")
-            if wysiwyg:
-                if lex:
-                    defaultFont = lex.font(QsciScintilla.STYLE_DEFAULT)
-                else:
-                    defaultFont = Preferences.getEditorOtherFonts(
-                        "DefaultFont")
-            else:
-                defaultFont = Preferences.getEditorExporter("RTF/Font")
-            fontface = defaultFont.family()
-            fontsize = QFontInfo(defaultFont).pointSize() << 1
-            if fontsize == 0:
-                fontsize = 10 << 1
-            characterset = QsciScintilla.SC_CHARSET_DEFAULT
-            tabs = Preferences.getEditorExporter("RTF/UseTabs")
-            
-            if lex:
-                fgColour = lex.color(QsciScintilla.STYLE_DEFAULT)
-                bgColour = lex.paper(QsciScintilla.STYLE_DEFAULT)
-            else:
-                fgColour = self.editor.color()
-                bgColour = self.editor.paper()
-            
-            try:
+            with E5OverrideCursor():
                 f = open(filename, "w", encoding="utf-8")
                 
                 styles = {}
@@ -366,14 +362,11 @@
                 
                 f.write(self.RTF_BODYCLOSE)
                 f.close()
-            except IOError as err:
-                QApplication.restoreOverrideCursor()
-                E5MessageBox.critical(
-                    self.editor,
-                    self.tr("Export source"),
-                    self.tr(
-                        """<p>The source could not be exported to"""
-                        """ <b>{0}</b>.</p><p>Reason: {1}</p>""")
-                    .format(filename, str(err)))
-        finally:
-            QApplication.restoreOverrideCursor()
+        except IOError as err:
+            E5MessageBox.critical(
+                self.editor,
+                self.tr("Export source"),
+                self.tr(
+                    """<p>The source could not be exported to"""
+                    """ <b>{0}</b>.</p><p>Reason: {1}</p>""")
+                .format(filename, str(err)))
--- a/eric6/QScintilla/Exporters/ExporterTEX.py	Fri Oct 09 17:19:29 2020 +0200
+++ b/eric6/QScintilla/Exporters/ExporterTEX.py	Sat Oct 10 12:20:51 2020 +0200
@@ -13,12 +13,10 @@
 
 import os
 
-from PyQt5.QtCore import Qt
-from PyQt5.QtGui import QCursor
-from PyQt5.QtWidgets import QApplication
 from PyQt5.Qsci import QsciScintilla
 
 from E5Gui import E5MessageBox
+from E5Gui.E5OverrideCursor import E5OverrideCursor
 
 from .ExporterBase import ExporterBase
 
@@ -115,54 +113,51 @@
         if not filename:
             return
         
+        self.editor.recolor(0, -1)
+        
+        tabSize = self.editor.getEditorConfig("TabWidth")
+        if tabSize == 0:
+            tabSize = 4
+        
+        onlyStylesUsed = Preferences.getEditorExporter(
+            "TeX/OnlyStylesUsed")
+        titleFullPath = Preferences.getEditorExporter(
+            "TeX/FullPathAsTitle")
+        
+        lex = self.editor.getLexer()
+        self.defaultPaper = (
+            lex and
+            lex.paper(QsciScintilla.STYLE_DEFAULT) or
+            self.editor.paper().name()
+        )
+        self.defaultColor = (
+            lex and
+            lex.color(QsciScintilla.STYLE_DEFAULT) or
+            self.editor.color().name()
+        )
+        self.defaultFont = (
+            lex and
+            lex.color(QsciScintilla.STYLE_DEFAULT) or
+            Preferences.getEditorOtherFonts("DefaultFont")
+        )
+        
+        lengthDoc = self.editor.length()
+        styleIsUsed = {}
+        if onlyStylesUsed:
+            for index in range(QsciScintilla.STYLE_MAX + 1):
+                styleIsUsed[index] = False
+            # check the used styles
+            pos = 0
+            while pos < lengthDoc:
+                styleIsUsed[self.editor.styleAt(pos) & 0x7F] = True
+                pos += 1
+        else:
+            for index in range(QsciScintilla.STYLE_MAX + 1):
+                styleIsUsed[index] = True
+        styleIsUsed[QsciScintilla.STYLE_DEFAULT] = True
+        
         try:
-            QApplication.setOverrideCursor(QCursor(Qt.WaitCursor))
-            QApplication.processEvents()
-            
-            self.editor.recolor(0, -1)
-            
-            tabSize = self.editor.getEditorConfig("TabWidth")
-            if tabSize == 0:
-                tabSize = 4
-            
-            onlyStylesUsed = Preferences.getEditorExporter(
-                "TeX/OnlyStylesUsed")
-            titleFullPath = Preferences.getEditorExporter(
-                "TeX/FullPathAsTitle")
-            
-            lex = self.editor.getLexer()
-            self.defaultPaper = (
-                lex and
-                lex.paper(QsciScintilla.STYLE_DEFAULT) or
-                self.editor.paper().name()
-            )
-            self.defaultColor = (
-                lex and
-                lex.color(QsciScintilla.STYLE_DEFAULT) or
-                self.editor.color().name()
-            )
-            self.defaultFont = (
-                lex and
-                lex.color(QsciScintilla.STYLE_DEFAULT) or
-                Preferences.getEditorOtherFonts("DefaultFont")
-            )
-            
-            lengthDoc = self.editor.length()
-            styleIsUsed = {}
-            if onlyStylesUsed:
-                for index in range(QsciScintilla.STYLE_MAX + 1):
-                    styleIsUsed[index] = False
-                # check the used styles
-                pos = 0
-                while pos < lengthDoc:
-                    styleIsUsed[self.editor.styleAt(pos) & 0x7F] = True
-                    pos += 1
-            else:
-                for index in range(QsciScintilla.STYLE_MAX + 1):
-                    styleIsUsed[index] = True
-            styleIsUsed[QsciScintilla.STYLE_DEFAULT] = True
-            
-            try:
+            with E5OverrideCursor():
                 f = open(filename, "w", encoding="utf-8")
                 
                 f.write("\\documentclass[a4paper]{article}\n")
@@ -279,14 +274,11 @@
                 # close last empty style macros and document too
                 f.write("}\n} %end tiny\n\n\\end{document}\n")
                 f.close()
-            except IOError as err:
-                QApplication.restoreOverrideCursor()
-                E5MessageBox.critical(
-                    self.editor,
-                    self.tr("Export source"),
-                    self.tr(
-                        """<p>The source could not be exported to"""
-                        """ <b>{0}</b>.</p><p>Reason: {1}</p>""")
-                    .format(filename, str(err)))
-        finally:
-            QApplication.restoreOverrideCursor()
+        except IOError as err:
+            E5MessageBox.critical(
+                self.editor,
+                self.tr("Export source"),
+                self.tr(
+                    """<p>The source could not be exported to"""
+                    """ <b>{0}</b>.</p><p>Reason: {1}</p>""")
+                .format(filename, str(err)))
--- a/eric6/QScintilla/MiniEditor.py	Fri Oct 09 17:19:29 2020 +0200
+++ b/eric6/QScintilla/MiniEditor.py	Sat Oct 10 12:20:51 2020 +0200
@@ -15,7 +15,7 @@
     QSignalMapper, QPoint, QTimer, QFileInfo, pyqtSignal, QSize, QRegExp, Qt,
     QCoreApplication
 )
-from PyQt5.QtGui import QCursor, QKeySequence, QPalette, QFont, QPixmap
+from PyQt5.QtGui import QKeySequence, QPalette, QFont, QPixmap
 from PyQt5.QtWidgets import (
     QWidget, QWhatsThis, QActionGroup, QDialog, QInputDialog, QApplication,
     QMenu, QVBoxLayout, QHBoxLayout, QLabel
@@ -28,6 +28,7 @@
 from E5Gui.E5MainWindow import E5MainWindow
 from E5Gui.E5ClickableLabel import E5ClickableLabel
 from E5Gui.E5ZoomWidget import E5ZoomWidget
+from E5Gui.E5OverrideCursor import E5OverrideCursor
 
 from .QsciScintillaCompat import QsciScintillaCompat
 
@@ -2519,48 +2520,45 @@
         @param fileName name of the file to load (string)
         @param filetype type of the source file (string)
         """
-        QApplication.setOverrideCursor(QCursor(Qt.WaitCursor))
-        
         self.__loadEditorConfig(fileName=fileName)
         
         try:
-            encoding = self.__getEditorConfig("DefaultEncoding",
-                                              nodefault=True)
-            if encoding:
-                txt, self.encoding = Utilities.readEncodedFileWithEncoding(
-                    fileName, encoding)
-            else:
-                txt, self.encoding = Utilities.readEncodedFile(fileName)
+            with E5OverrideCursor():
+                encoding = self.__getEditorConfig("DefaultEncoding",
+                                                  nodefault=True)
+                if encoding:
+                    txt, self.encoding = Utilities.readEncodedFileWithEncoding(
+                        fileName, encoding)
+                else:
+                    txt, self.encoding = Utilities.readEncodedFile(fileName)
         except (UnicodeDecodeError, IOError) as why:
-            QApplication.restoreOverrideCursor()
             E5MessageBox.critical(
                 self, self.tr('Open File'),
                 self.tr('<p>The file <b>{0}</b> could not be opened.</p>'
                         '<p>Reason: {1}</p>')
                 .format(fileName, str(why)))
-            QApplication.restoreOverrideCursor()
             return
         
-        self.__textEdit.setText(txt)
-        QApplication.restoreOverrideCursor()
-        
-        if filetype is None:
-            self.filetype = ""
-        else:
-            self.filetype = filetype
-        self.__setCurrentFile(fileName)
-        
-        self.__textEdit.setModified(False)
-        self.setWindowModified(False)
-        
-        self.__convertTabs()
-        
-        eolMode = self.__getEditorConfig("EOLMode", nodefault=True)
-        if eolMode is None:
-            fileEol = self.__textEdit.detectEolString(txt)
-            self.__textEdit.setEolModeByEolString(fileEol)
-        else:
-            self.__textEdit.convertEols(eolMode)
+        with E5OverrideCursor():
+            self.__textEdit.setText(txt)
+            
+            if filetype is None:
+                self.filetype = ""
+            else:
+                self.filetype = filetype
+            self.__setCurrentFile(fileName)
+            
+            self.__textEdit.setModified(False)
+            self.setWindowModified(False)
+            
+            self.__convertTabs()
+            
+            eolMode = self.__getEditorConfig("EOLMode", nodefault=True)
+            if eolMode is None:
+                fileEol = self.__textEdit.detectEolString(txt)
+                self.__textEdit.setEolModeByEolString(fileEol)
+            else:
+                self.__textEdit.convertEols(eolMode)
         
         self.__statusBar.showMessage(self.tr("File loaded"), 2000)
     
@@ -2612,8 +2610,6 @@
         @return flag indicating success
         @rtype bool
         """
-        QApplication.setOverrideCursor(Qt.WaitCursor)
-        
         config = self.__loadEditorConfigObject(fileName)
         
         eol = self.__getEditorConfig("EOLMode", nodefault=True, config=config)
@@ -2636,13 +2632,13 @@
         
         # now write text to the file
         try:
-            editorConfigEncoding = self.__getEditorConfig(
-                "DefaultEncoding", nodefault=True, config=config)
-            self.encoding = Utilities.writeEncodedFile(
-                fileName, txt, self.encoding,
-                forcedEncoding=editorConfigEncoding)
+            with E5OverrideCursor():
+                editorConfigEncoding = self.__getEditorConfig(
+                    "DefaultEncoding", nodefault=True, config=config)
+                self.encoding = Utilities.writeEncodedFile(
+                    fileName, txt, self.encoding,
+                    forcedEncoding=editorConfigEncoding)
         except (IOError, Utilities.CodingError, UnicodeError) as why:
-            QApplication.restoreOverrideCursor()
             E5MessageBox.critical(
                 self, self.tr('Save File'),
                 self.tr('<p>The file <b>{0}</b> could not be saved.<br/>'
@@ -2650,7 +2646,6 @@
                 .format(fileName, str(why)))
             return False
         
-        QApplication.restoreOverrideCursor()
         self.__statusBar.showMessage(self.tr("File saved"), 2000)
         
         return True
--- a/eric6/Snapshot/SnapWidget.py	Fri Oct 09 17:19:29 2020 +0200
+++ b/eric6/Snapshot/SnapWidget.py	Sat Oct 10 12:20:51 2020 +0200
@@ -315,7 +315,6 @@
         Private method to redisplay the window.
         """
         self.__updatePreview()
-        QApplication.restoreOverrideCursor()
         if not self.__savedPosition.isNull():
             self.move(self.__savedPosition)
         self.show()
--- a/eric6/Tools/UIPreviewer.py	Fri Oct 09 17:19:29 2020 +0200
+++ b/eric6/Tools/UIPreviewer.py	Sat Oct 10 12:20:51 2020 +0200
@@ -9,7 +9,7 @@
 
 
 from PyQt5.QtCore import QDir, QFileInfo, QEvent, QSize, Qt
-from PyQt5.QtGui import QCursor, QKeySequence, QImageWriter, QPainter
+from PyQt5.QtGui import QKeySequence, QImageWriter, QPainter
 from PyQt5.QtWidgets import (
     QSizePolicy, QSpacerItem, QWidget, QHBoxLayout, QWhatsThis, QDialog,
     QScrollArea, QApplication, QStyleFactory, QFrame, QMainWindow,
@@ -22,6 +22,7 @@
 from E5Gui import E5MessageBox, E5FileDialog
 from E5Gui.E5MainWindow import E5MainWindow
 from E5Gui.E5Application import e5App
+from E5Gui.E5OverrideCursor import E5OverrideCursor
 
 import Preferences
 import UI.PixmapCache
@@ -376,26 +377,25 @@
         
         @param sstyle name of the selected style (string)
         """
-        QApplication.setOverrideCursor(QCursor(Qt.WaitCursor))
-        qstyle = QStyleFactory.create(sstyle)
-        self.mainWidget.setStyle(qstyle)
-        
-        lst = self.mainWidget.findChildren(QWidget)
-        for obj in lst:
-            try:
-                obj.setStyle(qstyle)
-            except AttributeError:
-                pass
-        del lst
-        
-        self.mainWidget.hide()
-        self.mainWidget.show()
-        
-        self.lastQStyle = qstyle
-        self.lastStyle = sstyle
-        Preferences.Prefs.settings.setValue(
-            'UIPreviewer/style', self.styleCombo.currentIndex())
-        QApplication.restoreOverrideCursor()
+        with E5OverrideCursor():
+            qstyle = QStyleFactory.create(sstyle)
+            self.mainWidget.setStyle(qstyle)
+            
+            lst = self.mainWidget.findChildren(QWidget)
+            for obj in lst:
+                try:
+                    obj.setStyle(qstyle)
+                except AttributeError:
+                    pass
+            del lst
+            
+            self.mainWidget.hide()
+            self.mainWidget.show()
+            
+            self.lastQStyle = qstyle
+            self.lastStyle = sstyle
+            Preferences.Prefs.settings.setValue(
+                'UIPreviewer/style', self.styleCombo.currentIndex())
     
     def __updateActions(self):
         """
--- a/eric6/UI/EmailDialog.py	Fri Oct 09 17:19:29 2020 +0200
+++ b/eric6/UI/EmailDialog.py	Sat Oct 10 12:20:51 2020 +0200
@@ -7,20 +7,20 @@
 Module implementing a dialog to send bug reports or feature requests.
 """
 
-
 import os
 import mimetypes
 import smtplib
 import socket
 
 from PyQt5.QtCore import Qt, pyqtSlot
-from PyQt5.QtGui import QCursor, QTextOption
+from PyQt5.QtGui import QTextOption
 from PyQt5.QtWidgets import (
-    QHeaderView, QLineEdit, QDialog, QInputDialog, QApplication,
-    QDialogButtonBox, QTreeWidgetItem
+    QHeaderView, QLineEdit, QDialog, QInputDialog, QDialogButtonBox,
+    QTreeWidgetItem
 )
 
 from E5Gui import E5MessageBox, E5FileDialog
+from E5Gui.E5OverrideCursor import E5OverrideCursor
 
 from .Ui_EmailDialog import Ui_EmailDialog
 
@@ -350,14 +350,11 @@
                     else:
                         return False
 
-            QApplication.setOverrideCursor(QCursor(Qt.WaitCursor))
-            QApplication.processEvents()
-            server.sendmail(Preferences.getUser("Email"), self.__toAddress,
-                            msg)
-            server.quit()
-            QApplication.restoreOverrideCursor()
+            with E5OverrideCursor():
+                server.sendmail(Preferences.getUser("Email"), self.__toAddress,
+                                msg)
+                server.quit()
         except (smtplib.SMTPException, socket.error) as e:
-            QApplication.restoreOverrideCursor()
             if isinstance(e, smtplib.SMTPResponseException):
                 errorStr = e.smtp_error.decode()
             elif isinstance(e, smtplib.SMTPException):
--- a/eric6/UI/PythonAstViewer.py	Fri Oct 09 17:19:29 2020 +0200
+++ b/eric6/UI/PythonAstViewer.py	Sat Oct 10 12:20:51 2020 +0200
@@ -11,14 +11,15 @@
 import ast
 
 from PyQt5.QtCore import pyqtSlot, Qt, QTimer
-from PyQt5.QtGui import QCursor, QBrush
+from PyQt5.QtGui import QBrush
 from PyQt5.QtWidgets import (
-    QTreeWidget, QApplication, QTreeWidgetItem, QAbstractItemView, QWidget,
-    QVBoxLayout
+    QTreeWidget, QTreeWidgetItem, QAbstractItemView, QWidget, QVBoxLayout
 )
 
 from ThirdParty.asttokens.asttokens import ASTTokens
 
+from E5Gui.E5OverrideCursor import E5OverrideCursor
+
 import Preferences
 
 
@@ -229,27 +230,25 @@
             ))
             return
         
-        QApplication.setOverrideCursor(QCursor(Qt.WaitCursor))
-        try:
-            # generate the AST
-            root = ast.parse(source, self.__editor.getFileName(), "exec")
-            self.__markTextRanges(root, source)
-            astValid = True
-        except Exception as exc:
-            self.__createErrorItem(str(exc))
-            astValid = False
-        
-        if astValid:
-            self.setUpdatesEnabled(False)
+        with E5OverrideCursor():
+            try:
+                # generate the AST
+                root = ast.parse(source, self.__editor.getFileName(), "exec")
+                self.__markTextRanges(root, source)
+                astValid = True
+            except Exception as exc:
+                self.__createErrorItem(str(exc))
+                astValid = False
             
-            # populate the AST tree
-            self.__populateNode(self.tr("Module"), root, self.__astWidget)
-            self.__selectItemForEditorSelection()
-            QTimer.singleShot(0, self.__resizeColumns)
-            
-            self.setUpdatesEnabled(True)
-        
-        QApplication.restoreOverrideCursor()
+            if astValid:
+                self.setUpdatesEnabled(False)
+                
+                # populate the AST tree
+                self.__populateNode(self.tr("Module"), root, self.__astWidget)
+                self.__selectItemForEditorSelection()
+                QTimer.singleShot(0, self.__resizeColumns)
+                
+                self.setUpdatesEnabled(True)
         
         self.__grabFocus()
     
--- a/eric6/UI/PythonDisViewer.py	Fri Oct 09 17:19:29 2020 +0200
+++ b/eric6/UI/PythonDisViewer.py	Sat Oct 10 12:20:51 2020 +0200
@@ -15,12 +15,13 @@
 
 
 from PyQt5.QtCore import pyqtSlot, Qt, QTimer
-from PyQt5.QtGui import QCursor, QBrush
+from PyQt5.QtGui import QBrush
 from PyQt5.QtWidgets import (
-    QApplication, QTreeWidgetItem, QAbstractItemView, QWidget, QMenu
+    QTreeWidgetItem, QAbstractItemView, QWidget, QMenu
 )
 
 from E5Gui.E5Application import e5App
+from E5Gui.E5OverrideCursor import E5OverrideCursor
 
 import Preferences
 
@@ -478,24 +479,22 @@
         else:
             filename = "<dis>"
         
-        QApplication.setOverrideCursor(QCursor(Qt.WaitCursor))
-        try:
-            codeObject = self.__tryCompile(source, filename)
-        except Exception as exc:
-            codeObject = None
-            self.__createErrorItem(str(exc))
-        
-        if codeObject:
-            self.setUpdatesEnabled(False)
-            block = self.disWidget.blockSignals(True)
+        with E5OverrideCursor():
+            try:
+                codeObject = self.__tryCompile(source, filename)
+            except Exception as exc:
+                codeObject = None
+                self.__createErrorItem(str(exc))
             
-            self.__disassembleObject(codeObject, self.disWidget, filename)
-            QTimer.singleShot(0, self.__resizeDisColumns)
-            
-            self.disWidget.blockSignals(block)
-            self.setUpdatesEnabled(True)
-        
-        QApplication.restoreOverrideCursor()
+            if codeObject:
+                self.setUpdatesEnabled(False)
+                block = self.disWidget.blockSignals(True)
+                
+                self.__disassembleObject(codeObject, self.disWidget, filename)
+                QTimer.singleShot(0, self.__resizeDisColumns)
+                
+                self.disWidget.blockSignals(block)
+                self.setUpdatesEnabled(True)
     
     @pyqtSlot(dict)
     def showDisassembly(self, disassembly):
--- a/eric6/WebBrowser/AdBlock/AdBlockTreeWidget.py	Fri Oct 09 17:19:29 2020 +0200
+++ b/eric6/WebBrowser/AdBlock/AdBlockTreeWidget.py	Sat Oct 10 12:20:51 2020 +0200
@@ -16,6 +16,7 @@
 )
 
 from E5Gui.E5TreeWidget import E5TreeWidget
+from E5Gui.E5OverrideCursor import E5OverrideCursor
 
 
 class AdBlockTreeWidget(E5TreeWidget):
@@ -79,35 +80,33 @@
         """
         Public method to refresh the tree.
         """
-        QApplication.setOverrideCursor(Qt.WaitCursor)
-        self.__itemChangingBlock = True
-        self.clear()
-        
-        boldFont = QFont()
-        boldFont.setBold(True)
-        
-        self.__topItem = QTreeWidgetItem(self)
-        self.__topItem.setText(0, self.__subscription.title())
-        self.__topItem.setFont(0, boldFont)
-        self.addTopLevelItem(self.__topItem)
-        
-        allRules = self.__subscription.allRules()
-        
-        index = 0
-        for rule in allRules:
-            item = QTreeWidgetItem(self.__topItem)
-            item.setText(0, rule.filter())
-            item.setData(0, Qt.UserRole, index)
-            if self.__subscription.canEditRules():
-                item.setFlags(item.flags() | Qt.ItemIsEditable)
-            self.__adjustItemFeatures(item, rule)
-            index += 1
-        
-        self.expandAll()
-        self.showRule(None)
-        self.__itemChangingBlock = False
-        QApplication.restoreOverrideCursor()
-        QApplication.processEvents()
+        with E5OverrideCursor():
+            self.__itemChangingBlock = True
+            self.clear()
+            
+            boldFont = QFont()
+            boldFont.setBold(True)
+            
+            self.__topItem = QTreeWidgetItem(self)
+            self.__topItem.setText(0, self.__subscription.title())
+            self.__topItem.setFont(0, boldFont)
+            self.addTopLevelItem(self.__topItem)
+            
+            allRules = self.__subscription.allRules()
+            
+            index = 0
+            for rule in allRules:
+                item = QTreeWidgetItem(self.__topItem)
+                item.setText(0, rule.filter())
+                item.setData(0, Qt.UserRole, index)
+                if self.__subscription.canEditRules():
+                    item.setFlags(item.flags() | Qt.ItemIsEditable)
+                self.__adjustItemFeatures(item, rule)
+                index += 1
+            
+            self.expandAll()
+            self.showRule(None)
+            self.__itemChangingBlock = False
     
     def addRule(self, filterRule=""):
         """
--- a/eric6/WebBrowser/FlashCookieManager/FlashCookieManagerDialog.py	Fri Oct 09 17:19:29 2020 +0200
+++ b/eric6/WebBrowser/FlashCookieManager/FlashCookieManagerDialog.py	Sat Oct 10 12:20:51 2020 +0200
@@ -14,6 +14,7 @@
 )
 
 from E5Gui import E5MessageBox
+from E5Gui.E5OverrideCursor import E5OverrideCursor
 
 from .Ui_FlashCookieManagerDialog import Ui_FlashCookieManagerDialog
 
@@ -336,58 +337,55 @@
         """
         Private slot to refresh the cookies list.
         """
-        QApplication.setOverrideCursor(Qt.WaitCursor)
-        
-        cookies = self.__manager.flashCookies()
-        self.cookiesList.clear()
-        
-        counter = 0
-        originDict = {}
-        for cookie in cookies:
-            cookieOrigin = cookie.origin
-            if cookieOrigin.startswith("."):
-                cookieOrigin = cookieOrigin[1:]
-            
-            if cookieOrigin in originDict:
-                itm = QTreeWidgetItem(originDict[cookieOrigin])
-            else:
-                newParent = QTreeWidgetItem(self.cookiesList)
-                newParent.setText(0, cookieOrigin)
-                newParent.setIcon(0, UI.PixmapCache.getIcon("dirOpen"))
-                self.cookiesList.addTopLevelItem(newParent)
-                originDict[cookieOrigin] = newParent
-                
-                itm = QTreeWidgetItem(newParent)
+        with E5OverrideCursor():
+            cookies = self.__manager.flashCookies()
+            self.cookiesList.clear()
             
-            suffix = ""
-            if cookie.path.startswith(
-                self.__manager.flashPlayerDataPath() +
-                    "/macromedia.com/support/flashplayer/sys"):
-                suffix = self.tr(" (settings)")
-            
-            if cookie.path + "/" + cookie.name in (
-                self.__manager.newCookiesList()
-            ):
-                suffix += self.tr(" [new]")
-                font = itm.font(0)
-                font.setBold(True)
-                itm.setFont(font)
-                itm.parent().setExpanded(True)
+            counter = 0
+            originDict = {}
+            for cookie in cookies:
+                cookieOrigin = cookie.origin
+                if cookieOrigin.startswith("."):
+                    cookieOrigin = cookieOrigin[1:]
+                
+                if cookieOrigin in originDict:
+                    itm = QTreeWidgetItem(originDict[cookieOrigin])
+                else:
+                    newParent = QTreeWidgetItem(self.cookiesList)
+                    newParent.setText(0, cookieOrigin)
+                    newParent.setIcon(0, UI.PixmapCache.getIcon("dirOpen"))
+                    self.cookiesList.addTopLevelItem(newParent)
+                    originDict[cookieOrigin] = newParent
+                    
+                    itm = QTreeWidgetItem(newParent)
+                
+                suffix = ""
+                if cookie.path.startswith(
+                    self.__manager.flashPlayerDataPath() +
+                        "/macromedia.com/support/flashplayer/sys"):
+                    suffix = self.tr(" (settings)")
+                
+                if cookie.path + "/" + cookie.name in (
+                    self.__manager.newCookiesList()
+                ):
+                    suffix += self.tr(" [new]")
+                    font = itm.font(0)
+                    font.setBold(True)
+                    itm.setFont(font)
+                    itm.parent().setExpanded(True)
+                
+                itm.setText(0, self.tr("{0}{1}", "name and suffix").format(
+                    cookie.name, suffix))
+                itm.setData(0, Qt.UserRole, cookie)
+                
+                counter += 1
+                if counter > 100:
+                    QApplication.processEvents()
+                    counter = 0
             
-            itm.setText(0, self.tr("{0}{1}", "name and suffix").format(
-                cookie.name, suffix))
-            itm.setData(0, Qt.UserRole, cookie)
-            
-            counter += 1
-            if counter > 100:
-                QApplication.processEvents()
-                counter = 0
-        
-        self.removeAllButton.setEnabled(
-            self.cookiesList.topLevelItemCount() > 0)
-        self.removeButton.setEnabled(False)
-        
-        QApplication.restoreOverrideCursor()
+            self.removeAllButton.setEnabled(
+                self.cookiesList.topLevelItemCount() > 0)
+            self.removeButton.setEnabled(False)
     
     @pyqtSlot()
     def __refreshFilterLists(self):
--- a/eric6/WebBrowser/SafeBrowsing/SafeBrowsingDialog.py	Fri Oct 09 17:19:29 2020 +0200
+++ b/eric6/WebBrowser/SafeBrowsing/SafeBrowsingDialog.py	Sat Oct 10 12:20:51 2020 +0200
@@ -10,10 +10,11 @@
 
 from PyQt5.QtCore import pyqtSlot, Qt, QUrl, QDateTime
 from PyQt5.QtWidgets import (
-    QDialog, QDialogButtonBox, QAbstractButton, QApplication
+    QDialog, QDialogButtonBox, QAbstractButton
 )
 
 from E5Gui import E5MessageBox
+from E5Gui.E5OverrideCursor import E5OverrideCursor
 
 from .Ui_SafeBrowsingDialog import Ui_SafeBrowsingDialog
 
@@ -167,7 +168,6 @@
         @return flag indicating safe to close
         @rtype bool
         """
-        QApplication.restoreOverrideCursor()
         if self.__isModified():
             res = E5MessageBox.okToClearData(
                 self,
@@ -200,10 +200,9 @@
             self.tr("""Updating the Safe Browsing cache might be a lengthy"""
                     """ operation. Please be patient!"""))
         
-        QApplication.setOverrideCursor(Qt.WaitCursor)
-        ok, error = self.__manager.updateHashPrefixCache()
-        self.__resetProgress()
-        QApplication.restoreOverrideCursor()
+        with E5OverrideCursor():
+            ok, error = self.__manager.updateHashPrefixCache()
+            self.__resetProgress()
         if not ok:
             if error:
                 E5MessageBox.critical(
@@ -229,9 +228,8 @@
             self.tr("""Do you really want to clear the Safe Browsing cache?"""
                     """ Re-populating it might take some time."""))
         if res:
-            QApplication.setOverrideCursor(Qt.WaitCursor)
-            self.__manager.fullCacheCleanup()
-            QApplication.restoreOverrideCursor()
+            with E5OverrideCursor():
+                self.__manager.fullCacheCleanup()
     
     @pyqtSlot(str, int)
     def __setProgressMessage(self, message, maximum):
--- a/eric6/WebBrowser/Session/SessionManager.py	Fri Oct 09 17:19:29 2020 +0200
+++ b/eric6/WebBrowser/Session/SessionManager.py	Sat Oct 10 12:20:51 2020 +0200
@@ -21,6 +21,7 @@
 )
 
 from E5Gui import E5MessageBox
+from E5Gui.E5OverrideCursor import E5OverrideCursor
 
 import Utilities
 import Preferences
@@ -439,28 +440,27 @@
         if window is None:
             window = WebBrowserWindow.mainWindow()
         
-        QApplication.setOverrideCursor(Qt.WaitCursor)
-        # restore session for first window
-        data = sessionData["Windows"].pop(0)
-        window.tabWidget().loadFromSessionData(data)
-        if "WindowGeometry" in data:
-            geometry = QByteArray.fromBase64(
-                data["WindowGeometry"].encode("ascii"))
-            window.restoreGeometry(geometry)
-        QApplication.processEvents()
-        
-        # restore additional windows
-        for data in sessionData["Windows"]:
-            window = (
-                WebBrowserWindow.mainWindow().newWindow(restoreSession=True)
-            )
+        with E5OverrideCursor():
+            # restore session for first window
+            data = sessionData["Windows"].pop(0)
             window.tabWidget().loadFromSessionData(data)
             if "WindowGeometry" in data:
                 geometry = QByteArray.fromBase64(
                     data["WindowGeometry"].encode("ascii"))
                 window.restoreGeometry(geometry)
             QApplication.processEvents()
-        QApplication.restoreOverrideCursor()
+            
+            # restore additional windows
+            for data in sessionData["Windows"]:
+                window = (
+                    WebBrowserWindow.mainWindow().newWindow(restoreSession=True)
+                )
+                window.tabWidget().loadFromSessionData(data)
+                if "WindowGeometry" in data:
+                    geometry = QByteArray.fromBase64(
+                        data["WindowGeometry"].encode("ascii"))
+                    window.restoreGeometry(geometry)
+                QApplication.processEvents()
         
         if "CurrentWindowIndex" in sessionData:
             currentWindowIndex = sessionData["CurrentWindowIndex"]
--- a/eric6/WebBrowser/WebBrowserTabWidget.py	Fri Oct 09 17:19:29 2020 +0200
+++ b/eric6/WebBrowser/WebBrowserTabWidget.py	Sat Oct 10 12:20:51 2020 +0200
@@ -13,13 +13,14 @@
 from PyQt5.QtCore import pyqtSignal, pyqtSlot, Qt, QUrl, QFile, QFileDevice
 from PyQt5.QtGui import QIcon, QPixmap, QPainter
 from PyQt5.QtWidgets import (
-    QWidget, QHBoxLayout, QMenu, QToolButton, QDialog, QApplication
+    QWidget, QHBoxLayout, QMenu, QToolButton, QDialog
 )
 from PyQt5.QtPrintSupport import QPrinter, QPrintDialog, QAbstractPrintDialog
 
 from E5Gui.E5TabWidget import E5TabWidget
 from E5Gui import E5MessageBox
 from E5Gui.E5Application import e5App
+from E5Gui.E5OverrideCursor import E5OverrideCursor
 
 from .WebBrowserView import WebBrowserView
 from .WebBrowserPage import WebBrowserPage
@@ -807,9 +808,8 @@
         @param browser reference to the browser to be printed
         @type WebBrowserView
         """
-        QApplication.setOverrideCursor(Qt.WaitCursor)
-        browser.page().execPrintPage(printer, 10 * 1000)
-        QApplication.restoreOverrideCursor()
+        with E5OverrideCursor():
+            browser.page().execPrintPage(printer, 10 * 1000)
     
     def __sourceChanged(self, url, browser):
         """
--- a/eric6/WebBrowser/WebBrowserWindow.py	Fri Oct 09 17:19:29 2020 +0200
+++ b/eric6/WebBrowser/WebBrowserWindow.py	Sat Oct 10 12:20:51 2020 +0200
@@ -35,6 +35,7 @@
 from E5Gui.E5MainWindow import E5MainWindow
 from E5Gui.E5Application import e5App
 from E5Gui.E5ZoomWidget import E5ZoomWidget
+from E5Gui.E5OverrideCursor import E5OverrideCursor
 
 from E5Network.E5NetworkIcon import E5NetworkIcon
 
@@ -3454,13 +3455,12 @@
         Private slot to synchronize the TOC with the currently shown page.
         """
         if WebBrowserWindow._useQtHelp:
-            QApplication.setOverrideCursor(Qt.WaitCursor)
-            url = self.currentBrowser().source()
-            self.__showTocWindow()
-            if not self.__tocWindow.syncToContent(url):
-                self.statusBar().showMessage(
-                    self.tr("Could not find an associated content."), 5000)
-            QApplication.restoreOverrideCursor()
+            with E5OverrideCursor():
+                url = self.currentBrowser().source()
+                self.__showTocWindow()
+                if not self.__tocWindow.syncToContent(url):
+                    self.statusBar().showMessage(
+                        self.tr("Could not find an associated content."), 5000)
         
     def __showTocWindow(self):
         """

eric ide

mercurial