Fri, 30 Jun 2017 19:58:09 +0200
Continued implementing session support for the new web browser.
--- a/Preferences/__init__.py Fri Jun 30 19:48:32 2017 +0200 +++ b/Preferences/__init__.py Fri Jun 30 19:58:09 2017 +0200 @@ -1106,6 +1106,7 @@ # Sessions "SessionAutoSave": True, "SessionAutoSaveInterval": 15, # interval in seconds + "SessionLastActivePath": "", } if QWebEngineSettings: webBrowserDefaults["HelpViewerType"] = 1 # eric browser
--- a/WebBrowser/Session/SessionManager.py Fri Jun 30 19:48:32 2017 +0200 +++ b/WebBrowser/Session/SessionManager.py Fri Jun 30 19:58:09 2017 +0200 @@ -12,16 +12,41 @@ import os import json -from PyQt5.QtCore import pyqtSlot, QObject, QTimer, QDir +from PyQt5.QtCore import pyqtSlot, pyqtSignal, QObject, QTimer, QDir, QFile, \ + QFileInfo, QFileSystemWatcher import Utilities import Preferences +class SessionMetaData(object): + """ + Class implementing a data structure to store meta data for a session. + """ + def __init__(self): + """ + Constructor + """ + self.name = "" + self.filePath = "" + self.isActive = False + self.isDefault = False + self.isBackup = False + + class SessionManager(QObject): """ Class implementing the session manager. + + @signal sessionsMetaDataChanged() emitted to indicate a change of the + list of session meta data """ + sessionsMetaDataChanged = pyqtSignal() + + SwitchSession = 1 + CloneSession = 2 + ReplaceSession = SwitchSession | 4 + def __init__(self, parent=None): """ Constructor @@ -31,9 +56,31 @@ """ super(SessionManager, self).__init__(parent) - sessionsDir = QDir(self.getSessionsDirectory()) + sessionsDirName = self.getSessionsDirectory() + sessionsDir = QDir(sessionsDirName) if not sessionsDir.exists(): - sessionsDir.mkpath(self.getSessionsDirectory()) + sessionsDir.mkpath(sessionsDirName) + + self.__sessionMetaData = [] + # list containing meta data about saved sessions + + self.__sessionDefault = os.path.join(sessionsDirName, "session.json") + self.__sessionBackup1 = os.path.join(sessionsDirName, + "session.json.old") + self.__sessionBackup2 = os.path.join(sessionsDirName, + "session.json.old1") + + self.__lastActiveSession = Preferences.getWebBrowser( + "SessionLastActivePath") + if not QFile.exists(self.__lastActiveSession): + self.__lastActiveSession = self.__sessionDefault + + self.__sessionsDirectoryWatcher = \ + QFileSystemWatcher([self.getSessionsDirectory()], self) + self.__sessionsDirectoryWatcher.directoryChanged.connect( + self.__sessionDirectoryChanged) + + self.__backupSavedSession() self.__autoSaveTimer = QTimer() self.__autoSaveTimer.setSingleShot(True) @@ -64,7 +111,23 @@ @return name of the default session file @rtype str """ - return os.path.join(self.getSessionsDirectory(), "session.json") + return self.__sessionDefault + + def lastActiveSessionFile(self): + """ + Public method to get the name of the last active session file. + + @return name of the last active session file + @rtype str + """ + return self.__lastActiveSession + + def shutdown(self): + """ + Public method to perform any shutdown actions. + """ + self.__autoSaveTimer.stop() + self.__autoSaveSession(startTimer=False) def __initSessionSaveTimer(self): """ @@ -80,16 +143,22 @@ self.__autoSaveTimer.stop() @pyqtSlot() - def __autoSaveSession(self): + def __autoSaveSession(self, startTimer=True): """ Private slot to save the current session state. + + @param startTimer flag indicating to restart the timer + @type bool """ from WebBrowser.WebBrowserWindow import WebBrowserWindow if not WebBrowserWindow.isPrivate(): - self.writeCurrentSession(self.defaultSessionFile()) + Preferences.setWebBrowser("SessionLastActivePath", + self.__lastActiveSession) + self.writeCurrentSession(self.__lastActiveSession) - self.__autoSaveTimer.start(self.__autoSaveInterval) + if startTimer: + self.__autoSaveTimer.start(self.__autoSaveInterval) def writeCurrentSession(self, sessionFileName): """ @@ -110,7 +179,133 @@ data["WindowGeometry"] = bytes(geometry.toBase64()).decode("ascii") sessionData["Windows"].append(data) + else: + return sessionFile = open(sessionFileName, "w") json.dump(sessionData, sessionFile, indent=2) sessionFile.close() + + def __backupSavedSession(self): + """ + Private method to backup the most recently saved session. + """ + if QFile.exists(self.__lastActiveSession): + + if QFile.exists(self.__sessionBackup1): + QFile.remove(self.__sessionBackup2) + QFile.copy(self.__sessionBackup1, self.__sessionBackup2) + + QFile.remove(self.__sessionBackup1) + QFile.copy(self.__lastActiveSession, self.__sessionBackup1) + + def sessionMetaData(self, includeBackups=False): + """ + Public method to get the sessions meta data. + + @param includeBackups flag indicating to include backup sessions + @type bool + @return list of session meta data + @rtype list of SessionMetaData + """ + self.__fillMetaDataList() + + metaDataList = self.__sessionMetaData[:] + + if includeBackups and QFile.exists(self.__sessionBackup1): + data = SessionMetaData() + data.name = self.tr("Backup 1") + data.filePath = self.__sessionBackup1 + data.isBackup = True + metaDataList.append(data) + + if includeBackups and QFile.exists(self.__sessionBackup2): + data = SessionMetaData() + data.name = self.tr("Backup 2") + data.filePath = self.__sessionBackup2 + data.isBackup = True + metaDataList.append(data) + + return metaDataList + + def __fillMetaDataList(self): + """ + Private method to fill the sessions meta data list. + + The sessions meta data list is only populated, if the variable holding + it is empty (i.e. it is populated on demand). + """ + if self.__sessionMetaData: + return + + sessionFilesInfoList = QDir(self.getSessionsDirectory()).entryInfoList( + QDir.Files, QDir.Time) + for sessionFileInfo in sessionFilesInfoList: + data = SessionMetaData() + data.name = sessionFileInfo.baseName() + data.filePath = sessionFileInfo.canonicalFilePath() + + if sessionFileInfo == QFileInfo(self.defaultSessionFile()): + data.name = self.tr("Default Session") + data.isDefault = True + + if self.__isActive(sessionFileInfo): + data.isActive = True + + self.__sessionMetaData.append(data) + + def __isActive(self, filePath): + """ + Private method to check, if a given file is the active one. + + @param filePath path of the session file to be checked + @type str or QFileInfo + @return flag indicating the active file + @rtype bool + """ + return QFileInfo(filePath) == QFileInfo(self.__lastActiveSession) + + @pyqtSlot() + def __sessionDirectoryChanged(self): + """ + Private slot handling changes of the sessions directory. + """ + self.__sessionMetaData = [] + + self.sessionsMetaDataChanged.emit() + + def openSession(self, sessionFilePath="", flags=None): + # TODO: implement this + pass + + def renameSession(self, sessionFilePath="", flags=None): + # TODO: implement this + pass + + def saveSession(self): + # TODO: implement this + pass + + def __replaceSession(self, sessionFilePath): + # TODO: implement this + pass + + def __switchToSession(self, sessionFilePath): + # TODO: implement this + pass + + def __cloneSession(self, sessionFilePath): + # TODO: implement this + pass + + def __deleteSession(self, sessionFilePath): + # TODO: implement this + pass + + def __newSession(self): + # TODO: implement this + pass + + def openSessionManagerDialog(self): + # TODO: implement this + pass
--- a/WebBrowser/WebBrowserWindow.py Fri Jun 30 19:48:32 2017 +0200 +++ b/WebBrowser/WebBrowserWindow.py Fri Jun 30 19:58:09 2017 +0200 @@ -109,6 +109,8 @@ _tabManager = None _sessionManager = None + _performingShutdown = False + def __init__(self, home, path, parent, name, fromEric=False, initShortcutsOnly=False, searchWord=None, private=False, qthelp=False, settingsDir=""): @@ -410,8 +412,6 @@ self.__virusTotal.fileScanReport.connect( self.__virusTotalFileScanReport) - self.__shutdownCalled = False - self.flashCookieManager() if WebBrowserWindow._useQtHelp: @@ -889,7 +889,7 @@ if self.__fromEric: self.exitAct.triggered.connect(self.close) else: - self.exitAct.triggered.connect(self.__closeAllWindows) + self.exitAct.triggered.connect(self.shutdown) self.__actions.append(self.exitAct) self.backAct = E5Action( @@ -2688,15 +2688,6 @@ """ self.__searchWidget.showFind() - def __closeAllWindows(self): - """ - Private slot to close all windows. - """ - for browser in WebBrowserWindow.BrowserWindows: - if browser != self: - browser.close() - self.close() - def closeEvent(self, e): """ Protected event handler for the close event. @@ -2705,62 +2696,30 @@ <br />This event is simply accepted after the history has been saved and all window references have been deleted. """ - if not self.__shutdownCalled: - res = self.shutdown() - - if res: - e.accept() - self.webBrowserWindowClosed.emit(self) - else: - e.ignore() + res = self.__shutdownWindow() + + if res: + e.accept() + self.webBrowserWindowClosed.emit(self) else: - e.accept() + e.ignore() - def shutdown(self): - """ - Public method to shut down the web browser. + def __shutdownWindow(self): + """ + Private method to shut down a web browser window. @return flag indicating successful shutdown (boolean) """ - if not self.__tabWidget.shallShutDown(): - return False - - if not self.downloadManager().allowQuit(): - return False - - self.downloadManager().shutdown() - - self.cookieJar().close() + if not WebBrowserWindow._performingShutdown: + if not self.__tabWidget.shallShutDown(): + return False self.__bookmarksToolBar.setModel(None) - self.bookmarksManager().close() - - self.historyManager().close() - - self.passwordManager().close() - - self.adBlockManager().close() - - self.userAgentsManager().close() - - self.speedDial().close() - - self.syncManager().close() - - ZoomManager.instance().close() - - WebIconProvider.instance().close() self.__virusTotal.close() - self.flashCookieManager().shutdown() - self.__navigationBar.searchEdit().openSearchManager().close() - if len(WebBrowserWindow.BrowserWindows) == 1: - # it is the last window - self.tabManager().close() - if WebBrowserWindow._useQtHelp: self.__searchEngine.cancelIndexing() self.__searchEngine.cancelSearching() @@ -2789,12 +2748,105 @@ except ValueError: pass - self.networkManager().shutdown() - if not self.__fromEric: Preferences.syncPreferences() - - self.__shutdownCalled = True + if not WebBrowserWindow._performingShutdown and \ + len(WebBrowserWindow.BrowserWindows) == 0: + # shut down the browser in case the last window was + # simply closed + self.shutdown() + + return True + + def __shallShutDown(self): + """ + Private method to check, if the application should be shut down. + + @return flag indicating a shut down + @rtype bool + """ + if Preferences.getWebBrowser("WarnOnMultipleClose"): + windowCount = len(WebBrowserWindow.BrowserWindows) + tabCount = 0 + for browser in WebBrowserWindow.BrowserWindows: + tabCount += browser.tabWidget().count() + + if windowCount > 1 or tabCount > 1: + mb = E5MessageBox.E5MessageBox( + E5MessageBox.Information, + self.tr("Are you sure you want to close the web browser?"), + self.tr("""Are you sure you want to close the web""" + """ browser?\n""" + """You have {0} windows with {1} tabs open.""") + .format(windowCount, tabCount), + modal=True, + parent=self) + if self.fromEric: + quitButton = mb.addButton( + self.tr("&Close"), E5MessageBox.AcceptRole) + quitButton.setIcon(UI.PixmapCache.getIcon("close.png")) + else: + quitButton = mb.addButton( + self.tr("&Quit"), E5MessageBox.AcceptRole) + quitButton.setIcon(UI.PixmapCache.getIcon("exit.png")) + mb.addButton(E5MessageBox.Cancel) + mb.exec_() + return mb.clickedButton() == quitButton + + return True + + def shutdown(self): + """ + Public method to shut down the web browser. + + @return flag indicating successful shutdown (boolean) + """ + if not self.__shallShutDown(): + return False + + if not self.downloadManager().allowQuit(): + return False + + WebBrowserWindow._performingShutdown = True + + self.sessionManager().shutdown() + + self.downloadManager().shutdown() + + self.cookieJar().close() + + self.bookmarksManager().close() + + self.historyManager().close() + + self.passwordManager().close() + + self.adBlockManager().close() + + self.userAgentsManager().close() + + self.speedDial().close() + + self.syncManager().close() + + ZoomManager.instance().close() + + WebIconProvider.instance().close() + + self.flashCookieManager().shutdown() + + if len(WebBrowserWindow.BrowserWindows) == 1: + # it is the last window + self.tabManager().close() + + self.networkManager().shutdown() + + + for browser in WebBrowserWindow.BrowserWindows: + if browser != self: + browser.close() + self.close() + return True def __backward(self):