WebBrowser/Session/SessionManager.py

changeset 5783
44a9f08de394
parent 5782
60874802161b
child 5785
7c7c5f9e4fad
equal deleted inserted replaced
5782:60874802161b 5783:44a9f08de394
13 import json 13 import json
14 14
15 from PyQt5.QtCore import pyqtSlot, pyqtSignal, Qt, QObject, QTimer, QDir, \ 15 from PyQt5.QtCore import pyqtSlot, pyqtSignal, Qt, QObject, QTimer, QDir, \
16 QFile, QFileInfo, QFileSystemWatcher, QByteArray, QDateTime 16 QFile, QFileInfo, QFileSystemWatcher, QByteArray, QDateTime
17 from PyQt5.QtWidgets import QMenu, QAction, QActionGroup, QApplication, \ 17 from PyQt5.QtWidgets import QMenu, QAction, QActionGroup, QApplication, \
18 QInputDialog, QLineEdit 18 QInputDialog, QLineEdit, QDialog, QDialogButtonBox, QLabel, QComboBox, \
19 QVBoxLayout
19 20
20 from E5Gui import E5MessageBox 21 from E5Gui import E5MessageBox
21 22
22 import Utilities 23 import Utilities
23 import Preferences 24 import Preferences
85 self.__sessionsDirectoryWatcher.directoryChanged.connect( 86 self.__sessionsDirectoryWatcher.directoryChanged.connect(
86 self.__sessionDirectoryChanged) 87 self.__sessionDirectoryChanged)
87 88
88 self.__backupSavedSession() 89 self.__backupSavedSession()
89 90
90 self.__autoSaveTimer = QTimer() 91 self.__autoSaveTimer = None
91 self.__autoSaveTimer.setSingleShot(True) 92 self.__shutdown = False
92 self.__autoSaveTimer.timeout.connect(self.__autoSaveSession) 93
94 def activateTimer(self):
95 """
96 Public method to activate the session save timer.
97 """
98 if self.__autoSaveTimer is None:
99 self.__autoSaveTimer = QTimer()
100 self.__autoSaveTimer.setSingleShot(True)
101 self.__autoSaveTimer.timeout.connect(self.__autoSaveSession)
102 self.__initSessionSaveTimer()
103
104 def preferencesChanged(self):
105 """
106 Public slot to react upon changes of the settings.
107 """
93 self.__initSessionSaveTimer() 108 self.__initSessionSaveTimer()
94
95 def preferencesChanged(self):
96 """
97 Public slot to react upon changes of the settings.
98 """
99 self.__initSessionSaveTimer()
100 # TODO: implement this
101 109
102 def getSessionsDirectory(self): 110 def getSessionsDirectory(self):
103 """ 111 """
104 Public method to get the directory sessions are stored in. 112 Public method to get the directory sessions are stored in.
105 113
130 def shutdown(self): 138 def shutdown(self):
131 """ 139 """
132 Public method to perform any shutdown actions. 140 Public method to perform any shutdown actions.
133 """ 141 """
134 self.__autoSaveTimer.stop() 142 self.__autoSaveTimer.stop()
143 if not self.__shutdown:
144 self.__autoSaveSession(startTimer=False)
145 self.__shutdown = True
146
147 def autoSaveSession(self):
148 """
149 Public method to save the current session state.
150 """
135 self.__autoSaveSession(startTimer=False) 151 self.__autoSaveSession(startTimer=False)
136 152
137 def __initSessionSaveTimer(self): 153 def __initSessionSaveTimer(self):
138 """ 154 """
139 Private slot to initialize the auto save timer. 155 Private slot to initialize the auto save timer.
174 """ 190 """
175 from WebBrowser.WebBrowserWindow import WebBrowserWindow 191 from WebBrowser.WebBrowserWindow import WebBrowserWindow
176 192
177 sessionData = {"Windows": []} 193 sessionData = {"Windows": []}
178 194
195 activeWindow = WebBrowserWindow.getWindow()
179 for window in WebBrowserWindow.mainWindows(): 196 for window in WebBrowserWindow.mainWindows():
180 data = window.tabWidget().getSessionData() 197 data = window.tabWidget().getSessionData()
181 198
182 # add window geometry 199 # add window geometry
183 geometry = window.saveGeometry() 200 geometry = window.saveGeometry()
184 data["WindowGeometry"] = bytes(geometry.toBase64()).decode("ascii") 201 data["WindowGeometry"] = bytes(geometry.toBase64()).decode("ascii")
185 202
186 sessionData["Windows"].append(data) 203 sessionData["Windows"].append(data)
204
205 if window is activeWindow:
206 sessionData["CurrentWindowIndex"] = \
207 len(sessionData["Windows"]) -1
187 208
188 if sessionData["Windows"]: 209 if sessionData["Windows"]:
189 sessionFile = open(sessionFileName, "w") 210 sessionFile = open(sessionFileName, "w")
190 json.dump(sessionData, sessionFile, indent=2) 211 json.dump(sessionData, sessionFile, indent=2)
191 sessionFile.close() 212 sessionFile.close()
192 213
193 def __readSessionFromFile(self, sessionFileName): 214 @classmethod
194 """ 215 def readSessionFromFile(cls, sessionFileName):
195 Private method to read the session data from a file. 216 """
217 Class method to read the session data from a file.
196 218
197 @param sessionFileName file name of the session file 219 @param sessionFileName file name of the session file
198 @type str 220 @type str
199 @return dictionary containing the session data 221 @return dictionary containing the session data
200 @rtype dict 222 @rtype dict
201 """ 223 """
202 try: 224 try:
203 sessionFile = open(sessionFileName, "r") 225 sessionFile = open(sessionFileName, "r")
204 sessionData = json.load(sessionFile) 226 sessionData = json.load(sessionFile)
205 sessionFile.close() 227 sessionFile.close()
228 if not cls.isValidSession(sessionData):
229 sessionData = {}
206 except (IOError, OSError): 230 except (IOError, OSError):
207 sessionData = {} 231 sessionData = {}
208 232
209 return sessionData 233 return sessionData
234
235 @classmethod
236 def isValidSession(cls, session):
237 """
238 Class method to check the validity of a session.
239
240 @param session dictionary containing the session data
241 @type dict
242 @return flag indicating validity
243 @rtype bool
244 """
245 if not session:
246 return False
247
248 if "Windows" not in session:
249 return False
250
251 if not session["Windows"]:
252 return False
253
254 return True
210 255
211 def __backupSavedSession(self): 256 def __backupSavedSession(self):
212 """ 257 """
213 Private method to backup the most recently saved session. 258 Private method to backup the most recently saved session.
214 """ 259 """
262 307
263 sessionFilesInfoList = QDir(self.getSessionsDirectory()).entryInfoList( 308 sessionFilesInfoList = QDir(self.getSessionsDirectory()).entryInfoList(
264 ["*.json"], QDir.Files, QDir.Time) 309 ["*.json"], QDir.Files, QDir.Time)
265 310
266 for sessionFileInfo in sessionFilesInfoList: 311 for sessionFileInfo in sessionFilesInfoList:
267 sessionData = self.__readSessionFromFile( 312 sessionData = self.readSessionFromFile(
268 sessionFileInfo.absoluteFilePath()) 313 sessionFileInfo.absoluteFilePath())
269 if not sessionData or not sessionData["Windows"]: 314 if not sessionData or not sessionData["Windows"]:
270 continue 315 continue
271 316
272 data = SessionMetaData() 317 data = SessionMetaData()
333 act = self.sender() 378 act = self.sender()
334 if isinstance(act, QAction): 379 if isinstance(act, QAction):
335 path = act.data() 380 path = act.data()
336 self.switchToSession(path) 381 self.switchToSession(path)
337 382
338 def __openSession(self, sessionFilePath, flags=0): 383 def openSession(self, sessionFilePath, flags=0):
339 """ 384 """
340 Private method to open a session from a given session file. 385 Public method to open a session from a given session file.
341 386
342 @param sessionFilePath name of the session file to get session from 387 @param sessionFilePath name of the session file to get session from
343 @type str 388 @type str
344 @param flags flags determining the open mode 389 @param flags flags determining the open mode
345 @type int 390 @type int
346 """ 391 """
347 if self.__isActive(sessionFilePath): 392 if self.__isActive(sessionFilePath):
348 return 393 return
349 394
350 sessionData = self.__readSessionFromFile(sessionFilePath) 395 sessionData = self.readSessionFromFile(sessionFilePath)
351 if not sessionData or not sessionData["Windows"]: 396 if not sessionData or not sessionData["Windows"]:
352 return 397 return
353 398
354 from WebBrowser.WebBrowserWindow import WebBrowserWindow 399 from WebBrowser.WebBrowserWindow import WebBrowserWindow
355 window = WebBrowserWindow.mainWindow() 400 window = WebBrowserWindow.mainWindow()
361 406
362 # create new window for the new session 407 # create new window for the new session
363 window = window.newWindow(restoreSession=True) 408 window = window.newWindow(restoreSession=True)
364 409
365 # close all existing windows 410 # close all existing windows
366 for win in WebBrowserWindow.mainWindows(): 411 for win in WebBrowserWindow.mainWindows()[:]:
367 if win is not window: 412 if win is not window:
368 win.forceClose() 413 win.forceClose()
369 414
370 if not ((flags & SessionManager.ReplaceSession) == 415 if not ((flags & SessionManager.ReplaceSession) ==
371 SessionManager.ReplaceSession): 416 SessionManager.ReplaceSession):
372 self.__lastActiveSession = \ 417 self.__lastActiveSession = \
373 QFileInfo(sessionFilePath).canonicalFilePath() 418 QFileInfo(sessionFilePath).canonicalFilePath()
374 self.__sessionMetaData = [] 419 self.__sessionMetaData = []
420
421 self.restoreSessionFromData(window, sessionData)
422
423 @classmethod
424 def restoreSessionFromData(cls, window=None, sessionData=None):
425 """
426 Class method to restore a session from a session data dictionary.
427
428 @param window reference to main window to restore to
429 @type WebBrowserWindow
430 @param sessionData dictionary containing the session data
431 """
432 from WebBrowser.WebBrowserWindow import WebBrowserWindow
433 if window is None:
434 window = WebBrowserWindow.mainWindow()
375 435
376 QApplication.setOverrideCursor(Qt.WaitCursor) 436 QApplication.setOverrideCursor(Qt.WaitCursor)
377 # restore session for first window 437 # restore session for first window
378 data = sessionData["Windows"].pop(0) 438 data = sessionData["Windows"].pop(0)
379 window.tabWidget().loadFromSessionData(data) 439 window.tabWidget().loadFromSessionData(data)
380 if "WindowGeometry" in data: 440 if "WindowGeometry" in data:
381 geometry = QByteArray.fromBase64( 441 geometry = QByteArray.fromBase64(
382 data["WindowGeometry"].encode("ascii")) 442 data["WindowGeometry"].encode("ascii"))
383 window.restoreGeometry(geometry) 443 window.restoreGeometry(geometry)
444 if Utilities.isWindowsPlatform():
445 window.hide()
446 window.show()
384 QApplication.processEvents() 447 QApplication.processEvents()
385 448
386 # restore additional windows 449 # restore additional windows
387 for data in sessionData["Windows"]: 450 for data in sessionData["Windows"]:
388 window = WebBrowserWindow.mainWindow()\ 451 window = WebBrowserWindow.mainWindow()\
390 window.tabWidget().loadFromSessionData(data) 453 window.tabWidget().loadFromSessionData(data)
391 if "WindowGeometry" in data: 454 if "WindowGeometry" in data:
392 geometry = QByteArray.fromBase64( 455 geometry = QByteArray.fromBase64(
393 data["WindowGeometry"].encode("ascii")) 456 data["WindowGeometry"].encode("ascii"))
394 window.restoreGeometry(geometry) 457 window.restoreGeometry(geometry)
458 if Utilities.isWindowsPlatform():
459 window.hide()
460 window.show()
395 QApplication.processEvents() 461 QApplication.processEvents()
396 QApplication.restoreOverrideCursor() 462 QApplication.restoreOverrideCursor()
463
464 if "CurrentWindowIndex" in sessionData:
465 currentWindowIndex = sessionData["CurrentWindowIndex"]
466 try:
467 currentWindow = \
468 WebBrowserWindow.mainWindows()[currentWindowIndex]
469 currentWindow.raise_()
470 except IndexError:
471 # ignore it
472 pass
397 473
398 def renameSession(self, sessionFilePath, flags=0): 474 def renameSession(self, sessionFilePath, flags=0):
399 """ 475 """
400 Public method to rename or clone a session 476 Public method to rename or clone a session.
401 477
402 @param sessionFilePath name of the session file 478 @param sessionFilePath name of the session file
403 @type str 479 @type str
404 @param flags flags determining a rename or clone operation 480 @param flags flags determining a rename or clone operation
405 @type int 481 @type int
491 """ 567 """
492 Public method to replace the current session with the given one. 568 Public method to replace the current session with the given one.
493 569
494 @param sessionFilePath file name of the session file to replace with 570 @param sessionFilePath file name of the session file to replace with
495 @type str 571 @type str
572 @return flag indicating success
573 @rtype bool
496 """ 574 """
497 from WebBrowser.WebBrowserWindow import WebBrowserWindow 575 from WebBrowser.WebBrowserWindow import WebBrowserWindow
498 res = E5MessageBox.yesNo( 576 res = E5MessageBox.yesNo(
499 WebBrowserWindow.getWindow(), 577 WebBrowserWindow.getWindow(),
500 self.tr("Restore Backup"), 578 self.tr("Restore Backup"),
501 self.tr("""Are you sure you want to replace the current""" 579 self.tr("""Are you sure you want to replace the current"""
502 """ session?""")) 580 """ session?"""))
503 if res: 581 if res:
504 self.__openSession(sessionFilePath, SessionManager.ReplaceSession) 582 self.openSession(sessionFilePath, SessionManager.ReplaceSession)
583 return True
584 else:
585 return False
505 586
506 def switchToSession(self, sessionFilePath): 587 def switchToSession(self, sessionFilePath):
507 """ 588 """
508 Public method to switch the current session to the given one. 589 Public method to switch the current session to the given one.
509 590
510 @param sessionFilePath file name of the session file to switch to 591 @param sessionFilePath file name of the session file to switch to
511 @type str 592 @type str
512 """ 593 @return flag indicating success
513 self.__openSession(sessionFilePath, SessionManager.SwitchSession) 594 @rtype bool
595 """
596 self.openSession(sessionFilePath, SessionManager.SwitchSession)
597 return True
514 598
515 def cloneSession(self, sessionFilePath): 599 def cloneSession(self, sessionFilePath):
516 """ 600 """
517 Public method to clone a session. 601 Public method to clone a session.
518 602
524 def deleteSession(self, sessionFilePath): 608 def deleteSession(self, sessionFilePath):
525 """ 609 """
526 Public method to delete a session. 610 Public method to delete a session.
527 611
528 @param sessionFilePath file name of the session file to be deleted 612 @param sessionFilePath file name of the session file to be deleted
529 @type str 613 @type str
530 """ 614 """
531 from WebBrowser.WebBrowserWindow import WebBrowserWindow 615 from WebBrowser.WebBrowserWindow import WebBrowserWindow
532 res = E5MessageBox.yesNo( 616 res = E5MessageBox.yesNo(
533 WebBrowserWindow.getWindow(), 617 WebBrowserWindow.getWindow(),
534 self.tr("Delete Session"), 618 self.tr("Delete Session"),
584 from WebBrowser.WebBrowserWindow import WebBrowserWindow 668 from WebBrowser.WebBrowserWindow import WebBrowserWindow
585 from .SessionManagerDialog import SessionManagerDialog 669 from .SessionManagerDialog import SessionManagerDialog
586 670
587 dlg = SessionManagerDialog(WebBrowserWindow.getWindow()) 671 dlg = SessionManagerDialog(WebBrowserWindow.getWindow())
588 dlg.open() 672 dlg.open()
673
674 def selectSession(self):
675 """
676 Public method to select a session to be restored.
677
678 @return name of the session file to be restored
679 @rtype str
680 """
681 from WebBrowser.WebBrowserWindow import WebBrowserWindow
682
683 self.__fillMetaDataList()
684
685 if self.__sessionMetaData:
686 # skip, if no session file available
687 dlg = QDialog(WebBrowserWindow.getWindow(),
688 Qt.WindowStaysOnTopHint)
689 lbl = QLabel(self.tr("Please select the startup session:"))
690 combo = QComboBox(dlg)
691 buttonBox = QDialogButtonBox(
692 QDialogButtonBox.Ok | QDialogButtonBox.Cancel, dlg)
693 buttonBox.accepted.connect(dlg.accept)
694 buttonBox.rejected.connect(dlg.reject)
695
696 layout = QVBoxLayout()
697 layout.addWidget(lbl)
698 layout.addWidget(combo)
699 layout.addWidget(buttonBox)
700 dlg.setLayout(layout)
701
702 lastActiveSessionFileInfo = QFileInfo(self.__lastActiveSession)
703
704 for metaData in self.__sessionMetaData:
705 if QFileInfo(metaData.filePath) != lastActiveSessionFileInfo:
706 combo.addItem(metaData.name, metaData.filePath)
707 else:
708 combo.insertItem(
709 0,
710 self.tr("{0} (last session)").format(metaData.name),
711 metaData.filePath
712 )
713 combo.setCurrentIndex(0)
714
715 if dlg.exec_() == QDialog.Accepted:
716 session = combo.currentData()
717 if session is None:
718 self.__lastActiveSession = self.__sessionDefault
719 else:
720 self.__lastActiveSession = session
721
722 return self.__lastActiveSession

eric ide

mercurial