UI/UserInterface.py

branch
maintenance
changeset 6646
51eefa621de4
parent 6602
331ac8f99cf8
parent 6645
ad476851d7e0
child 6747
09ad978cb776
--- a/UI/UserInterface.py	Sat Dec 01 11:45:24 2018 +0100
+++ b/UI/UserInterface.py	Thu Jan 10 14:22:59 2019 +0100
@@ -1,6 +1,6 @@
 # -*- coding: utf-8 -*-
 
-# Copyright (c) 2002 - 2018 Detlev Offenbach <detlev@die-offenbachs.de>
+# Copyright (c) 2002 - 2019 Detlev Offenbach <detlev@die-offenbachs.de>
 #
 
 """
@@ -19,7 +19,7 @@
 
 from PyQt5.QtCore import pyqtSlot, QTimer, QFile, QFileInfo, pyqtSignal, \
     PYQT_VERSION_STR, QDate, QIODevice, qVersion, QProcess, QSize, QUrl, \
-    QObject, Qt
+    QObject, Qt, QUuid, QThread
 from PyQt5.QtGui import QKeySequence, QDesktopServices
 from PyQt5.QtWidgets import QSizePolicy, QWidget, QWhatsThis, QToolBar, \
     QDialog, QSplitter, QApplication, QMenu, QVBoxLayout, QDockWidget, \
@@ -28,21 +28,6 @@
 from PyQt5.QtNetwork import QNetworkProxyFactory, QNetworkAccessManager, \
     QNetworkRequest, QNetworkReply
 
-from Globals import qVersionTuple
-try:
-    from PyQt5 import QtWebKit      # __IGNORE_WARNING__
-    WEBKIT_AVAILABLE = True
-except ImportError:
-    WEBKIT_AVAILABLE = False
-if qVersionTuple() < (5, 6, 0):
-    WEBENGINE_AVAILABLE = False
-else:
-    try:
-        from PyQt5 import QtWebEngineWidgets    # __IGNORE_WARNING__
-        WEBENGINE_AVAILABLE = True
-    except ImportError:
-        WEBENGINE_AVAILABLE = False
-
 from .Info import Version, VersionOnly, BugAddress, Program, FeatureAddress
 from . import Config
 
@@ -72,6 +57,8 @@
 
 from eric6config import getConfig
 
+from Globals import qVersionTuple
+
 
 class Redirector(QObject):
     """
@@ -282,6 +269,10 @@
         self.templateViewer = None
         self.numbersViewer = None
         
+        self.__webBrowserProcess = None
+        self.__webBrowserClient = None
+        self.__webBrowserSAName = QUuid.createUuid().toString()[1:-1]
+        
         # Create the main window now so that we can connect QActions to it.
         logging.debug("Creating Layout...")
         self.__createLayout(debugServer)
@@ -571,22 +562,9 @@
         self.toolProcs = []
         self.__initExternalToolsActions()
         
-        # create a dummy help window for shortcuts handling
-        if WEBENGINE_AVAILABLE:
-            from WebBrowser.WebBrowserWindow import WebBrowserWindow
-            self.dummyHelpViewer = \
-                WebBrowserWindow(None, '.', None, 'web_browser', True, True)
-        elif WEBKIT_AVAILABLE:
-            from Helpviewer.HelpWindow import HelpWindow
-            self.dummyHelpViewer = \
-                HelpWindow(None, '.', None, 'help viewer', True, True)
-        else:
-            self.dummyHelpViewer = None
-        
         # redirect handling of http and https URLs to ourselves
-        if WEBENGINE_AVAILABLE or WEBKIT_AVAILABLE:
-            QDesktopServices.setUrlHandler("http", self.handleUrl)
-            QDesktopServices.setUrlHandler("https", self.handleUrl)
+        QDesktopServices.setUrlHandler("http", self.handleUrl)
+        QDesktopServices.setUrlHandler("https", self.handleUrl)
         
         # register all relevant objects
         splash.showMessage(self.tr("Registering Objects..."))
@@ -602,8 +580,6 @@
         if self.templateViewer is not None:
             e5App().registerObject("TemplateViewer", self.templateViewer)
         e5App().registerObject("Shell", self.shell)
-        if self.dummyHelpViewer is not None:
-            e5App().registerObject("DummyHelpViewer", self.dummyHelpViewer)
         e5App().registerObject("PluginManager", self.pluginManager)
         e5App().registerObject("ToolbarManager", self.toolbarManager)
         if self.cooperation is not None:
@@ -720,9 +696,6 @@
             self.__networkManager.sslErrors.connect(self.__sslErrors)
         self.__replies = []
         
-        # attribute for the help window
-        self.helpWindow = None
-        
         # set spellchecker defaults
         from QScintilla.SpellChecker import SpellChecker
         SpellChecker.setDefaultLanguage(
@@ -1816,29 +1789,28 @@
         self.whatsThisAct.triggered.connect(self.__whatsThis)
         self.actions.append(self.whatsThisAct)
 
-        if WEBENGINE_AVAILABLE or WEBKIT_AVAILABLE:
-            self.helpviewerAct = E5Action(
-                self.tr('Helpviewer'),
-                UI.PixmapCache.getIcon("help.png"),
-                self.tr('&Helpviewer...'),
-                QKeySequence(self.tr("F1")),
-                0, self, 'helpviewer')
-            self.helpviewerAct.setStatusTip(self.tr(
-                'Open the helpviewer window'))
-            self.helpviewerAct.setWhatsThis(self.tr(
-                """<b>Helpviewer</b>"""
-                """<p>Display the eric6 web browser. This window will show"""
-                """ HTML help files and help from Qt help collections. It"""
-                """ has the capability to navigate to links, set bookmarks,"""
-                """ print the displayed help and some more features. You may"""
-                """ use it to browse the internet as well</p><p>If called"""
-                """ with a word selected, this word is search in the Qt help"""
-                """ collection.</p>"""
-            ))
-            self.helpviewerAct.triggered.connect(self.__helpViewer)
-            self.actions.append(self.helpviewerAct)
-        else:
-            self.helpviewerAct = None
+        self.helpviewerAct = E5Action(
+            self.tr('Helpviewer'),
+            UI.PixmapCache.getIcon("help.png"),
+            self.tr('&Helpviewer...'),
+            QKeySequence(self.tr("F1")),
+            0, self, 'helpviewer')
+        self.helpviewerAct.setStatusTip(self.tr(
+            'Open the helpviewer window'))
+        self.helpviewerAct.setWhatsThis(self.tr(
+            """<b>Helpviewer</b>"""
+            """<p>Display the eric6 web browser. This window will show"""
+            """ HTML help files and help from Qt help collections. It"""
+            """ has the capability to navigate to links, set bookmarks,"""
+            """ print the displayed help and some more features. You may"""
+            """ use it to browse the internet as well</p><p>If called"""
+            """ with a word selected, this word is search in the Qt help"""
+            """ collection.</p>"""
+        ))
+        self.helpviewerAct.triggered.connect(self.__helpViewer)
+        self.actions.append(self.helpviewerAct)
+##        else:
+##            self.helpviewerAct = None
         
         self.__initQtDocActions()
         self.__initPythonDocActions()
@@ -2145,22 +2117,21 @@
         self.hexEditorAct.triggered.connect(self.__openHexEditor)
         self.actions.append(self.hexEditorAct)
 
-        if WEBENGINE_AVAILABLE or WEBKIT_AVAILABLE:
-            self.webBrowserAct = E5Action(
-                self.tr('eric6 Web Browser'),
-                UI.PixmapCache.getIcon("ericWeb.png"),
-                self.tr('eric6 &Web Browser...'),
-                0, 0, self, 'web_browser')
-            self.webBrowserAct.setStatusTip(self.tr(
-                'Start the eric6 Web Browser'))
-            self.webBrowserAct.setWhatsThis(self.tr(
-                """<b>eric6 Web Browser</b>"""
-                """<p>Browse the Internet with the eric6 Web Browser.</p>"""
-            ))
-            self.webBrowserAct.triggered.connect(self.__startWebBrowser)
-            self.actions.append(self.webBrowserAct)
-        else:
-            self.webBrowserAct = None
+        self.webBrowserAct = E5Action(
+            self.tr('eric6 Web Browser'),
+            UI.PixmapCache.getIcon("ericWeb.png"),
+            self.tr('eric6 &Web Browser...'),
+            0, 0, self, 'web_browser')
+        self.webBrowserAct.setStatusTip(self.tr(
+            'Start the eric6 Web Browser'))
+        self.webBrowserAct.setWhatsThis(self.tr(
+            """<b>eric6 Web Browser</b>"""
+            """<p>Browse the Internet with the eric6 Web Browser.</p>"""
+        ))
+        self.webBrowserAct.triggered.connect(self.__startWebBrowser)
+        self.actions.append(self.webBrowserAct)
+##        else:
+##            self.webBrowserAct = None
 
         self.iconEditorAct = E5Action(
             self.tr('Icon Editor'),
@@ -3366,16 +3337,20 @@
             .format(sip_version_str)
         versionText += """<tr><td><b>QScintilla</b></td><td>{0}</td></tr>"""\
             .format(QSCINTILLA_VERSION_STR)
-        if WEBENGINE_AVAILABLE:
+        try:
             from WebBrowser.Tools import WebBrowserTools
             chromeVersion = WebBrowserTools.getWebEngineVersions()[0]
             versionText += \
                 """<tr><td><b>WebEngine</b></td><td>{0}</td></tr>"""\
                 .format(chromeVersion)
-        if WEBKIT_AVAILABLE:
+        except ImportError:
+            pass
+        try:
             from PyQt5.QtWebKit import qWebKitVersion
             versionText += """<tr><td><b>WebKit</b></td><td>{0}</td></tr>"""\
                 .format(qWebKitVersion())
+        except ImportError:
+            pass
         versionText += """<tr><td><b>{0}</b></td><td>{1}</td></tr>"""\
             .format(Program, Version)
         versionText += self.tr("""</table>""")
@@ -5234,10 +5209,7 @@
         if home.endswith(".chm"):
             self.__chmViewer(home)
         else:
-            if WEBENGINE_AVAILABLE:
-                hvType = Preferences.getWebBrowser("HelpViewerType")
-            else:
-                hvType = Preferences.getHelp("HelpViewerType")
+            hvType = Preferences.getWebBrowser("HelpViewerType")
             if hvType == 1:
                 self.launchHelpViewer(home)
             elif hvType == 2:
@@ -5298,10 +5270,7 @@
         if home.endswith(".chm"):
             self.__chmViewer(home)
         else:
-            if WEBENGINE_AVAILABLE:
-                hvType = Preferences.getWebBrowser("HelpViewerType")
-            else:
-                hvType = Preferences.getHelp("HelpViewerType")
+            hvType = Preferences.getWebBrowser("HelpViewerType")
             if hvType == 1:
                 self.launchHelpViewer(home)
             elif hvType == 2:
@@ -5367,10 +5336,7 @@
             else:
                 home = "file://" + home
         
-        if WEBENGINE_AVAILABLE:
-            hvType = Preferences.getWebBrowser("HelpViewerType")
-        else:
-            hvType = Preferences.getHelp("HelpViewerType")
+        hvType = Preferences.getWebBrowser("HelpViewerType")
         if hvType == 1:
             self.launchHelpViewer(home)
         elif hvType == 2:
@@ -5432,10 +5398,7 @@
         else:
             home = pyqt4DocDir
         
-        if WEBENGINE_AVAILABLE:
-            hvType = Preferences.getWebBrowser("HelpViewerType")
-        else:
-            hvType = Preferences.getHelp("HelpViewerType")
+        hvType = Preferences.getWebBrowser("HelpViewerType")
         if hvType == 1:
             self.launchHelpViewer(home)
         elif hvType == 2:
@@ -5499,10 +5462,7 @@
         else:
             home = pyqt5DocDir
         
-        if WEBENGINE_AVAILABLE:
-            hvType = Preferences.getWebBrowser("HelpViewerType")
-        else:
-            hvType = Preferences.getHelp("HelpViewerType")
+        hvType = Preferences.getWebBrowser("HelpViewerType")
         if hvType == 1:
             self.launchHelpViewer(home)
         elif hvType == 2:
@@ -5539,10 +5499,7 @@
             else:
                 home = "file://" + home
         
-        if WEBENGINE_AVAILABLE:
-            hvType = Preferences.getWebBrowser("HelpViewerType")
-        else:
-            hvType = Preferences.getHelp("HelpViewerType")
+        hvType = Preferences.getWebBrowser("HelpViewerType")
         if hvType == 1:
             self.launchHelpViewer(home)
         elif hvType == 2:
@@ -5608,10 +5565,7 @@
         else:
             home = pysideDocDir
         
-        if WEBENGINE_AVAILABLE:
-            hvType = Preferences.getWebBrowser("HelpViewerType")
-        else:
-            hvType = Preferences.getHelp("HelpViewerType")
+        hvType = Preferences.getWebBrowser("HelpViewerType")
         if hvType == 1:
             self.launchHelpViewer(home)
         elif hvType == 2:
@@ -5653,63 +5607,133 @@
             if not homeUrl.scheme():
                 home = QUrl.fromLocalFile(home).toString()
         
-        if WEBENGINE_AVAILABLE or WEBKIT_AVAILABLE:
-            single = useSingle
-            if WEBENGINE_AVAILABLE:
-                single = single or \
-                    Preferences.getWebBrowser("SingleWebBrowserWindow")
-            elif WEBKIT_AVAILABLE:
-                single = single or Preferences.getHelp("SingleHelpWindow")
-            if not single or self.helpWindow is None:
-                if WEBENGINE_AVAILABLE:
-                    from WebBrowser.WebBrowserWindow import WebBrowserWindow
-                    browser = WebBrowserWindow(home, '.', None, 'web_browser',
-                                               True, searchWord=searchWord)
-                elif WEBKIT_AVAILABLE:
-                    from Helpviewer.HelpWindow import HelpWindow
-                    browser = HelpWindow(home, '.', None, 'help viewer', True,
-                                         searchWord=searchWord)
-
-                if QApplication.desktop().width() > 400 and \
-                   QApplication.desktop().height() > 500:
-                    browser.show()
-                else:
-                    browser.showMaximized()
-                
-                if single:
-                    self.helpWindow = browser
-                    try:
-                        self.helpWindow.webBrowserWindowClosed.connect(
-                            self.__helpClosed)
-                    except AttributeError:
-                        self.helpWindow.helpClosed.connect(self.__helpClosed)
-                    self.preferencesChanged.connect(
-                        self.helpWindow.preferencesChanged)
-                    self.masterPasswordChanged.connect(
-                        self.helpWindow.masterPasswordChanged)
-            elif searchWord is not None:
-                self.helpWindow.search(searchWord)
-                self.helpWindow.raise_()
-            else:
-                self.helpWindow.newTab(home)
-                self.helpWindow.raise_()
-        else:
+        launchResult = self.__launchExternalWebBrowser(
+            home, searchWord=searchWord)
+        if not launchResult:
             self.__webBrowser(home)
     
-    def __helpClosed(self):
-        """
-        Private slot to handle the helpClosed signal of the help window.
-        """
-        if WEBENGINE_AVAILABLE:
-            single = Preferences.getWebBrowser("SingleWebBrowserWindow")
-        elif WEBKIT_AVAILABLE:
-            single = Preferences.getHelp("SingleHelpWindow")
-        if single:
-            self.preferencesChanged.disconnect(
-                self.helpWindow.preferencesChanged)
-            self.masterPasswordChanged.disconnect(
-                self.helpWindow.masterPasswordChanged)
-            self.helpWindow = None
+    def __launchExternalWebBrowser(self, home, searchWord=None):
+        """
+        Private method to start an external web browser and communicate with
+        it.
+        
+        @param home filename of file to be shown or URL to be opened
+        @type str
+        @keyparam searchWord word to search for
+        @type str
+        @return flag indicating a successful launch
+        @rtype bool
+        """
+        clientArgs = []
+        if searchWord:
+            clientArgs.append("--search={0}".format(searchWord))
+        
+        if self.__webBrowserProcess is None:
+            webBrowsers = [
+                os.path.join(
+                    os.path.dirname(__file__), "..", "eric6_browser.py"),
+                # QtWebEngine based web browser
+                os.path.join(
+                    os.path.dirname(__file__), "..", "eric6_webbrowser.py"),
+                # QtWebKit based web browser
+            ]
+            process = QProcess()
+            for browser in webBrowsers:
+                args = [
+                    browser,
+                    "--quiet",
+                    "--qthelp",
+                    "--single",
+                    "--name={0}".format(self.__webBrowserSAName)
+                ]
+                process.start(sys.executable, args)
+                if not process.waitForStarted():
+                    E5MessageBox.warning(
+                        self,
+                        self.tr("Start Web Browser"),
+                        self.tr("""The eric6 web browser could not be"""
+                                """ started."""))
+                    return False
+                
+                res = self.__connectToWebBrowser(process)
+                if res == 1:
+                    # connection unsuccessful
+                    return False
+                elif res == 0:
+                    # successful
+                    break
+            else:
+                return False
+            
+            process.finished.connect(self.__webBrowserFinished)
+            self.__webBrowserProcess = process
+            
+            if home:
+                clientArgs.append(home)
+        else:
+            clientArgs.append("--newtab={0}".format(home))
+        
+        if clientArgs:
+            self.__webBrowserClient.processArgs(clientArgs, disconnect=False)
+        
+        return True
+    
+    def __connectToWebBrowser(self, process):
+        """
+        Private method to connect to a started web browser.
+        
+        @param process reference to the started web browser process
+        @type QProcess
+        @return error indication (1 = connection not possible, 0 = ok,
+            -1 = server exited with an error code)
+        @rtype int
+        """
+        from WebBrowser.WebBrowserSingleApplication import \
+            WebBrowserSingleApplicationClient
+        
+        webBrowserClient = WebBrowserSingleApplicationClient(
+            self.__webBrowserSAName)
+        connectCount = 30
+        while connectCount:
+            res = webBrowserClient.connect()
+            if res != 0:
+                break
+            else:
+                connectCount -= 1
+                QThread.msleep(1000)
+                QApplication.processEvents()
+            if process.state() == QProcess.NotRunning and \
+               process.exitStatus() == QProcess.NormalExit and \
+               process.exitCode() == 100:
+                # Process exited prematurely due to missing pre-requisites
+                return -1
+        if res <= 0:
+            E5MessageBox.warning(
+                self,
+                self.tr("Start Web Browser"),
+                self.tr("""<p>The eric6 web browser is not started.</p>"""
+                        """<p>Reason: {0}</p>""").format(
+                    webBrowserClient.errstr())
+            )
+            return 1
+        
+        self.__webBrowserClient = webBrowserClient
+        return 0
+    
+    def __webBrowserFinished(self):
+        """
+        Private slot handling the end of the external web browser process.
+        """
+        self.__webBrowserProcess.deleteLater()
+        
+        self.__webBrowserProcess = None
+        self.__webBrowserClient = None
+    
+    def __webBrowserShutdown(self):
+        """
+        Private method to shut down the web browser.
+        """
+        self.__webBrowserClient.processArgs(["--shutdown"], disconnect=False)
     
     def __helpViewer(self):
         """
@@ -5734,22 +5758,6 @@
                 self.tr('Open Browser'),
                 self.tr('Could not start a web browser'))
 
-    def getHelpViewer(self, preview=False):
-        """
-        Public method to get a reference to the help window instance.
-        
-        @keyparam preview flag indicating to get a help window for preview
-            (boolean)
-        @return reference to the help window instance (HelpWindow)
-        """
-        if WEBENGINE_AVAILABLE or WEBKIT_AVAILABLE:
-            if self.helpWindow is None:
-                self.launchHelpViewer("", useSingle=True)
-            self.helpWindow.raise_()
-            return self.helpWindow
-        else:
-            return None
-    
     @pyqtSlot()
     @pyqtSlot(str)
     def showPreferences(self, pageName=None):
@@ -5762,7 +5770,6 @@
         dlg = ConfigurationDialog(
             self, 'Configuration',
             expandedEntries=self.__expandedConfigurationEntries,
-            webEngine=WEBENGINE_AVAILABLE,
         )
         dlg.preferencesChanged.connect(self.__preferencesChanged)
         dlg.masterPasswordChanged.connect(self.__masterPasswordChanged)
@@ -5872,19 +5879,21 @@
         @param oldPassword current master password (string)
         @param newPassword new master password (string)
         """
+        import Globals
+        
         self.masterPasswordChanged.emit(oldPassword, newPassword)
         Preferences.convertPasswords(oldPassword, newPassword)
-        if self.helpWindow is None:
-            if WEBENGINE_AVAILABLE:
-                from WebBrowser.Passwords.PasswordManager import \
-                    PasswordManager
-                pwManager = PasswordManager()
-                pwManager.masterPasswordChanged(oldPassword, newPassword)
-            elif WEBKIT_AVAILABLE:
-                from Helpviewer.Passwords.PasswordManager import \
-                    PasswordManager
-                pwManager = PasswordManager()
-                pwManager.masterPasswordChanged(oldPassword, newPassword)
+        variant = Globals.getWebBrowserSupport()
+        if variant == "QtWebEngine":
+            from WebBrowser.Passwords.PasswordManager import \
+                PasswordManager
+            pwManager = PasswordManager()
+            pwManager.masterPasswordChanged(oldPassword, newPassword)
+        elif variant == "QtWebKit":
+            from Helpviewer.Passwords.PasswordManager import \
+                PasswordManager
+            pwManager = PasswordManager()
+            pwManager.masterPasswordChanged(oldPassword, newPassword)
         Utilities.crypto.changeRememberedMaster(newPassword)
         
     def __reloadAPIs(self):
@@ -5936,7 +5945,7 @@
         """
         if self.shortcutsDialog is None:
             from Preferences.ShortcutsDialog import ShortcutsDialog
-            self.shortcutsDialog = ShortcutsDialog(self, 'Shortcuts')
+            self.shortcutsDialog = ShortcutsDialog(self)
         self.shortcutsDialog.populate()
         self.shortcutsDialog.show()
         
@@ -6563,9 +6572,8 @@
         if self.shutdownCalled:
             return True
         
-        if self.helpWindow is not None:
-            if not self.helpWindow.shutdown():
-                return False
+        if self.__webBrowserProcess is not None:
+            self.__webBrowserShutdown()
         
         if self.irc is not None:
             if not self.irc.shutdown():

eric ide

mercurial