src/eric7/UI/UserInterface.py

branch
eric7
changeset 10828
fc1310995b98
parent 10823
13542803c1b1
child 10837
40cdaa4a847d
equal deleted inserted replaced
10827:54e6de23c546 10828:fc1310995b98
10 import contextlib 10 import contextlib
11 import datetime 11 import datetime
12 import enum 12 import enum
13 import functools 13 import functools
14 import getpass 14 import getpass
15 import glob
15 import json 16 import json
16 import logging 17 import logging
17 import os 18 import os
18 import pathlib 19 import pathlib
19 import shutil 20 import shutil
20 import sys 21 import sys
22
23 import psutil
21 24
22 from PyQt6 import sip 25 from PyQt6 import sip
23 from PyQt6.Qsci import QSCINTILLA_VERSION_STR 26 from PyQt6.Qsci import QSCINTILLA_VERSION_STR
24 from PyQt6.QtCore import ( 27 from PyQt6.QtCore import (
25 PYQT_VERSION_STR, 28 PYQT_VERSION_STR,
43 QKeySequence, 46 QKeySequence,
44 QSessionManager, 47 QSessionManager,
45 ) 48 )
46 from PyQt6.QtNetwork import QNetworkAccessManager, QNetworkProxyFactory 49 from PyQt6.QtNetwork import QNetworkAccessManager, QNetworkProxyFactory
47 from PyQt6.QtWidgets import ( 50 from PyQt6.QtWidgets import (
51 QAbstractItemView,
48 QApplication, 52 QApplication,
49 QDialog, 53 QDialog,
50 QDockWidget, 54 QDockWidget,
51 QLabel, 55 QLabel,
52 QMenu, 56 QMenu,
73 proxyAuthenticationRequired, 77 proxyAuthenticationRequired,
74 ) 78 )
75 from eric7.EricWidgets import EricErrorMessage, EricFileDialog, EricMessageBox 79 from eric7.EricWidgets import EricErrorMessage, EricFileDialog, EricMessageBox
76 from eric7.EricWidgets.EricApplication import ericApp 80 from eric7.EricWidgets.EricApplication import ericApp
77 from eric7.EricWidgets.EricClickableLabel import EricClickableLabel 81 from eric7.EricWidgets.EricClickableLabel import EricClickableLabel
82 from eric7.EricWidgets.EricListSelectionDialog import EricListSelectionDialog
78 from eric7.EricWidgets.EricMainWindow import EricMainWindow 83 from eric7.EricWidgets.EricMainWindow import EricMainWindow
79 from eric7.EricWidgets.EricSingleApplication import EricSingleApplicationServer 84 from eric7.EricWidgets.EricSingleApplication import EricSingleApplicationServer
80 from eric7.EricWidgets.EricToolBarManager import EricToolBarManager 85 from eric7.EricWidgets.EricToolBarManager import EricToolBarManager
81 from eric7.EricWidgets.EricZoomWidget import EricZoomWidget 86 from eric7.EricWidgets.EricZoomWidget import EricZoomWidget
82 from eric7.Globals import getConfig 87 from eric7.Globals import getConfig
1946 ) 1951 )
1947 ) 1952 )
1948 self.loadSessionAct.triggered.connect(self.__loadSessionFromFile) 1953 self.loadSessionAct.triggered.connect(self.__loadSessionFromFile)
1949 self.actions.append(self.loadSessionAct) 1954 self.actions.append(self.loadSessionAct)
1950 1955
1956 self.loadCrashSessionAct = EricAction(
1957 self.tr("Load crash session"),
1958 self.tr("Load crash session..."),
1959 0,
1960 0,
1961 self,
1962 "load_crash_session",
1963 )
1964 self.loadCrashSessionAct.setStatusTip(self.tr("Load crash session"))
1965 self.loadCrashSessionAct.setWhatsThis(
1966 self.tr(
1967 """<b>Load crash session...</b>"""
1968 """<p>This presents a list of available crash session files"""
1969 """ to select from and loads the selected one.</p>"""
1970 )
1971 )
1972 self.loadCrashSessionAct.triggered.connect(self.__loadCrashSession)
1973 self.actions.append(self.loadCrashSessionAct)
1974
1975 self.cleanCrashSessionsAct = EricAction(
1976 self.tr("Clean crash sessions"),
1977 self.tr("Clean crash sessions..."),
1978 0,
1979 0,
1980 self,
1981 "clean_crash_sessions",
1982 )
1983 self.cleanCrashSessionsAct.setStatusTip(self.tr("Clean crash sessions"))
1984 self.cleanCrashSessionsAct.setWhatsThis(
1985 self.tr(
1986 """<b>Clean crash sessions...</b>"""
1987 """<p>This asks for confirmation and deletes all stale crash session"""
1988 """ files.</p>"""
1989 )
1990 )
1991 self.cleanCrashSessionsAct.triggered.connect(self.__cleanCrashSessions)
1992 self.actions.append(self.cleanCrashSessionsAct)
1993
1951 self.newWindowAct = EricAction( 1994 self.newWindowAct = EricAction(
1952 self.tr("New Window"), 1995 self.tr("New Window"),
1953 EricPixmapCache.getIcon("newWindow"), 1996 EricPixmapCache.getIcon("newWindow"),
1954 self.tr("New &Window"), 1997 self.tr("New &Window"),
1955 QKeySequence(self.tr("Ctrl+Shift+N", "File|New Window")), 1998 QKeySequence(self.tr("Ctrl+Shift+N", "File|New Window")),
3817 ############################################################## 3860 ##############################################################
3818 3861
3819 self.__menus["server"] = self.__ericServerInterface.initMenu() 3862 self.__menus["server"] = self.__ericServerInterface.initMenu()
3820 3863
3821 ############################################################## 3864 ##############################################################
3865 ## Sessions menu
3866 ##############################################################
3867
3868 self.__menus["sessions"] = QMenu(self.tr("Sessions"))
3869 self.__menus["sessions"].addAction(self.saveSessionAct)
3870 self.__menus["sessions"].addAction(self.loadSessionAct)
3871 self.__menus["sessions"].addSeparator()
3872 self.__menus["sessions"].addAction(self.loadCrashSessionAct)
3873 self.__menus["sessions"].addAction(self.cleanCrashSessionsAct)
3874
3875 ##############################################################
3822 ## File menu 3876 ## File menu
3823 ############################################################## 3877 ##############################################################
3824 3878
3825 self.__menus["file"] = self.viewmanager.initFileMenu() 3879 self.__menus["file"] = self.viewmanager.initFileMenu()
3826 mb.addMenu(self.__menus["file"]) 3880 mb.addMenu(self.__menus["file"])
3827 self.__menus["file"].addSeparator() 3881 self.__menus["file"].addSeparator()
3828 self.__menus["file"].addAction(self.saveSessionAct) 3882 self.__menus["file"].addMenu(self.__menus["sessions"])
3829 self.__menus["file"].addAction(self.loadSessionAct)
3830 self.__menus["file"].addSeparator() 3883 self.__menus["file"].addSeparator()
3831 self.__menus["file"].addAction(self.restartAct) 3884 self.__menus["file"].addAction(self.restartAct)
3832 self.__menus["file"].addAction(self.exitAct) 3885 self.__menus["file"].addAction(self.exitAct)
3833 act = self.__menus["file"].actions()[0] 3886 act = self.__menus["file"].actions()[0]
3834 sep = self.__menus["file"].insertSeparator(act) 3887 sep = self.__menus["file"].insertSeparator(act)
7692 """ 7745 """
7693 fn = os.path.join(Globals.getConfigDir(), "eric7tasks.etj") 7746 fn = os.path.join(Globals.getConfigDir(), "eric7tasks.etj")
7694 if os.path.exists(fn): 7747 if os.path.exists(fn):
7695 self.__tasksFile.readFile(fn) 7748 self.__tasksFile.readFile(fn)
7696 7749
7697 def __writeSession(self, filename="", crashSession=False): 7750 def __writeSession(self, filename=""):
7698 """ 7751 """
7699 Private slot to write the session data to a JSON file (.esj). 7752 Private slot to write the session data to a JSON file (.esj).
7700 7753
7701 @param filename name of a session file to write 7754 @param filename name of a session file to write
7702 @type str 7755 @type str
7703 @param crashSession flag indicating to write a crash session file
7704 @type bool
7705 @return flag indicating success 7756 @return flag indicating success
7706 @rtype bool 7757 @rtype bool
7707 """ 7758 """
7708 if filename: 7759 fn = (
7709 fn = filename 7760 filename
7710 elif crashSession: 7761 if filename
7711 fn = os.path.join(Globals.getConfigDir(), "eric7_crash_session.esj") 7762 else os.path.join(Globals.getConfigDir(), "eric7session.esj")
7712 else: 7763 )
7713 fn = os.path.join(Globals.getConfigDir(), "eric7session.esj")
7714 7764
7715 return self.__sessionFile.writeFile(fn) 7765 return self.__sessionFile.writeFile(fn)
7716 7766
7717 def __readSession(self, filename=""): 7767 def __readSession(self, filename=""):
7718 """ 7768 """
7785 if not sessionFile: 7835 if not sessionFile:
7786 return 7836 return
7787 7837
7788 self.__readSession(filename=sessionFile) 7838 self.__readSession(filename=sessionFile)
7789 7839
7840 def __crashSessionFilePath(self, globPattern=False):
7841 """
7842 Private method to generate a path name for a unique crash session file.
7843
7844 @param globPattern flag indicating to get the glob pattern for crash
7845 session files (defaults to False)
7846 @type bool (optional)
7847 @return crash session file path
7848 @rtype str
7849 """
7850 if globPattern:
7851 return os.path.join(Globals.getConfigDir(), "eric7_crash_session_*.esj")
7852 else:
7853 return os.path.join(
7854 Globals.getConfigDir(), f"eric7_crash_session_{os.getpid()}.esj"
7855 )
7856
7857 def __getCrashedSessions(self):
7858 """
7859 Private method to get a list of crash session file paths of crashed sessions.
7860
7861 Note: Crashed sessions are those, whose PID does not exist anymore.
7862
7863 @return list of crashed session file paths
7864 @rtype list of str
7865 """
7866 crashedSessionsList = []
7867
7868 crashSessionPattern = self.__crashSessionFilePath(globPattern=True)
7869 crashSessionPatternParts = crashSessionPattern.split("*", 1)
7870 # crashSessionPatternParts is used to extract the PID from the crash session
7871 # file path
7872 crashSessionsList = glob.glob(crashSessionPattern)
7873 if crashSessionsList:
7874 for crashSession in crashSessionsList:
7875 pid = crashSession.replace(crashSessionPatternParts[0], "").replace(
7876 crashSessionPatternParts[1], ""
7877 )
7878 if not psutil.pid_exists(int(pid)):
7879 # it is a real crash session
7880 crashedSessionsList.append(crashSession)
7881
7882 return crashedSessionsList
7883
7884 def __checkCrashSessionExists(self):
7885 """
7886 Private method to check for the existence of crash session files and
7887 select the one to open.
7888
7889 @return file path of the crash session file to open. An empty string indicates
7890 that no crash session file should be opened or exists.
7891 @rtype str
7892 """
7893 selectedCrashSessionFile = ""
7894 crashedSessionsList = self.__getCrashedSessions()
7895 if crashedSessionsList:
7896 dlg = EricListSelectionDialog(
7897 sorted(crashedSessionsList),
7898 selectionMode=QAbstractItemView.SelectionMode.SingleSelection,
7899 title=self.tr("Found Crash Sessions"),
7900 message=self.tr(
7901 "These crash session files were found. Select the one to"
7902 " open. Select 'Cancel' to not open a crash session."
7903 ),
7904 doubleClickOk=True,
7905 parent=self,
7906 )
7907 if dlg.exec() == QDialog.DialogCode.Accepted:
7908 selectedCrashSessionFile = dlg.getSelection()[0]
7909
7910 return selectedCrashSessionFile
7911
7790 def __deleteCrashSession(self): 7912 def __deleteCrashSession(self):
7791 """ 7913 """
7792 Private slot to delete the crash session file. 7914 Private slot to delete the crash session file.
7793 """ 7915 """
7794 fn = os.path.join(Globals.getConfigDir(), "eric7_crash_session.esj") 7916 fn = self.__crashSessionFilePath()
7795 if os.path.exists(fn): 7917 if os.path.exists(fn):
7796 with contextlib.suppress(OSError): 7918 with contextlib.suppress(OSError):
7797 os.remove(fn) 7919 os.remove(fn)
7798 7920
7799 def __writeCrashSession(self): 7921 def __writeCrashSession(self):
7803 if ( 7925 if (
7804 not self.__readingSession 7926 not self.__readingSession
7805 and not self.__disableCrashSession 7927 and not self.__disableCrashSession
7806 and Preferences.getUI("CrashSessionEnabled") 7928 and Preferences.getUI("CrashSessionEnabled")
7807 ): 7929 ):
7808 self.__writeSession(crashSession=True) 7930 self.__writeSession(filename=self.__crashSessionFilePath())
7809 7931
7810 def __readCrashSession(self): 7932 def __readCrashSession(self):
7811 """ 7933 """
7812 Private method to check for and read a crash session. 7934 Private method to check for and read a crash session.
7813 7935
7818 if ( 7940 if (
7819 not self.__disableCrashSession 7941 not self.__disableCrashSession
7820 and not self.__noCrashOpenAtStartup 7942 and not self.__noCrashOpenAtStartup
7821 and Preferences.getUI("OpenCrashSessionOnStartup") 7943 and Preferences.getUI("OpenCrashSessionOnStartup")
7822 ): 7944 ):
7823 fn = os.path.join(Globals.getConfigDir(), "eric7_crash_session.esj") 7945 fn = self.__checkCrashSessionExists()
7824 if os.path.exists(fn): 7946 if fn:
7825 yes = EricMessageBox.yesNo( 7947 res = self.__readSession(filename=fn)
7826 self,
7827 self.tr("Crash Session found!"),
7828 self.tr(
7829 """A session file of a crashed session was"""
7830 """ found. Shall this session be restored?"""
7831 ),
7832 )
7833 if yes:
7834 res = self.__readSession(filename=fn)
7835 7948
7836 return res 7949 return res
7950
7951 @pyqtSlot()
7952 def __loadCrashSession(self):
7953 """
7954 Private slot to load a crash session.
7955 """
7956 fn = self.__checkCrashSessionExists()
7957 if fn:
7958 self.__readSession(filename=fn)
7959
7960 @pyqtSlot()
7961 def __cleanCrashSessions(self):
7962 """
7963 Private slot to clean all stale crash sessions.
7964 """
7965 from .DeleteFilesConfirmationDialog import DeleteFilesConfirmationDialog
7966
7967 crashedSessionsList = self.__getCrashedSessions()
7968 if crashedSessionsList:
7969 dlg = DeleteFilesConfirmationDialog(
7970 parent=self,
7971 caption=self.tr("Clean stale crash sessions"),
7972 message=self.tr(
7973 "Do you really want to delete these stale crash session files?"
7974 ),
7975 files=sorted(crashedSessionsList),
7976 )
7977 if dlg.exec() == QDialog.DialogCode.Accepted:
7978 for crashSession in crashedSessionsList:
7979 os.remove(crashSession)
7837 7980
7838 def showFindFileByNameDialog(self): 7981 def showFindFileByNameDialog(self):
7839 """ 7982 """
7840 Public slot to show the Find File by Name dialog. 7983 Public slot to show the Find File by Name dialog.
7841 """ 7984 """

eric ide

mercurial