31 pyqtSlot, |
31 pyqtSlot, |
32 ) |
32 ) |
33 from PyQt6.QtGui import QAction, QKeySequence |
33 from PyQt6.QtGui import QAction, QKeySequence |
34 from PyQt6.QtWidgets import QDialog, QInputDialog, QLineEdit, QMenu, QToolBar |
34 from PyQt6.QtWidgets import QDialog, QInputDialog, QLineEdit, QMenu, QToolBar |
35 |
35 |
36 from eric7 import Globals, Preferences, Utilities |
36 from eric7 import Preferences, Utilities |
37 from eric7.CodeFormatting.BlackFormattingAction import BlackFormattingAction |
37 from eric7.CodeFormatting.BlackFormattingAction import BlackFormattingAction |
38 from eric7.CodeFormatting.BlackUtilities import aboutBlack |
38 from eric7.CodeFormatting.BlackUtilities import aboutBlack |
39 from eric7.CodeFormatting.IsortFormattingAction import IsortFormattingAction |
39 from eric7.CodeFormatting.IsortFormattingAction import IsortFormattingAction |
40 from eric7.CodeFormatting.IsortUtilities import aboutIsort |
40 from eric7.CodeFormatting.IsortUtilities import aboutIsort |
41 from eric7.EricGui import EricPixmapCache |
41 from eric7.EricGui import EricPixmapCache |
50 from eric7.EricXML.SessionReader import SessionReader |
50 from eric7.EricXML.SessionReader import SessionReader |
51 from eric7.EricXML.TasksReader import TasksReader |
51 from eric7.EricXML.TasksReader import TasksReader |
52 from eric7.EricXML.UserProjectReader import UserProjectReader |
52 from eric7.EricXML.UserProjectReader import UserProjectReader |
53 from eric7.Globals import recentNameProject |
53 from eric7.Globals import recentNameProject |
54 from eric7.Sessions.SessionFile import SessionFile |
54 from eric7.Sessions.SessionFile import SessionFile |
|
55 from eric7.SystemUtilities import ( |
|
56 FileSystemUtilities, |
|
57 OSUtilities, |
|
58 PythonUtilities, |
|
59 QtUtilities, |
|
60 ) |
55 from eric7.Tasks.TasksFile import TasksFile |
61 from eric7.Tasks.TasksFile import TasksFile |
56 from eric7.UI import Config |
62 from eric7.UI import Config |
57 from eric7.UI.NotificationWidget import NotificationTypes |
63 from eric7.UI.NotificationWidget import NotificationTypes |
58 |
64 |
59 from .DebuggerPropertiesFile import DebuggerPropertiesFile |
65 from .DebuggerPropertiesFile import DebuggerPropertiesFile |
345 "MicroPython": ["Console", "Other"], |
351 "MicroPython": ["Console", "Other"], |
346 "Ruby": ["Console", "Other"], |
352 "Ruby": ["Console", "Other"], |
347 "JavaScript": ["Other"], |
353 "JavaScript": ["Other"], |
348 } |
354 } |
349 |
355 |
350 if Utilities.checkPyside(variant=2): |
356 if QtUtilities.checkPyside(variant=2): |
351 self.__projectTypes["PySide2"] = self.tr("PySide2 GUI") |
357 self.__projectTypes["PySide2"] = self.tr("PySide2 GUI") |
352 self.__projectTypes["PySide2C"] = self.tr("PySide2 Console") |
358 self.__projectTypes["PySide2C"] = self.tr("PySide2 Console") |
353 self.__projectProgLanguages["Python3"].extend(["PySide2", "PySide2C"]) |
359 self.__projectProgLanguages["Python3"].extend(["PySide2", "PySide2C"]) |
354 |
360 |
355 if Utilities.checkPyside(variant=6): |
361 if QtUtilities.checkPyside(variant=6): |
356 self.__projectTypes["PySide6"] = self.tr("PySide6 GUI") |
362 self.__projectTypes["PySide6"] = self.tr("PySide6 GUI") |
357 self.__projectTypes["PySide6C"] = self.tr("PySide6 Console") |
363 self.__projectTypes["PySide6C"] = self.tr("PySide6 Console") |
358 self.__projectProgLanguages["Python3"].extend(["PySide6", "PySide6C"]) |
364 self.__projectProgLanguages["Python3"].extend(["PySide6", "PySide6C"]) |
359 |
365 |
360 def getProjectTypes(self, progLanguage=""): |
366 def getProjectTypes(self, progLanguage=""): |
1894 if dlg.exec() == QDialog.DialogCode.Accepted: |
1900 if dlg.exec() == QDialog.DialogCode.Accepted: |
1895 fnames, target, isSource = dlg.getData() |
1901 fnames, target, isSource = dlg.getData() |
1896 if target != "": |
1902 if target != "": |
1897 for fn in fnames: |
1903 for fn in fnames: |
1898 targetfile = os.path.join(target, os.path.basename(fn)) |
1904 targetfile = os.path.join(target, os.path.basename(fn)) |
1899 if not Utilities.samepath(os.path.dirname(fn), target): |
1905 if not FileSystemUtilities.samepath(os.path.dirname(fn), target): |
1900 try: |
1906 try: |
1901 if not os.path.isdir(target): |
1907 if not os.path.isdir(target): |
1902 os.makedirs(target) |
1908 os.makedirs(target) |
1903 |
1909 |
1904 if os.path.exists(targetfile): |
1910 if os.path.exists(targetfile): |
1989 for pattern in ignorePatterns: |
1997 for pattern in ignorePatterns: |
1990 if fnmatch.fnmatch(file, pattern): |
1998 if fnmatch.fnmatch(file, pattern): |
1991 continue |
1999 continue |
1992 |
2000 |
1993 targetfile = os.path.join(target, os.path.basename(file)) |
2001 targetfile = os.path.join(target, os.path.basename(file)) |
1994 if not Utilities.samepath(target, source): |
2002 if not FileSystemUtilities.samepath(target, source): |
1995 try: |
2003 try: |
1996 if os.path.exists(targetfile): |
2004 if os.path.exists(targetfile): |
1997 res = EricMessageBox.yesNo( |
2005 res = EricMessageBox.yesNo( |
1998 self.ui, |
2006 self.ui, |
1999 self.tr("Add directory"), |
2007 self.tr("Add directory"), |
2147 "", |
2155 "", |
2148 EricFileDialog.DontConfirmOverwrite, |
2156 EricFileDialog.DontConfirmOverwrite, |
2149 ) |
2157 ) |
2150 if not newfn: |
2158 if not newfn: |
2151 return False |
2159 return False |
2152 newfn = Utilities.toNativeSeparators(newfn) |
2160 newfn = FileSystemUtilities.toNativeSeparators(newfn) |
2153 |
2161 |
2154 if os.path.exists(newfn): |
2162 if os.path.exists(newfn): |
2155 res = EricMessageBox.yesNo( |
2163 res = EricMessageBox.yesNo( |
2156 self.ui, |
2164 self.ui, |
2157 self.tr("Rename File"), |
2165 self.tr("Rename File"), |
2828 |
2836 |
2829 with EricOverrideCursor(): |
2837 with EricOverrideCursor(): |
2830 # search the project directory for files with known extensions |
2838 # search the project directory for files with known extensions |
2831 filespecs = list(self.__pdata["FILETYPES"].keys()) |
2839 filespecs = list(self.__pdata["FILETYPES"].keys()) |
2832 for filespec in filespecs: |
2840 for filespec in filespecs: |
2833 files = Utilities.direntries(self.ppath, True, filespec) |
2841 files = FileSystemUtilities.direntries(self.ppath, True, filespec) |
2834 for file in files: |
2842 for file in files: |
2835 self.appendFile(file) |
2843 self.appendFile(file) |
2836 |
2844 |
2837 # special handling for translation files |
2845 # special handling for translation files |
2838 if self.translationsRoot: |
2846 if self.translationsRoot: |
2848 pattern = pattern.replace("%language%", "*") |
2856 pattern = pattern.replace("%language%", "*") |
2849 else: |
2857 else: |
2850 tpd = self.__pdata["TRANSLATIONPATTERN"].split("%language%")[0] |
2858 tpd = self.__pdata["TRANSLATIONPATTERN"].split("%language%")[0] |
2851 else: |
2859 else: |
2852 pattern = "*.ts" |
2860 pattern = "*.ts" |
2853 tslist.extend(Utilities.direntries(tpd, True, pattern)) |
2861 tslist.extend(FileSystemUtilities.direntries(tpd, True, pattern)) |
2854 pattern = self.__binaryTranslationFile(pattern) |
2862 pattern = self.__binaryTranslationFile(pattern) |
2855 if pattern: |
2863 if pattern: |
2856 tslist.extend(Utilities.direntries(tpd, True, pattern)) |
2864 tslist.extend(FileSystemUtilities.direntries(tpd, True, pattern)) |
2857 if tslist: |
2865 if tslist: |
2858 if "_" in os.path.basename(tslist[0]): |
2866 if "_" in os.path.basename(tslist[0]): |
2859 # the first entry determines the mainscript name |
2867 # the first entry determines the mainscript name |
2860 mainscriptname = ( |
2868 mainscriptname = ( |
2861 os.path.splitext(mainscript)[0] |
2869 os.path.splitext(mainscript)[0] |
2900 ) |
2908 ) |
2901 pattern = os.path.basename( |
2909 pattern = os.path.basename( |
2902 self.__pdata["TRANSLATIONPATTERN"] |
2910 self.__pdata["TRANSLATIONPATTERN"] |
2903 ).replace("%language%", "*") |
2911 ).replace("%language%", "*") |
2904 pattern = self.__binaryTranslationFile(pattern) |
2912 pattern = self.__binaryTranslationFile(pattern) |
2905 qmlist = Utilities.direntries(tpd, True, pattern) |
2913 qmlist = FileSystemUtilities.direntries(tpd, True, pattern) |
2906 for qm in qmlist: |
2914 for qm in qmlist: |
2907 self.__pdata["TRANSLATIONS"].append(qm) |
2915 self.__pdata["TRANSLATIONS"].append(qm) |
2908 self.projectFileAdded.emit(qm, "TRANSLATIONS") |
2916 self.projectFileAdded.emit(qm, "TRANSLATIONS") |
2909 if not self.__pdata["MAINSCRIPT"] and bool(mainscriptname): |
2917 if not self.__pdata["MAINSCRIPT"] and bool(mainscriptname): |
2910 if self.__pdata["PROGLANGUAGE"] in ["Python3", "MicroPython"]: |
2918 if self.__pdata["PROGLANGUAGE"] in ["Python3", "MicroPython"]: |
3114 |
3122 |
3115 if fn is None: |
3123 if fn is None: |
3116 fn = EricFileDialog.getOpenFileName( |
3124 fn = EricFileDialog.getOpenFileName( |
3117 self.parent(), |
3125 self.parent(), |
3118 self.tr("Open project"), |
3126 self.tr("Open project"), |
3119 Preferences.getMultiProject("Workspace") or Utilities.getHomeDir(), |
3127 Preferences.getMultiProject("Workspace") or OSUtilities.getHomeDir(), |
3120 self.tr("Project Files (*.epj);;XML Project Files (*.e4p)"), |
3128 self.tr("Project Files (*.epj);;XML Project Files (*.e4p)"), |
3121 ) |
3129 ) |
3122 |
3130 |
3123 if fn and self.closeProject(): |
3131 if fn and self.closeProject(): |
3124 with EricOverrideCursor(): |
3132 with EricOverrideCursor(): |
3310 """ |
3318 """ |
3311 defaultFilter = self.tr("Project Files (*.epj)") |
3319 defaultFilter = self.tr("Project Files (*.epj)") |
3312 defaultPath = ( |
3320 defaultPath = ( |
3313 self.ppath |
3321 self.ppath |
3314 if self.ppath |
3322 if self.ppath |
3315 else (Preferences.getMultiProject("Workspace") or Utilities.getHomeDir()) |
3323 else (Preferences.getMultiProject("Workspace") or OSUtilities.getHomeDir()) |
3316 ) |
3324 ) |
3317 fn, selectedFilter = EricFileDialog.getSaveFileNameAndFilter( |
3325 fn, selectedFilter = EricFileDialog.getSaveFileNameAndFilter( |
3318 self.parent(), |
3326 self.parent(), |
3319 self.tr("Save Project"), |
3327 self.tr("Save Project"), |
3320 defaultPath, |
3328 defaultPath, |
3748 @return flag indicating that the path starts with the project path |
3756 @return flag indicating that the path starts with the project path |
3749 @rtype bool |
3757 @rtype bool |
3750 """ |
3758 """ |
3751 return bool(self.ppath) and ( |
3759 return bool(self.ppath) and ( |
3752 path == self.ppath |
3760 path == self.ppath |
3753 or Utilities.normcasepath(Utilities.toNativeSeparators(path)).startswith( |
3761 or FileSystemUtilities.normcasepath( |
3754 Utilities.normcasepath(Utilities.toNativeSeparators(self.ppath + "/")) |
3762 FileSystemUtilities.toNativeSeparators(path) |
|
3763 ).startswith( |
|
3764 FileSystemUtilities.normcasepath( |
|
3765 FileSystemUtilities.toNativeSeparators(self.ppath + "/") |
|
3766 ) |
3755 ) |
3767 ) |
3756 ) |
3768 ) |
3757 |
3769 |
3758 def getProjectFile(self): |
3770 def getProjectFile(self): |
3759 """ |
3771 """ |
3825 |
3837 |
3826 @param path file or directory name to convert (string) |
3838 @param path file or directory name to convert (string) |
3827 @return project relative path or unchanged path, if path doesn't |
3839 @return project relative path or unchanged path, if path doesn't |
3828 belong to the project (string) |
3840 belong to the project (string) |
3829 """ |
3841 """ |
3830 return Utilities.fromNativeSeparators(self.getRelativePath(path)) |
3842 return FileSystemUtilities.fromNativeSeparators(self.getRelativePath(path)) |
3831 |
3843 |
3832 def getAbsolutePath(self, fn): |
3844 def getAbsolutePath(self, fn): |
3833 """ |
3845 """ |
3834 Public method to convert a project relative file path to an absolute |
3846 Public method to convert a project relative file path to an absolute |
3835 file path. |
3847 file path. |
3848 |
3860 |
3849 @param fn file or directory name to convert (string) |
3861 @param fn file or directory name to convert (string) |
3850 @return absolute path (string) |
3862 @return absolute path (string) |
3851 """ |
3863 """ |
3852 if not os.path.isabs(fn): |
3864 if not os.path.isabs(fn): |
3853 fn = os.path.join(self.ppath, Utilities.toNativeSeparators(fn)) |
3865 fn = os.path.join(self.ppath, FileSystemUtilities.toNativeSeparators(fn)) |
3854 return fn |
3866 return fn |
3855 |
3867 |
3856 def getEolString(self): |
3868 def getEolString(self): |
3857 """ |
3869 """ |
3858 Public method to get the EOL-string to be used by the project. |
3870 Public method to get the EOL-string to be used by the project. |
3965 ericApp() |
3977 ericApp() |
3966 .getObject("VirtualEnvManager") |
3978 .getObject("VirtualEnvManager") |
3967 .getVirtualenvInterpreter(venvName) |
3979 .getVirtualenvInterpreter(venvName) |
3968 ) |
3980 ) |
3969 if not interpreter and resolveGlobal: |
3981 if not interpreter and resolveGlobal: |
3970 interpreter = Globals.getPythonExecutable() |
3982 interpreter = PythonUtilities.getPythonExecutable() |
3971 |
3983 |
3972 return interpreter |
3984 return interpreter |
3973 |
3985 |
3974 def getProjectExecPath(self): |
3986 def getProjectExecPath(self): |
3975 """ |
3987 """ |
4060 group == "OTHERS" |
4072 group == "OTHERS" |
4061 and any(newfn.startswith(entry) for entry in self.__pdata[group]) |
4073 and any(newfn.startswith(entry) for entry in self.__pdata[group]) |
4062 ): |
4074 ): |
4063 return True |
4075 return True |
4064 |
4076 |
4065 if Utilities.isWindowsPlatform(): |
4077 if OSUtilities.isWindowsPlatform(): |
4066 # try the above case-insensitive |
4078 # try the above case-insensitive |
4067 newfn = newfn.lower() |
4079 newfn = newfn.lower() |
4068 if any(entry.lower() == newfn for entry in self.__pdata[group]): |
4080 if any(entry.lower() == newfn for entry in self.__pdata[group]): |
4069 return True |
4081 return True |
4070 |
4082 |
5388 """ |
5400 """ |
5389 Private method to synchronize the list of recently opened projects |
5401 Private method to synchronize the list of recently opened projects |
5390 with the central store. |
5402 with the central store. |
5391 """ |
5403 """ |
5392 for recent in self.recent[:]: |
5404 for recent in self.recent[:]: |
5393 if Utilities.samepath(self.pfile, recent): |
5405 if FileSystemUtilities.samepath(self.pfile, recent): |
5394 self.recent.remove(recent) |
5406 self.recent.remove(recent) |
5395 self.recent.insert(0, self.pfile) |
5407 self.recent.insert(0, self.pfile) |
5396 maxRecent = Preferences.getProject("RecentNumber") |
5408 maxRecent = Preferences.getProject("RecentNumber") |
5397 if len(self.recent) > maxRecent: |
5409 if len(self.recent) > maxRecent: |
5398 self.recent = self.recent[:maxRecent] |
5410 self.recent = self.recent[:maxRecent] |
5408 |
5420 |
5409 for idx, rp in enumerate(self.recent, start=1): |
5421 for idx, rp in enumerate(self.recent, start=1): |
5410 formatStr = "&{0:d}. {1}" if idx < 10 else "{0:d}. {1}" |
5422 formatStr = "&{0:d}. {1}" if idx < 10 else "{0:d}. {1}" |
5411 act = self.recentMenu.addAction( |
5423 act = self.recentMenu.addAction( |
5412 formatStr.format( |
5424 formatStr.format( |
5413 idx, Utilities.compactPath(rp, self.ui.maxMenuFilePathLen) |
5425 idx, FileSystemUtilities.compactPath(rp, self.ui.maxMenuFilePathLen) |
5414 ) |
5426 ) |
5415 ) |
5427 ) |
5416 act.setData(rp) |
5428 act.setData(rp) |
5417 act.setEnabled(pathlib.Path(rp).exists()) |
5429 act.setEnabled(pathlib.Path(rp).exists()) |
5418 |
5430 |
5518 for ns in newSources: |
5530 for ns in newSources: |
5519 # ignore hidden files and directories |
5531 # ignore hidden files and directories |
5520 if ns.startswith("."): |
5532 if ns.startswith("."): |
5521 continue |
5533 continue |
5522 if ( |
5534 if ( |
5523 Utilities.isWindowsPlatform() |
5535 OSUtilities.isWindowsPlatform() |
5524 and os.path.isdir(os.path.join(curpath, ns)) |
5536 and os.path.isdir(os.path.join(curpath, ns)) |
5525 and ns.startswith("_") |
5537 and ns.startswith("_") |
5526 ): |
5538 ): |
5527 # dot net hack |
5539 # dot net hack |
5528 continue |
5540 continue |
6161 try: |
6175 try: |
6162 newline = None if self.__pdata["EOL"] == 0 else self.getEolString() |
6176 newline = None if self.__pdata["EOL"] == 0 else self.getEolString() |
6163 with open(pkglist, "w", encoding="utf-8", newline=newline) as pkglistFile: |
6177 with open(pkglist, "w", encoding="utf-8", newline=newline) as pkglistFile: |
6164 pkglistFile.write("\n".join(header) + "\n") |
6178 pkglistFile.write("\n".join(header) + "\n") |
6165 pkglistFile.write( |
6179 pkglistFile.write( |
6166 "\n".join([Utilities.fromNativeSeparators(f) for f in lst]) |
6180 "\n".join( |
|
6181 [FileSystemUtilities.fromNativeSeparators(f) for f in lst] |
|
6182 ) |
6167 ) |
6183 ) |
6168 pkglistFile.write("\n") |
6184 pkglistFile.write("\n") |
6169 # ensure the file ends with an empty line |
6185 # ensure the file ends with an empty line |
6170 except OSError as why: |
6186 except OSError as why: |
6171 EricMessageBox.critical( |
6187 EricMessageBox.critical( |