Mon, 03 Jul 2017 19:23:54 +0200
Continued implementing session support for the new web browser.
--- a/Preferences/ConfigurationPages/WebBrowserPage.py Sun Jul 02 19:40:39 2017 +0200 +++ b/Preferences/ConfigurationPages/WebBrowserPage.py Mon Jul 03 19:23:54 2017 +0200 @@ -92,9 +92,16 @@ self.startupCombo.setCurrentIndex( Preferences.getWebBrowser("StartupBehavior")) + self.newTabCombo.setCurrentIndex( + Preferences.getWebBrowser("NewTabBehavior")) self.homePageEdit.setText( Preferences.getWebBrowser("HomePage")) + self.saveSessionCheckBox.setChecked( + Preferences.getWebBrowser("SessionAutoSave")) + self.sessionTimerSpinBox.setValue( + Preferences.getWebBrowser("SessionAutoSaveInterval")) + self.defaultSchemeCombo.setCurrentIndex( self.defaultSchemeCombo.findText( Preferences.getWebBrowser("DefaultScheme"))) @@ -243,10 +250,20 @@ "StartupBehavior", self.startupCombo.currentIndex()) Preferences.setWebBrowser( + "NewTabBehavior", + self.newTabCombo.currentIndex()) + Preferences.setWebBrowser( "HomePage", self.homePageEdit.text()) Preferences.setWebBrowser( + "SessionAutoSave", + self.saveSessionCheckBox.isChecked()) + Preferences.setWebBrowser( + "SessionAutoSaveInterval", + self.sessionTimerSpinBox.value()) + + Preferences.setWebBrowser( "DefaultScheme", self.defaultSchemeCombo.currentText())
--- a/Preferences/ConfigurationPages/WebBrowserPage.ui Sun Jul 02 19:40:39 2017 +0200 +++ b/Preferences/ConfigurationPages/WebBrowserPage.ui Mon Jul 03 19:23:54 2017 +0200 @@ -176,20 +176,49 @@ </widget> </item> <item row="1" column="0"> + <widget class="QLabel" name="label_12"> + <property name="text"> + <string>On new tab:</string> + </property> + </widget> + </item> + <item row="1" column="1" colspan="3"> + <widget class="QComboBox" name="newTabCombo"> + <property name="toolTip"> + <string>Select the behavior of new tabs</string> + </property> + <item> + <property name="text"> + <string>Show Empty Page</string> + </property> + </item> + <item> + <property name="text"> + <string>Show Home Page</string> + </property> + </item> + <item> + <property name="text"> + <string>Show Speed Dial</string> + </property> + </item> + </widget> + </item> + <item row="2" column="0"> <widget class="QLabel" name="homePageLabel"> <property name="text"> <string>Home Page:</string> </property> </widget> </item> - <item row="1" column="1" colspan="3"> + <item row="2" column="1" colspan="3"> <widget class="QLineEdit" name="homePageEdit"> <property name="toolTip"> <string>Enter the desired home page</string> </property> </widget> </item> - <item row="2" column="1"> + <item row="3" column="1"> <widget class="QPushButton" name="setCurrentPageButton"> <property name="toolTip"> <string>Press to set the current page as the home page</string> @@ -199,7 +228,7 @@ </property> </widget> </item> - <item row="2" column="2"> + <item row="3" column="2"> <widget class="QPushButton" name="defaultHomeButton"> <property name="toolTip"> <string>Press to set the default home page</string> @@ -209,7 +238,7 @@ </property> </widget> </item> - <item row="2" column="3"> + <item row="3" column="3"> <spacer name="horizontalSpacer_2"> <property name="orientation"> <enum>Qt::Horizontal</enum> @@ -223,6 +252,75 @@ </spacer> </item> </layout> + <zorder>label</zorder> + <zorder>startupCombo</zorder> + <zorder>homePageLabel</zorder> + <zorder>homePageEdit</zorder> + <zorder>setCurrentPageButton</zorder> + <zorder>defaultHomeButton</zorder> + <zorder>label_12</zorder> + <zorder>newTabCombo</zorder> + </widget> + </item> + <item> + <widget class="QGroupBox" name="groupBox_8"> + <property name="title"> + <string>Sessions</string> + </property> + <layout class="QGridLayout" name="gridLayout_6"> + <item row="0" column="0" colspan="3"> + <widget class="QCheckBox" name="saveSessionCheckBox"> + <property name="toolTip"> + <string>Select to save sessions automatically</string> + </property> + <property name="text"> + <string>Save sessions automatically</string> + </property> + </widget> + </item> + <item row="1" column="0"> + <widget class="QLabel" name="label_13"> + <property name="text"> + <string>Session Timer:</string> + </property> + </widget> + </item> + <item row="1" column="1"> + <widget class="QSpinBox" name="sessionTimerSpinBox"> + <property name="toolTip"> + <string>Enter the time to save sessions</string> + </property> + <property name="alignment"> + <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> + </property> + <property name="suffix"> + <string> s</string> + </property> + <property name="minimum"> + <number>10</number> + </property> + <property name="maximum"> + <number>180</number> + </property> + <property name="singleStep"> + <number>1</number> + </property> + </widget> + </item> + <item row="1" column="2"> + <spacer name="horizontalSpacer_8"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>443</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + </layout> </widget> </item> <item> @@ -823,9 +921,12 @@ <tabstop>screenCaptureCheckBox</tabstop> <tabstop>webGLCheckBox</tabstop> <tabstop>startupCombo</tabstop> + <tabstop>newTabCombo</tabstop> <tabstop>homePageEdit</tabstop> <tabstop>setCurrentPageButton</tabstop> <tabstop>defaultHomeButton</tabstop> + <tabstop>saveSessionCheckBox</tabstop> + <tabstop>sessionTimerSpinBox</tabstop> <tabstop>defaultSchemeCombo</tabstop> <tabstop>jsOpenWindowsCheckBox</tabstop> <tabstop>jsClipboardCheckBox</tabstop>
--- a/Preferences/__init__.py Sun Jul 02 19:40:39 2017 +0200 +++ b/Preferences/__init__.py Mon Jul 03 19:23:54 2017 +0200 @@ -1032,12 +1032,16 @@ "StatusBarVisible": True, "SaveGeometry": True, "WebBrowserState": QByteArray(), - "StartupBehavior": 2, # show speed dial + "StartupBehavior": 2, # show speed dial # 0 open empty page # 1 open home page # 2 open speed dial # 3 restore last session # 4 ask user for session + "NewTabBehavior": 2, # show speed dial + # 0 open empty page + # 1 open home page + # 2 open speed dial "HomePage": "eric:home", "WarnOnMultipleClose": True, "DefaultScheme": "https://", @@ -2879,7 +2883,7 @@ "MinimumFontSize", "MinimumLogicalFontSize", "DiskCacheSize", "AcceptCookies", "KeepCookiesUntil", "AdBlockUpdatePeriod", "TabManagerGroupByType", - "SessionAutoSaveInterval", + "SessionAutoSaveInterval", "NewTabBehavior", ]: return int(prefClass.settings.value( "WebBrowser/" + key, prefClass.webBrowserDefaults[key]))
--- a/WebBrowser/CookieJar/CookieJar.py Sun Jul 02 19:40:39 2017 +0200 +++ b/WebBrowser/CookieJar/CookieJar.py Mon Jul 03 19:23:54 2017 +0200 @@ -214,14 +214,16 @@ if self.__acceptCookies == self.AcceptOnlyFromSitesNavigatedTo: mainWindow = WebBrowserWindow.mainWindow() if mainWindow is not None: - url = mainWindow.getWindow().currentBrowser().url() - if url.isValid(): - host = url.host() - else: - host = "" - res = self.__matchDomain(cookieDomain, host) - if not res: - return True + browser = mainWindow.getWindow().currentBrowser() + if browser is not None: + url = browser.url() + if url.isValid(): + host = url.host() + else: + host = "" + res = self.__matchDomain(cookieDomain, host) + if not res: + return True if self.__filterTrackingCookies and cookie.name().startsWith(b"__utm"): return True
--- a/WebBrowser/Session/SessionManager.py Sun Jul 02 19:40:39 2017 +0200 +++ b/WebBrowser/Session/SessionManager.py Mon Jul 03 19:23:54 2017 +0200 @@ -15,7 +15,8 @@ from PyQt5.QtCore import pyqtSlot, pyqtSignal, Qt, QObject, QTimer, QDir, \ QFile, QFileInfo, QFileSystemWatcher, QByteArray, QDateTime from PyQt5.QtWidgets import QMenu, QAction, QActionGroup, QApplication, \ - QInputDialog, QLineEdit + QInputDialog, QLineEdit, QDialog, QDialogButtonBox, QLabel, QComboBox, \ + QVBoxLayout from E5Gui import E5MessageBox @@ -87,17 +88,24 @@ self.__backupSavedSession() - self.__autoSaveTimer = QTimer() - self.__autoSaveTimer.setSingleShot(True) - self.__autoSaveTimer.timeout.connect(self.__autoSaveSession) - self.__initSessionSaveTimer() + self.__autoSaveTimer = None + self.__shutdown = False + + def activateTimer(self): + """ + Public method to activate the session save timer. + """ + if self.__autoSaveTimer is None: + self.__autoSaveTimer = QTimer() + self.__autoSaveTimer.setSingleShot(True) + self.__autoSaveTimer.timeout.connect(self.__autoSaveSession) + self.__initSessionSaveTimer() def preferencesChanged(self): """ Public slot to react upon changes of the settings. """ self.__initSessionSaveTimer() - # TODO: implement this def getSessionsDirectory(self): """ @@ -132,6 +140,14 @@ Public method to perform any shutdown actions. """ self.__autoSaveTimer.stop() + if not self.__shutdown: + self.__autoSaveSession(startTimer=False) + self.__shutdown = True + + def autoSaveSession(self): + """ + Public method to save the current session state. + """ self.__autoSaveSession(startTimer=False) def __initSessionSaveTimer(self): @@ -176,6 +192,7 @@ sessionData = {"Windows": []} + activeWindow = WebBrowserWindow.getWindow() for window in WebBrowserWindow.mainWindows(): data = window.tabWidget().getSessionData() @@ -184,15 +201,20 @@ data["WindowGeometry"] = bytes(geometry.toBase64()).decode("ascii") sessionData["Windows"].append(data) + + if window is activeWindow: + sessionData["CurrentWindowIndex"] = \ + len(sessionData["Windows"]) -1 if sessionData["Windows"]: sessionFile = open(sessionFileName, "w") json.dump(sessionData, sessionFile, indent=2) sessionFile.close() - def __readSessionFromFile(self, sessionFileName): + @classmethod + def readSessionFromFile(cls, sessionFileName): """ - Private method to read the session data from a file. + Class method to read the session data from a file. @param sessionFileName file name of the session file @type str @@ -203,11 +225,34 @@ sessionFile = open(sessionFileName, "r") sessionData = json.load(sessionFile) sessionFile.close() + if not cls.isValidSession(sessionData): + sessionData = {} except (IOError, OSError): sessionData = {} return sessionData + @classmethod + def isValidSession(cls, session): + """ + Class method to check the validity of a session. + + @param session dictionary containing the session data + @type dict + @return flag indicating validity + @rtype bool + """ + if not session: + return False + + if "Windows" not in session: + return False + + if not session["Windows"]: + return False + + return True + def __backupSavedSession(self): """ Private method to backup the most recently saved session. @@ -264,7 +309,7 @@ ["*.json"], QDir.Files, QDir.Time) for sessionFileInfo in sessionFilesInfoList: - sessionData = self.__readSessionFromFile( + sessionData = self.readSessionFromFile( sessionFileInfo.absoluteFilePath()) if not sessionData or not sessionData["Windows"]: continue @@ -335,9 +380,9 @@ path = act.data() self.switchToSession(path) - def __openSession(self, sessionFilePath, flags=0): + def openSession(self, sessionFilePath, flags=0): """ - Private method to open a session from a given session file. + Public method to open a session from a given session file. @param sessionFilePath name of the session file to get session from @type str @@ -347,7 +392,7 @@ if self.__isActive(sessionFilePath): return - sessionData = self.__readSessionFromFile(sessionFilePath) + sessionData = self.readSessionFromFile(sessionFilePath) if not sessionData or not sessionData["Windows"]: return @@ -363,7 +408,7 @@ window = window.newWindow(restoreSession=True) # close all existing windows - for win in WebBrowserWindow.mainWindows(): + for win in WebBrowserWindow.mainWindows()[:]: if win is not window: win.forceClose() @@ -373,6 +418,21 @@ QFileInfo(sessionFilePath).canonicalFilePath() self.__sessionMetaData = [] + self.restoreSessionFromData(window, sessionData) + + @classmethod + def restoreSessionFromData(cls, window=None, sessionData=None): + """ + Class method to restore a session from a session data dictionary. + + @param window reference to main window to restore to + @type WebBrowserWindow + @param sessionData dictionary containing the session data + """ + from WebBrowser.WebBrowserWindow import WebBrowserWindow + if window is None: + window = WebBrowserWindow.mainWindow() + QApplication.setOverrideCursor(Qt.WaitCursor) # restore session for first window data = sessionData["Windows"].pop(0) @@ -381,6 +441,9 @@ geometry = QByteArray.fromBase64( data["WindowGeometry"].encode("ascii")) window.restoreGeometry(geometry) + if Utilities.isWindowsPlatform(): + window.hide() + window.show() QApplication.processEvents() # restore additional windows @@ -392,12 +455,25 @@ geometry = QByteArray.fromBase64( data["WindowGeometry"].encode("ascii")) window.restoreGeometry(geometry) + if Utilities.isWindowsPlatform(): + window.hide() + window.show() QApplication.processEvents() QApplication.restoreOverrideCursor() + + if "CurrentWindowIndex" in sessionData: + currentWindowIndex = sessionData["CurrentWindowIndex"] + try: + currentWindow = \ + WebBrowserWindow.mainWindows()[currentWindowIndex] + currentWindow.raise_() + except IndexError: + # ignore it + pass def renameSession(self, sessionFilePath, flags=0): """ - Public method to rename or clone a session + Public method to rename or clone a session. @param sessionFilePath name of the session file @type str @@ -493,6 +569,8 @@ @param sessionFilePath file name of the session file to replace with @type str + @return flag indicating success + @rtype bool """ from WebBrowser.WebBrowserWindow import WebBrowserWindow res = E5MessageBox.yesNo( @@ -501,7 +579,10 @@ self.tr("""Are you sure you want to replace the current""" """ session?""")) if res: - self.__openSession(sessionFilePath, SessionManager.ReplaceSession) + self.openSession(sessionFilePath, SessionManager.ReplaceSession) + return True + else: + return False def switchToSession(self, sessionFilePath): """ @@ -509,8 +590,11 @@ @param sessionFilePath file name of the session file to switch to @type str + @return flag indicating success + @rtype bool """ - self.__openSession(sessionFilePath, SessionManager.SwitchSession) + self.openSession(sessionFilePath, SessionManager.SwitchSession) + return True def cloneSession(self, sessionFilePath): """ @@ -526,7 +610,7 @@ Public method to delete a session. @param sessionFilePath file name of the session file to be deleted - @type str + @type str """ from WebBrowser.WebBrowserWindow import WebBrowserWindow res = E5MessageBox.yesNo( @@ -586,3 +670,53 @@ dlg = SessionManagerDialog(WebBrowserWindow.getWindow()) dlg.open() + + def selectSession(self): + """ + Public method to select a session to be restored. + + @return name of the session file to be restored + @rtype str + """ + from WebBrowser.WebBrowserWindow import WebBrowserWindow + + self.__fillMetaDataList() + + if self.__sessionMetaData: + # skip, if no session file available + dlg = QDialog(WebBrowserWindow.getWindow(), + Qt.WindowStaysOnTopHint) + lbl = QLabel(self.tr("Please select the startup session:")) + combo = QComboBox(dlg) + buttonBox = QDialogButtonBox( + QDialogButtonBox.Ok | QDialogButtonBox.Cancel, dlg) + buttonBox.accepted.connect(dlg.accept) + buttonBox.rejected.connect(dlg.reject) + + layout = QVBoxLayout() + layout.addWidget(lbl) + layout.addWidget(combo) + layout.addWidget(buttonBox) + dlg.setLayout(layout) + + lastActiveSessionFileInfo = QFileInfo(self.__lastActiveSession) + + for metaData in self.__sessionMetaData: + if QFileInfo(metaData.filePath) != lastActiveSessionFileInfo: + combo.addItem(metaData.name, metaData.filePath) + else: + combo.insertItem( + 0, + self.tr("{0} (last session)").format(metaData.name), + metaData.filePath + ) + combo.setCurrentIndex(0) + + if dlg.exec_() == QDialog.Accepted: + session = combo.currentData() + if session is None: + self.__lastActiveSession = self.__sessionDefault + else: + self.__lastActiveSession = session + + return self.__lastActiveSession
--- a/WebBrowser/Session/SessionManagerDialog.py Sun Jul 02 19:40:39 2017 +0200 +++ b/WebBrowser/Session/SessionManagerDialog.py Mon Jul 03 19:23:54 2017 +0200 @@ -7,6 +7,8 @@ Module implementing a dialog to manage sessions. """ +from __future__ import unicode_literals + from PyQt5.QtCore import pyqtSlot, Qt, QFileInfo from PyQt5.QtGui import QPalette from PyQt5.QtWidgets import QDialog, QTreeWidgetItem @@ -34,6 +36,7 @@ """ super(SessionManagerDialog, self).__init__(parent) self.setupUi(self) + self.setAttribute(Qt.WA_DeleteOnClose) self.newButton.clicked.connect(self.__newSession) self.renameButton.clicked.connect(self.__renameSession) @@ -214,6 +217,11 @@ filePath = itm.data(0, SessionManagerDialog.SessionFileRole) if filePath: if itm.data(0, SessionManagerDialog.BackupSessionRole): - WebBrowserWindow.sessionManager().replaceSession(filePath) + res = WebBrowserWindow.sessionManager()\ + .replaceSession(filePath) else: - WebBrowserWindow.sessionManager().switchToSession(filePath) + res = WebBrowserWindow.sessionManager()\ + .switchToSession(filePath) + + if res: + self.close()
--- a/WebBrowser/WebBrowserTabWidget.py Sun Jul 02 19:40:39 2017 +0200 +++ b/WebBrowser/WebBrowserTabWidget.py Mon Jul 03 19:23:54 2017 +0200 @@ -455,11 +455,15 @@ self.__closeButton.setEnabled(True) self.__navigationButton.setEnabled(True) - if not linkName and not restoreSession: - if Preferences.getWebBrowser("StartupBehavior") == 1: - linkName = Preferences.getWebBrowser("HomePage") - elif Preferences.getWebBrowser("StartupBehavior") == 2: - linkName = "eric:speeddial" + if not restoreSession: + if not linkName: + if Preferences.getWebBrowser("NewTabBehavior") == 1: + linkName = Preferences.getWebBrowser("HomePage") + elif Preferences.getWebBrowser("NewTabBehavior") == 2: + linkName = "eric:speeddial" + else: + if linkName in ["about:blank", "eric:blank"]: + linkName = "" if linkName: browser.setSource(QUrl(linkName))
--- a/WebBrowser/WebBrowserWindow.py Sun Jul 02 19:40:39 2017 +0200 +++ b/WebBrowser/WebBrowserWindow.py Mon Jul 03 19:23:54 2017 +0200 @@ -109,6 +109,7 @@ _tabManager = None _sessionManager = None + _performingStartup = True _performingShutdown = False _lastActiveWindow = None @@ -353,9 +354,36 @@ syncMgr.syncMessage.connect(self.statusBar().showMessage) syncMgr.syncError.connect(self.statusBar().showMessage) + restoreSessionData = {} + if WebBrowserWindow._performingStartup and not home: + startupBehavior = Preferences.getWebBrowser("StartupBehavior") + if not private and startupBehavior in [3, 4]: + if startupBehavior == 3: + # restore last session + restoreSessionFile = \ + self.sessionManager().lastActiveSessionFile() + elif startupBehavior == 4: + # select session + restoreSessionFile = \ + self.sessionManager().selectSession() + sessionData = \ + self.sessionManager().readSessionFromFile( + restoreSessionFile) + if self.sessionManager().isValidSession(sessionData): + restoreSessionData = sessionData + restoreSession = True + else: + if Preferences.getWebBrowser("StartupBehavior") == 0: + home = "eric:blank" + elif Preferences.getWebBrowser("StartupBehavior") == 1: + home = Preferences.getWebBrowser("HomePage") + elif Preferences.getWebBrowser("StartupBehavior") == 2: + home = "eric:speeddial" + if not restoreSession: self.__tabWidget.newBrowser(home) self.__tabWidget.currentBrowser().setFocus() + WebBrowserWindow._performingStartup = False self.__imagesIcon = ImagesIcon(self) self.statusBar().addPermanentWidget(self.__imagesIcon) @@ -443,7 +471,12 @@ self.__hideNavigationTimer.timeout.connect(self.__hideNavigation) self.__forcedClose = False - self.sessionManager() + + if restoreSessionData: + self.sessionManager().restoreSessionFromData( + self, restoreSessionData) + + self.sessionManager().activateTimer() QTimer.singleShot(0, syncMgr.loadSettings) @@ -2767,6 +2800,13 @@ if not self.__tabWidget.shallShutDown(): return False + if not self.__fromEric: + if not WebBrowserWindow._performingShutdown and \ + len(WebBrowserWindow.BrowserWindows) == 1: + # shut down the session manager in case the last window is + # about to be closed + self.sessionManager().shutdown() + self.__bookmarksToolBar.setModel(None) self.__virusTotal.close()