Continued implementing session support for the new web browser.

Sat, 01 Jul 2017 19:14:01 +0200

author
Detlev Offenbach <detlev@die-offenbachs.de>
date
Sat, 01 Jul 2017 19:14:01 +0200
changeset 5780
79d06c98c5c9
parent 5779
b53fabc86f3c
child 5782
60874802161b

Continued implementing session support for the new web browser.

Documentation/Help/source.qch file | annotate | diff | comparison | revisions
WebBrowser/Session/SessionManager.py file | annotate | diff | comparison | revisions
WebBrowser/WebBrowserPage.py file | annotate | diff | comparison | revisions
WebBrowser/WebBrowserTabWidget.py file | annotate | diff | comparison | revisions
WebBrowser/WebBrowserWindow.py file | annotate | diff | comparison | revisions
Binary file Documentation/Help/source.qch has changed
--- a/WebBrowser/Session/SessionManager.py	Fri Jun 30 19:58:09 2017 +0200
+++ b/WebBrowser/Session/SessionManager.py	Sat Jul 01 19:14:01 2017 +0200
@@ -12,8 +12,11 @@
 import os
 import json
 
-from PyQt5.QtCore import pyqtSlot, pyqtSignal, QObject, QTimer, QDir, QFile, \
-    QFileInfo, QFileSystemWatcher
+from PyQt5.QtCore import pyqtSlot, pyqtSignal, Qt, QObject, QTimer, QDir, \
+    QFile, QFileInfo, QFileSystemWatcher, QByteArray
+from PyQt5.QtWidgets import QMenu, QAction, QActionGroup, QApplication
+
+from E5Gui import E5MessageBox
 
 import Utilities
 import Preferences
@@ -46,6 +49,7 @@
     SwitchSession = 1
     CloneSession = 2
     ReplaceSession = SwitchSession | 4
+    RestoreSession = 8
     
     def __init__(self, parent=None):
         """
@@ -179,12 +183,29 @@
             data["WindowGeometry"] = bytes(geometry.toBase64()).decode("ascii")
             
             sessionData["Windows"].append(data)
-        else:
-            return
+        
+        if sessionData["Windows"]:
+            sessionFile = open(sessionFileName, "w")
+            json.dump(sessionData, sessionFile, indent=2)
+            sessionFile.close()
+    
+    def __readSessionFromFile(self, sessionFileName):
+        """
+        Private method to read the session data from a file.
         
-        sessionFile = open(sessionFileName, "w")
-        json.dump(sessionData, sessionFile, indent=2)
-        sessionFile.close()
+        @param sessionFileName file name of the session file
+        @type str
+        @return dictionary containing the session data
+        @rtype dict
+        """
+        try:
+            sessionFile = open(sessionFileName, "r")
+            sessionData = json.load(sessionFile)
+            sessionFile.close()
+        except (IOError, OSError):
+            sessionData = {}
+        
+        return sessionData
     
     def __backupSavedSession(self):
         """
@@ -239,7 +260,7 @@
             return
         
         sessionFilesInfoList = QDir(self.getSessionsDirectory()).entryInfoList(
-            QDir.Files, QDir.Time)
+            ["*.json"], QDir.Files, QDir.Time)
         for sessionFileInfo in sessionFilesInfoList:
             data = SessionMetaData()
             data.name = sessionFileInfo.baseName()
@@ -274,9 +295,86 @@
         
         self.sessionsMetaDataChanged.emit()
     
-    def openSession(self, sessionFilePath="", flags=None):
-        # TODO: implement this
-        pass
+    @pyqtSlot()
+    def aboutToShowSessionsMenu(self):
+        """
+        Public slot to populate the sessions selection menu.
+        """
+        menu = self.sender()
+        if isinstance(menu, QMenu):
+            menu.clear()
+            
+            actionGroup = QActionGroup(menu)
+            sessions = self.sessionMetaData(includeBackups=False)
+            for session in sessions:
+                act = menu.addAction(session.name)
+                act.setCheckable(True)
+                act.setChecked(session.isActive)
+                act.setData(session.filePath)
+                actionGroup.addAction(act)
+                act.triggered.connect(self.__sessionActTriggered)
+    
+    @pyqtSlot()
+    def __sessionActTriggered(self):
+        """
+        Private slot to handle the menu selection of a session.
+        """
+        act = self.sender()
+        if isinstance(act, QAction):
+            path = act.data()
+            self.switchToSession(path)
+    
+    def __openSession(self, sessionFilePath, flags=None):
+        """
+        Private method to open a session from a given session file.
+        """
+        if self.__isActive(sessionFilePath):
+            return
+        
+        sessionData = self.__readSessionFromFile(sessionFilePath)
+        if not sessionData or not sessionData["Windows"]:
+            return
+        
+        from WebBrowser.WebBrowserWindow import WebBrowserWindow
+        window = WebBrowserWindow.mainWindow()
+        if flags & SessionManager.SwitchSession:
+            # save the current session
+            self.writeCurrentSession(self.__lastActiveSession)
+            
+            # create new window for the new session
+            window = window.newWindow(restoreSession=True)
+            
+            # close all existing windows
+            for win in WebBrowserWindow.mainWindows():
+                if win is not window:
+                    win.forceClose()
+            
+            if not (flags & SessionManager.ReplaceSession):
+                self.__lastActiveSession = \
+                    QFileInfo(sessionFilePath).canonicalFilePath()
+                self.__sessionMetaData = []
+        
+        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)
+            window.tabWidget().loadFromSessionData(data)
+            if "WindowGeometry" in data:
+                geometry = QByteArray.fromBase64(
+                    data["WindowGeometry"].encode("ascii"))
+                window.restoreGeometry(geometry)
+            QApplication.processEvents()
+        QApplication.restoreOverrideCursor()
     
     def renameSession(self, sessionFilePath="", flags=None):
         # TODO: implement this
@@ -286,26 +384,43 @@
         # TODO: implement this
         pass
     
-    def __replaceSession(self, sessionFilePath):
-        # TODO: implement this
-        pass
+    def replaceSession(self, sessionFilePath):
+        """
+        Public method to replace the current session with the given one.
+        
+        @param sessionFilePath file name of the session file to replace with
+        @type str
+        """
+        from WebBrowser.WebBrowserWindow import WebBrowserWindow
+        res = E5MessageBox.yesNo(
+            WebBrowserWindow.mainWindow(),
+            self.tr("Restore Backup"),
+            self.tr("""Are you sure you want to replace current session?"""))
+        if res:
+            self.__openSession(sessionFilePath, SessionManager.ReplaceSession)
     
-    def __switchToSession(self, sessionFilePath):
-        # TODO: implement this
-        pass
+    def switchToSession(self, sessionFilePath):
+        """
+        Public method to switch the current session to the given one.
+        
+        @param sessionFilePath file name of the session file to switch to
+        @type str
+        """
+        self.__openSession(sessionFilePath, SessionManager.SwitchSession)
     
-    def __cloneSession(self, sessionFilePath):
+    def cloneSession(self, sessionFilePath):
         # TODO: implement this
         pass
     
-    def __deleteSession(self, sessionFilePath):
+    def deleteSession(self, sessionFilePath):
         # TODO: implement this
         pass
     
-    def __newSession(self):
+    def newSession(self):
         # TODO: implement this
         pass
     
-    def openSessionManagerDialog(self):
+    def showSessionManagerDialog(self):
         # TODO: implement this
         pass
+        print("showSessionManagerDialog()")
--- a/WebBrowser/WebBrowserPage.py	Fri Jun 30 19:58:09 2017 +0200
+++ b/WebBrowser/WebBrowserPage.py	Sat Jul 01 19:14:01 2017 +0200
@@ -407,6 +407,10 @@
             encoding="ascii")
         sessionData["HistoryIndex"] = self.history().currentItemIndex()
         
+        # 4. current URL
+        sessionData["Url"] = self.url().toString(
+            QUrl.PrettyDecoded | QUrl.RemovePassword)
+        
         return sessionData
     
     def loadFromSessionData(self, sessionData):
--- a/WebBrowser/WebBrowserTabWidget.py	Fri Jun 30 19:58:09 2017 +0200
+++ b/WebBrowser/WebBrowserTabWidget.py	Sat Jul 01 19:14:01 2017 +0200
@@ -378,15 +378,21 @@
         """
         self.newBrowser()
     
-    def newBrowser(self, link=None, position=-1, background=False):
+    def newBrowser(self, link=None, position=-1, background=False,
+                   restoreSession=False):
         """
         Public method to create a new web browser tab.
         
-        @param link link to be shown (string or QUrl)
+        @param link link to be shown
+        @type str or QUrl
         @keyparam position position to create the new tab at or -1 to add it
-            to the end (integer)
+            to the end
+        @type int
         @keyparam background flag indicating to open the tab in the
-            background (bool)
+            background
+        @type bool
+        @keyparam restoreSession flag indicating a restore session action
+        @type bool
         @return reference to the new browser
         @rtype WebBrowserView
         """
@@ -449,7 +455,7 @@
         self.__closeButton.setEnabled(True)
         self.__navigationButton.setEnabled(True)
         
-        if not linkName:
+        if not linkName and not restoreSession:
             if Preferences.getWebBrowser("StartupBehavior") == 0:
                 linkName = Preferences.getWebBrowser("HomePage")
             elif Preferences.getWebBrowser("StartupBehavior") == 1:
@@ -1222,7 +1228,7 @@
         # 1. load tab data
         if "Tabs" in sessionData:
             for data in sessionData["Tabs"]:
-                browser = self.newBrowser()
+                browser = self.newBrowser(restoreSession=True)
                 browser.page().loadFromSessionData(data)
         
         # 2. set tab index
--- a/WebBrowser/WebBrowserWindow.py	Fri Jun 30 19:58:09 2017 +0200
+++ b/WebBrowser/WebBrowserWindow.py	Sat Jul 01 19:14:01 2017 +0200
@@ -113,22 +113,35 @@
     
     def __init__(self, home, path, parent, name, fromEric=False,
                  initShortcutsOnly=False, searchWord=None,
-                 private=False, qthelp=False, settingsDir=""):
+                 private=False, qthelp=False, settingsDir="",
+                 restoreSession=False):
         """
         Constructor
         
-        @param home the URL to be shown (string)
-        @param path the path of the working dir (usually '.') (string)
-        @param parent parent widget of this window (QWidget)
-        @param name name of this window (string)
+        @param home the URL to be shown
+        @type str
+        @param path the path of the working dir (usually '.')
+        @type str
+        @param parent parent widget of this window
+        @type QWidget
+        @param name name of this window
+        @type str
         @param fromEric flag indicating whether it was called from within
-            eric6 (boolean)
+            eric6
+        @type bool
         @keyparam initShortcutsOnly flag indicating to just initialize the
-            keyboard shortcuts (boolean)
-        @keyparam searchWord word to search for (string)
-        @keyparam private flag indicating a private browsing window (bool)
-        @keyparam qthelp flag indicating to enable the QtHelp support (bool)
-        @keyparam settingsDir directory to be used for the settings files (str)
+            keyboard shortcuts
+        @type bool
+        @keyparam searchWord word to search for
+        @type str
+        @keyparam private flag indicating a private browsing window
+        @type bool
+        @keyparam qthelp flag indicating to enable the QtHelp support
+        @type bool
+        @keyparam settingsDir directory to be used for the settings files
+        @type str
+        @keyparam restoreSession flag indicating a restore session action
+        @type bool
         """
         self.__hideNavigationTimer = None
         
@@ -340,8 +353,9 @@
             syncMgr.syncMessage.connect(self.statusBar().showMessage)
             syncMgr.syncError.connect(self.statusBar().showMessage)
             
-            self.__tabWidget.newBrowser(home)
-            self.__tabWidget.currentBrowser().setFocus()
+            if not restoreSession:
+                self.__tabWidget.newBrowser(home)
+                self.__tabWidget.currentBrowser().setFocus()
             
             self.__imagesIcon = ImagesIcon(self)
             self.statusBar().addPermanentWidget(self.__imagesIcon)
@@ -428,6 +442,7 @@
             self.__hideNavigationTimer.setSingleShot(True)
             self.__hideNavigationTimer.timeout.connect(self.__hideNavigation)
             
+            self.__forcedClose = False
             self.sessionManager()
             
             QTimer.singleShot(0, syncMgr.loadSettings)
@@ -1835,6 +1850,21 @@
             self.showTabManagerAct.triggered.connect(self.__showTabManager)
         self.__actions.append(self.showTabManagerAct)
         
+        self.showSessionsManagerAct = E5Action(
+            self.tr('Session Manager'),
+            self.tr('Session Manager...'),
+            0, 0, self, 'webbrowser_show_session_manager')
+        self.showSessionsManagerAct.setStatusTip(self.tr(
+            'Shows the session manager window'))
+        self.showSessionsManagerAct.setWhatsThis(self.tr(
+            """<b>Session Manager</b>"""
+            """<p>Shows the session manager window.</p>"""
+        ))
+        if not self.__initShortcutsOnly:
+            self.showSessionsManagerAct.triggered.connect(
+                self.__showSessionManagerDialog)
+        self.__actions.append(self.showSessionsManagerAct)
+        
         self.virustotalScanCurrentAct = E5Action(
             self.tr("Scan current site"),
             UI.PixmapCache.getIcon("virustotal.png"),
@@ -1902,6 +1932,12 @@
         menu.addAction(self.openAct)
         menu.addAction(self.openTabAct)
         menu.addSeparator()
+        if not self.isPrivate():
+            sessionsMenu = menu.addMenu(self.tr("Sessions"))
+            sessionsMenu.aboutToShow.connect(
+                self.sessionManager().aboutToShowSessionsMenu)
+            menu.addAction(self.showSessionsManagerAct)
+            menu.addSeparator()
         if self.saveAsAct is not None:
             menu.addAction(self.saveAsAct)
         menu.addAction(self.savePageScreenAct)
@@ -2081,6 +2117,13 @@
         self.__superMenu.addAction(self.openTabAct)
         self.__superMenu.addSeparator()
         
+        if not self.isPrivate():
+            sessionsMenu = self.__superMenu.addMenu(self.tr("Sessions"))
+            sessionsMenu.aboutToShow.connect(
+                self.sessionManager().aboutToShowSessionsMenu)
+            self.__superMenu.addAction(self.showSessionsManagerAct)
+            self.__superMenu.addSeparator()
+        
         menu = self.__superMenu.addMenu(self.tr("Save"))
         if self.saveAsAct:
             menu.addAction(self.saveAsAct)
@@ -2378,12 +2421,14 @@
             return self.__tabWidget.newBrowser(link, background=background)
     
     @pyqtSlot()
-    def newWindow(self, link=None):
+    def newWindow(self, link=None, restoreSession=False):
         """
         Public slot called to open a new web browser window.
         
         @param link URL to be displayed in the new window
         @type str or QUrl
+        @param restoreSession flag indicating a restore session action
+        @type bool
         @return reference to the new window
         @rtype WebBrowserWindow
         """
@@ -2394,7 +2439,8 @@
         else:
             linkName = link
         h = WebBrowserWindow(linkName, ".", self.parent(), "webbrowser",
-                             self.__fromEric, private=self.isPrivate())
+                             self.__fromEric, private=self.isPrivate(),
+                             restoreSession=restoreSession)
         h.show()
         
         self.webBrowserWindowOpened.emit(h)
@@ -2688,6 +2734,13 @@
         """
         self.__searchWidget.showFind()
         
+    def forceClose(self):
+        """
+        Public method to force closing the window.
+        """
+        self.__forcedClose = True
+        self.close()
+    
     def closeEvent(self, e):
         """
         Protected event handler for the close event.
@@ -2710,7 +2763,7 @@
         
         @return flag indicating successful shutdown (boolean)
         """
-        if not WebBrowserWindow._performingShutdown:
+        if not WebBrowserWindow._performingShutdown and not self.__forcedClose:
             if not self.__tabWidget.shallShutDown():
                 return False
         
@@ -4723,3 +4776,9 @@
             cls._sessionManager = SessionManager()
         
         return cls._sessionManager
+    
+    def __showSessionManagerDialog(self):
+        """
+        Private slot to show the session manager dialog.
+        """
+        self.sessionManager().showSessionManagerDialog()

eric ide

mercurial