src/eric7/Project/Project.py

branch
eric7-maintenance
changeset 9549
67295777d9fe
parent 9442
906485dcd210
parent 9533
e017c0df9ef1
child 9551
40e2dd39e687
equal deleted inserted replaced
9451:24c847222774 9549:67295777d9fe
5 5
6 """ 6 """
7 Module implementing the project management functionality. 7 Module implementing the project management functionality.
8 """ 8 """
9 9
10 import collections
10 import contextlib 11 import contextlib
11 import copy 12 import copy
12 import fnmatch 13 import fnmatch
13 import glob 14 import glob
14 import json 15 import json
16 import pathlib 17 import pathlib
17 import shutil 18 import shutil
18 import time 19 import time
19 import zipfile 20 import zipfile
20 21
22 from PyQt6.Qsci import QsciScintilla
21 from PyQt6.QtCore import ( 23 from PyQt6.QtCore import (
22 pyqtSlot, 24 QByteArray,
25 QCryptographicHash,
23 QFile, 26 QFile,
24 pyqtSignal,
25 QCryptographicHash,
26 QIODevice, 27 QIODevice,
27 QByteArray,
28 QObject, 28 QObject,
29 QProcess, 29 QProcess,
30 pyqtSignal,
31 pyqtSlot,
30 ) 32 )
31 from PyQt6.QtGui import QKeySequence, QAction 33 from PyQt6.QtGui import QAction, QKeySequence
32 from PyQt6.QtWidgets import QLineEdit, QToolBar, QDialog, QInputDialog, QMenu 34 from PyQt6.QtWidgets import QDialog, QInputDialog, QLineEdit, QMenu, QToolBar
33 from PyQt6.Qsci import QsciScintilla 35
34 36 from eric7 import Globals, Preferences, Utilities
37 from eric7.CodeFormatting.BlackFormattingAction import BlackFormattingAction
38 from eric7.CodeFormatting.BlackUtilities import aboutBlack
39 from eric7.CodeFormatting.IsortFormattingAction import IsortFormattingAction
40 from eric7.CodeFormatting.IsortUtilities import aboutIsort
41 from eric7.EricGui import EricPixmapCache
42 from eric7.EricGui.EricAction import EricAction, createActionGroup
43 from eric7.EricGui.EricOverrideCursor import EricOverrideCursor, EricOverridenCursor
44 from eric7.EricWidgets import EricFileDialog, EricMessageBox
35 from eric7.EricWidgets.EricApplication import ericApp 45 from eric7.EricWidgets.EricApplication import ericApp
36 from eric7.EricWidgets import EricFileDialog, EricMessageBox
37 from eric7.EricWidgets.EricListSelectionDialog import EricListSelectionDialog 46 from eric7.EricWidgets.EricListSelectionDialog import EricListSelectionDialog
38 from eric7.EricWidgets.EricProgressDialog import EricProgressDialog 47 from eric7.EricWidgets.EricProgressDialog import EricProgressDialog
39 from eric7.EricGui.EricOverrideCursor import EricOverrideCursor, EricOverridenCursor 48 from eric7.EricXML.DebuggerPropertiesReader import DebuggerPropertiesReader
40 49 from eric7.EricXML.ProjectReader import ProjectReader
50 from eric7.EricXML.SessionReader import SessionReader
51 from eric7.EricXML.TasksReader import TasksReader
52 from eric7.EricXML.UserProjectReader import UserProjectReader
41 from eric7.Globals import recentNameProject 53 from eric7.Globals import recentNameProject
42 54 from eric7.Sessions.SessionFile import SessionFile
43 from eric7.EricGui import EricPixmapCache 55 from eric7.Tasks.TasksFile import TasksFile
44 from eric7.UI import Config 56 from eric7.UI import Config
45 from eric7.UI.NotificationWidget import NotificationTypes 57 from eric7.UI.NotificationWidget import NotificationTypes
46 58
47 from eric7.EricGui.EricAction import EricAction, createActionGroup 59 from .DebuggerPropertiesFile import DebuggerPropertiesFile
48 60 from .FileCategoryRepositoryItem import FileCategoryRepositoryItem
49 from eric7 import Globals, Preferences, Utilities 61 from .ProjectBrowserModel import ProjectBrowserModel
50
51 from .ProjectFile import ProjectFile 62 from .ProjectFile import ProjectFile
52 from .UserProjectFile import UserProjectFile 63 from .UserProjectFile import UserProjectFile
53 from .DebuggerPropertiesFile import DebuggerPropertiesFile
54
55 from eric7.Sessions.SessionFile import SessionFile
56
57 from eric7.Tasks.TasksFile import TasksFile
58
59 from eric7.CodeFormatting.BlackFormattingAction import BlackFormattingAction
60 from eric7.CodeFormatting.BlackUtilities import aboutBlack
61 64
62 65
63 class Project(QObject): 66 class Project(QObject):
64 """ 67 """
65 Class implementing the project management functionality. 68 Class implementing the project management functionality.
66 69
67 @signal dirty(bool) emitted when the dirty state changes 70 @signal dirty(bool) emitted when the dirty state changes
68 @signal projectLanguageAdded(str) emitted after a new language was added 71 @signal projectFileAdded(str, str) emitted after a new file was added
72 @signal projectFileRemoved(str, str) emitted after a file of the project was removed
73 @signal projectFileCompiled(str, str) emitted after a form was compiled
69 @signal projectLanguageAddedByCode(str) emitted after a new language was 74 @signal projectLanguageAddedByCode(str) emitted after a new language was
70 added. The language code is sent by this signal. 75 added. The language code is sent by this signal.
71 @signal projectLanguageRemoved(str) emitted after a language was removed
72 @signal projectFormAdded(str) emitted after a new form was added
73 @signal projectFormRemoved(str) emitted after a form was removed
74 @signal projectFormCompiled(str) emitted after a form was compiled
75 @signal projectSourceAdded(str) emitted after a new source file was added
76 @signal projectSourceRemoved(str) emitted after a source was removed
77 @signal projectInterfaceAdded(str) emitted after a new IDL file was added
78 @signal projectInterfaceRemoved(str) emitted after a IDL file was removed
79 @signal projectProtocolAdded(str) emitted after a new proto file was added
80 @signal projectProtocolRemoved(str) emitted after a proto file was removed
81 @signal projectResourceAdded(str) emitted after a new resource file was
82 added
83 @signal projectResourceRemoved(str) emitted after a resource was removed
84 @signal projectOthersAdded(str) emitted after a file or directory was added
85 to the OTHERS project data area
86 @signal projectOthersRemoved(str) emitted after a file was removed from the
87 OTHERS project data area
88 @signal projectAboutToBeCreated() emitted just before the project will be 76 @signal projectAboutToBeCreated() emitted just before the project will be
89 created 77 created
90 @signal newProjectHooks() emitted after a new project was generated but 78 @signal newProjectHooks() emitted after a new project was generated but
91 before the newProject() signal is sent 79 before the newProject() signal is sent
92 @signal newProject() emitted after a new project was generated 80 @signal newProject() emitted after a new project was generated
127 @signal projectChanged() emitted to signal a change of the project 115 @signal projectChanged() emitted to signal a change of the project
128 @signal appendStdout(str) emitted after something was received from 116 @signal appendStdout(str) emitted after something was received from
129 a QProcess on stdout 117 a QProcess on stdout
130 @signal appendStderr(str) emitted after something was received from 118 @signal appendStderr(str) emitted after something was received from
131 a QProcess on stderr 119 a QProcess on stderr
120 @signal processChangedProjectFiles() emitted to indicate, that changed project files
121 should be processed
132 """ 122 """
133 123
134 dirty = pyqtSignal(bool) 124 dirty = pyqtSignal(bool)
135 projectLanguageAdded = pyqtSignal(str) 125 projectFileAdded = pyqtSignal(str, str)
126 projectFileRemoved = pyqtSignal(str, str)
127 projectFileCompiled = pyqtSignal(str, str)
136 projectLanguageAddedByCode = pyqtSignal(str) 128 projectLanguageAddedByCode = pyqtSignal(str)
137 projectLanguageRemoved = pyqtSignal(str)
138 projectFormAdded = pyqtSignal(str)
139 projectFormRemoved = pyqtSignal(str)
140 projectFormCompiled = pyqtSignal(str)
141 projectSourceAdded = pyqtSignal(str)
142 projectSourceRemoved = pyqtSignal(str)
143 projectInterfaceAdded = pyqtSignal(str)
144 projectInterfaceRemoved = pyqtSignal(str)
145 projectProtocolAdded = pyqtSignal(str)
146 projectProtocolRemoved = pyqtSignal(str)
147 projectResourceAdded = pyqtSignal(str)
148 projectResourceRemoved = pyqtSignal(str)
149 projectOthersAdded = pyqtSignal(str)
150 projectOthersRemoved = pyqtSignal(str)
151 projectAboutToBeCreated = pyqtSignal() 129 projectAboutToBeCreated = pyqtSignal()
152 newProjectHooks = pyqtSignal() 130 newProjectHooks = pyqtSignal()
153 newProject = pyqtSignal() 131 newProject = pyqtSignal()
154 sourceFile = pyqtSignal(str) 132 sourceFile = pyqtSignal(str)
155 designerFile = pyqtSignal(str) 133 designerFile = pyqtSignal(str)
172 showMenu = pyqtSignal(str, QMenu) 150 showMenu = pyqtSignal(str, QMenu)
173 lexerAssociationsChanged = pyqtSignal() 151 lexerAssociationsChanged = pyqtSignal()
174 projectChanged = pyqtSignal() 152 projectChanged = pyqtSignal()
175 appendStdout = pyqtSignal(str) 153 appendStdout = pyqtSignal(str)
176 appendStderr = pyqtSignal(str) 154 appendStderr = pyqtSignal(str)
155 processChangedProjectFiles = pyqtSignal()
177 156
178 eols = [os.linesep, "\n", "\r", "\r\n"] 157 eols = [os.linesep, "\n", "\r", "\r\n"]
179 158
180 DefaultMake = "make" 159 DefaultMake = "make"
181 DefaultMakefile = "makefile" 160 DefaultMakefile = "makefile"
202 "Python3": self.tr( 181 "Python3": self.tr(
203 "Python3 Files (*.py *.py3);;" "Python3 GUI Files (*.pyw *.pyw3);;" 182 "Python3 Files (*.py *.py3);;" "Python3 GUI Files (*.pyw *.pyw3);;"
204 ), 183 ),
205 } 184 }
206 185
186 self.__fileCategoriesRepository = {}
187 # This dictionary will be populated by the various project browsers with
188 # classes of type 'FileCategoryRepositoryItem' using the 'addFileCategory()
189 # and removeFileCategory() methods.
190
207 self.vcsMenu = None 191 self.vcsMenu = None
208 self.__makeProcess = None 192 self.__makeProcess = None
209 193
210 self.__initProjectTypes() 194 self.__initProjectTypes()
211 195
222 206
223 if filename is not None: 207 if filename is not None:
224 self.openProject(filename) 208 self.openProject(filename)
225 else: 209 else:
226 self.vcs = self.initVCS() 210 self.vcs = self.initVCS()
227
228 from .ProjectBrowserModel import ProjectBrowserModel
229 211
230 self.__model = ProjectBrowserModel(self) 212 self.__model = ProjectBrowserModel(self)
231 213
232 self.codemetrics = None 214 self.codemetrics = None
233 self.codecoverage = None 215 self.codecoverage = None
234 self.profiledata = None 216 self.profiledata = None
235 self.applicationDiagram = None 217 self.applicationDiagram = None
236 self.loadedDiagram = None 218 self.loadedDiagram = None
237 self.__findProjectFileDialog = None 219 self.__findProjectFileDialog = None
220
221 self.processChangedProjectFiles.connect(self.__autoExecuteMake)
222
223 def addFileCategory(self, category, categoryItem):
224 """
225 Public method to add a file category to the categories repository.
226
227 Note: The given category must not be contained in the repository already.
228
229 @param category file category (must be unique)
230 @type str
231 @param categoryItem data class instance containing the category data
232 @type FileCategoryRepositoryItem
233 @exception TypeError raised to signal a wrong type for the category item
234 """
235 if not isinstance(categoryItem, FileCategoryRepositoryItem):
236 raise TypeError(
237 "'categoryItem' must be an instance of 'FileCategoryRepositoryItem'."
238 )
239
240 if category in self.__fileCategoriesRepository:
241 EricMessageBox.critical(
242 self.ui,
243 self.tr("Add File Category"),
244 self.tr(
245 "<p>The file category <b>{0}</b> has already been added. This"
246 " attempt will be ignored.</p>"
247 ),
248 )
249 else:
250 self.__fileCategoriesRepository[category] = categoryItem
251 with contextlib.suppress(AttributeError):
252 self.__pdata[category] = []
253
254 def removeFileCategory(self, category):
255 """
256 Public method to remove a category from the categories repository.
257
258 Note: If the category is not contained in the repository, the request to
259 remove it will be ignored silently.
260
261 @param category file category
262 @type str
263 """
264 with contextlib.suppress(KeyError):
265 del self.__fileCategoriesRepository[category]
238 266
239 def __sourceExtensions(self, language): 267 def __sourceExtensions(self, language):
240 """ 268 """
241 Private method to get the source extensions of a programming language. 269 Private method to get the source extensions of a programming language.
242 270
482 self.dbgGlobalConfigOverride = { 510 self.dbgGlobalConfigOverride = {
483 "enable": False, 511 "enable": False,
484 "redirect": True, 512 "redirect": True,
485 } 513 }
486 514
487 self.pdata = { 515 self.__pdata = {
488 "DESCRIPTION": "", 516 "DESCRIPTION": "",
489 "VERSION": "", 517 "VERSION": "",
490 "SOURCES": [],
491 "FORMS": [],
492 "RESOURCES": [],
493 "INTERFACES": [],
494 "PROTOCOLS": [],
495 "OTHERS": [],
496 "TRANSLATIONS": [],
497 "TRANSLATIONEXCEPTIONS": [], 518 "TRANSLATIONEXCEPTIONS": [],
498 "TRANSLATIONPATTERN": "", 519 "TRANSLATIONPATTERN": "",
499 "TRANSLATIONSBINPATH": "", 520 "TRANSLATIONSBINPATH": "",
500 "TRANSLATIONSOURCESTARTPATH": "", 521 "TRANSLATIONSOURCESTARTPATH": "",
501 "MAINSCRIPT": "", 522 "MAINSCRIPT": "",
546 "DOCSTRING": "", 567 "DOCSTRING": "",
547 "TESTING_FRAMEWORK": "", 568 "TESTING_FRAMEWORK": "",
548 "LICENSE": "", 569 "LICENSE": "",
549 "EMBEDDED_VENV": False, 570 "EMBEDDED_VENV": False,
550 } 571 }
572 for category in self.__fileCategoriesRepository:
573 self.__pdata[category] = []
551 574
552 self.__initDebugProperties() 575 self.__initDebugProperties()
553 576
554 self.pudata = { 577 self.pudata = {
555 "VCSOVERRIDE": "", 578 "VCSOVERRIDE": "",
557 } 580 }
558 581
559 self.vcs = self.initVCS() 582 self.vcs = self.initVCS()
560 583
561 self.__initVenvConfiguration() 584 self.__initVenvConfiguration()
585
586 def getProjectData(self, dataKey=None, default=None):
587 """
588 Public method to get the data associated with the given data key.
589
590 Note: If dataKey is None, a copy of the project data structure
591 is returned.
592
593 @param dataKey key of the data to get (defaults to None)
594 @type str (optional)
595 @param default default value for non-existent keys (defaults to None)
596 @type Any (optional)
597 @return requested data or None if the data key doesn't exist or
598 a copy of the project data dictionary
599 @rtype Any
600 """
601 if dataKey is None:
602 return copy.deepcopy(self.__pdata)
603
604 try:
605 return self.__pdata[dataKey]
606 except KeyError:
607 return default
608
609 def setProjectData(self, data, dataKey=None, setDirty=True):
610 """
611 Public method to set data associated with the given data key in the project
612 dictionary.
613
614 Note: If no data key is given or is None, the data must be a dictionary used
615 to update the project data.
616
617 @param data data to be set or a dictionary to update the project data
618 @type Any
619 @param dataKey key of the data to set (defaults to None)
620 @type str (optional)
621 @param setDirty flag indicating to set the dirty flag if the data is different
622 from the current one (defaults to True)
623 @type bool (optional)
624 """
625 if dataKey is None:
626 self.__pdata.update(data)
627 else:
628 if self.__pdata[dataKey] != data and setDirty:
629 self.setDirty(True)
630 self.__pdata[dataKey] = data
562 631
563 def getData(self, category, key): 632 def getData(self, category, key):
564 """ 633 """
565 Public method to get data out of the project data store. 634 Public method to get data out of the project data store.
566 635
578 "CHECKERSPARMS", 647 "CHECKERSPARMS",
579 "PACKAGERSPARMS", 648 "PACKAGERSPARMS",
580 "DOCUMENTATIONPARMS", 649 "DOCUMENTATIONPARMS",
581 "OTHERTOOLSPARMS", 650 "OTHERTOOLSPARMS",
582 ] 651 ]
583 and key in self.pdata[category] 652 and key in self.__pdata[category]
584 ): 653 ):
585 return copy.deepcopy(self.pdata[category][key]) 654 return copy.deepcopy(self.__pdata[category][key])
586 else: 655 else:
587 return None 656 return None
588 657
589 def setData(self, category, key, data): 658 def setData(self, category, key, data):
590 """ 659 """
607 ]: 676 ]:
608 return False 677 return False
609 678
610 # test for changes of data and save them in the project 679 # test for changes of data and save them in the project
611 # 1. there were none, now there are 680 # 1. there were none, now there are
612 if key not in self.pdata[category] and len(data) > 0: 681 if key not in self.__pdata[category] and len(data) > 0:
613 self.pdata[category][key] = copy.deepcopy(data) 682 self.__pdata[category][key] = copy.deepcopy(data)
614 self.setDirty(True) 683 self.setDirty(True)
615 # 2. there were some, now there aren't 684 # 2. there were some, now there aren't
616 elif key in self.pdata[category] and len(data) == 0: 685 elif key in self.__pdata[category] and len(data) == 0:
617 del self.pdata[category][key] 686 del self.__pdata[category][key]
618 self.setDirty(True) 687 self.setDirty(True)
619 # 3. there were some and still are 688 # 3. there were some and still are
620 elif key in self.pdata[category] and len(data) > 0: 689 elif key in self.__pdata[category] and len(data) > 0:
621 if data != self.pdata[category][key]: 690 if data != self.__pdata[category][key]:
622 self.pdata[category][key] = copy.deepcopy(data) 691 self.__pdata[category][key] = copy.deepcopy(data)
623 self.setDirty(True) 692 self.setDirty(True)
624 # 4. there were none and none are given 693 # 4. there were none and none are given
625 else: 694 else:
626 return False 695 return False
627 return True 696 return True
628 697
698 def getFileCategories(self):
699 """
700 Public method to get the list of known file categories.
701
702 @return list of known file categories
703 @rtype list of str
704 """
705 return list(self.__fileCategoriesRepository.keys())
706
707 def getFileCategoryFilterString(
708 self, categories=None, withOthers=False, withAll=True
709 ):
710 """
711 Public method to get a file selection string for the given categories.
712
713 @param categories list of file type categories (defaults to None).
714 A value of None means all categories except 'OTHERS'.
715 @type list of str (optional)
716 @param withOthers flag indicating to include the 'OTHERS' category
717 (defaults to False)
718 @type bool (optional)
719 @param withAll flag indicating to include a filter for 'All Files'
720 (defaults to True)
721 @type bool (optional)
722 @return file selection filter string
723 @rtype str
724 """
725 if categories is None:
726 categories = [c for c in self.__fileCategoriesRepository if c != "OTHERS"]
727 if withOthers:
728 categories.append("OTHERS")
729
730 patterns = collections.defaultdict(list)
731 for pattern, filetype in self.__pdata["FILETYPES"].items():
732 if filetype in categories and filetype in self.__fileCategoriesRepository:
733 patterns[filetype].append(pattern)
734
735 filters = []
736 for filetype in patterns:
737 filters.append(
738 self.__fileCategoriesRepository[
739 filetype
740 ].fileCategoryFilterTemplate.format(
741 " ".join(sorted(patterns[filetype]))
742 )
743 )
744 filterString = ";;".join(sorted(filters))
745 if withAll:
746 filterString += ";;" + self.tr("All Files (*)")
747
748 return filterString
749
750 def getFileCategoryString(self, category):
751 """
752 Public method to get a user string for the given category.
753
754 @param category file type category
755 @type str
756 @return user string for the category
757 @rtype str
758 """
759 return self.__fileCategoriesRepository[category].fileCategoryUserString
760
761 def getFileCategoryType(self, category):
762 """
763 Public method to get a user type string for the given category.
764
765 @param category file type category
766 @type str
767 @return user type string for the category
768 @rtype str
769 """
770 return self.__fileCategoriesRepository[category].fileCategoryTyeString
771
772 def getFileCategoryExtension(self, category, reverse=False):
773 """
774 Public method to get a list of default file extensions for the given category.
775
776 @param category file type category
777 @type str
778 @param reverse flag indicating to get all other extensions except the one of
779 the given category
780 @type bool
781 @return list of default file extensions for the category
782 @rtype list of str
783 """
784 if reverse:
785 extensions = []
786 for cat, item in self.__fileCategoriesRepository.items():
787 if cat != category:
788 extensions += item.fileCategoryExtensions[:]
789 return extensions
790 else:
791 return self.__fileCategoriesRepository[category].fileCategoryExtensions[:]
792
629 def initFileTypes(self): 793 def initFileTypes(self):
630 """ 794 """
631 Public method to initialize the filetype associations with default 795 Public method to initialize the filetype associations with default
632 values. 796 values.
633 """ 797 """
634 self.pdata["FILETYPES"] = { 798 self.__pdata["FILETYPES"] = {
635 "*.txt": "OTHERS", 799 "*.txt": "OTHERS",
636 "*.md": "OTHERS", 800 "*.md": "OTHERS",
637 "*.rst": "OTHERS", 801 "*.rst": "OTHERS",
638 "README": "OTHERS", 802 "README": "OTHERS",
639 "README.*": "OTHERS", 803 "README.*": "OTHERS",
644 "Makefile": "OTHERS", 808 "Makefile": "OTHERS",
645 } 809 }
646 810
647 # Sources 811 # Sources
648 sourceKey = ( 812 sourceKey = (
649 "Mixed" if self.pdata["MIXEDLANGUAGE"] else self.pdata["PROGLANGUAGE"] 813 "Mixed" if self.__pdata["MIXEDLANGUAGE"] else self.__pdata["PROGLANGUAGE"]
650 ) 814 )
651 for ext in self.__sourceExtensions(sourceKey): 815 for ext in self.__sourceExtensions(sourceKey):
652 self.pdata["FILETYPES"]["*{0}".format(ext)] = "SOURCES" 816 self.__pdata["FILETYPES"]["*{0}".format(ext)] = "SOURCES"
653 817
654 # IDL interfaces 818 # IDL interfaces
655 self.pdata["FILETYPES"]["*.idl"] = "INTERFACES" 819 self.__pdata["FILETYPES"]["*.idl"] = "INTERFACES"
656 820
657 # Protobuf Files 821 # Protobuf Files
658 self.pdata["FILETYPES"]["*.proto"] = "PROTOCOLS" 822 self.__pdata["FILETYPES"]["*.proto"] = "PROTOCOLS"
659 823
660 # Forms 824 # Forms
661 if self.pdata["PROJECTTYPE"] in [ 825 if self.__pdata["PROJECTTYPE"] in [
662 "E7Plugin", 826 "E7Plugin",
663 "PyQt5", 827 "PyQt5",
664 "PyQt6", 828 "PyQt6",
665 "PySide2", 829 "PySide2",
666 "PySide6", 830 "PySide6",
667 ]: 831 ]:
668 self.pdata["FILETYPES"]["*.ui"] = "FORMS" 832 self.__pdata["FILETYPES"]["*.ui"] = "FORMS"
669 833
670 # Resources 834 # Resources
671 if self.pdata["PROJECTTYPE"] in [ 835 if self.__pdata["PROJECTTYPE"] in [
672 "PyQt5", 836 "PyQt5",
673 "PyQt5C", 837 "PyQt5C",
674 "PySide2", 838 "PySide2",
675 "PySide2C", 839 "PySide2C",
676 "PySide6", 840 "PySide6",
677 "PySide6C", 841 "PySide6C",
678 ]: 842 ]:
679 self.pdata["FILETYPES"]["*.qrc"] = "RESOURCES" 843 self.__pdata["FILETYPES"]["*.qrc"] = "RESOURCES"
680 844
681 # Translations 845 # Translations
682 if self.pdata["PROJECTTYPE"] in [ 846 if self.__pdata["PROJECTTYPE"] in [
683 "E7Plugin", 847 "E7Plugin",
684 "PyQt5", 848 "PyQt5",
685 "PyQt5C", 849 "PyQt5C",
686 "PyQt6", 850 "PyQt6",
687 "PyQt6C", 851 "PyQt6C",
688 "PySide2", 852 "PySide2",
689 "PySide2C", 853 "PySide2C",
690 "PySide6", 854 "PySide6",
691 "PySide6C", 855 "PySide6C",
692 ]: 856 ]:
693 self.pdata["FILETYPES"]["*.ts"] = "TRANSLATIONS" 857 self.__pdata["FILETYPES"]["*.ts"] = "TRANSLATIONS"
694 self.pdata["FILETYPES"]["*.qm"] = "TRANSLATIONS" 858 self.__pdata["FILETYPES"]["*.qm"] = "TRANSLATIONS"
695 859
696 # Project type specific ones 860 # Project type specific ones
697 with contextlib.suppress(KeyError): 861 with contextlib.suppress(KeyError):
698 if self.__fileTypeCallbacks[self.pdata["PROJECTTYPE"]] is not None: 862 if self.__fileTypeCallbacks[self.__pdata["PROJECTTYPE"]] is not None:
699 ftypes = self.__fileTypeCallbacks[self.pdata["PROJECTTYPE"]]() 863 ftypes = self.__fileTypeCallbacks[self.__pdata["PROJECTTYPE"]]()
700 self.pdata["FILETYPES"].update(ftypes) 864 self.__pdata["FILETYPES"].update(ftypes)
701 865
702 self.setDirty(True) 866 self.setDirty(True)
703 867
704 def updateFileTypes(self): 868 def updateFileTypes(self):
705 """ 869 """
706 Public method to update the filetype associations with new default 870 Public method to update the filetype associations with new default
707 values. 871 values.
708 """ 872 """
709 if self.pdata["PROJECTTYPE"] in [ 873 if self.__pdata["PROJECTTYPE"] in [
710 "E7Plugin", 874 "E7Plugin",
711 "PyQt5", 875 "PyQt5",
712 "PyQt5C", 876 "PyQt5C",
713 "PyQt6", 877 "PyQt6",
714 "PyQt6C", 878 "PyQt6C",
715 "PySide2", 879 "PySide2",
716 "PySide2C", 880 "PySide2C",
717 "PySide6", 881 "PySide6",
718 "PySide6C", 882 "PySide6C",
719 ]: 883 ]:
720 if "*.ts" not in self.pdata["FILETYPES"]: 884 if "*.ts" not in self.__pdata["FILETYPES"]:
721 self.pdata["FILETYPES"]["*.ts"] = "TRANSLATIONS" 885 self.__pdata["FILETYPES"]["*.ts"] = "TRANSLATIONS"
722 if "*.qm" not in self.pdata["FILETYPES"]: 886 if "*.qm" not in self.__pdata["FILETYPES"]:
723 self.pdata["FILETYPES"]["*.qm"] = "TRANSLATIONS" 887 self.__pdata["FILETYPES"]["*.qm"] = "TRANSLATIONS"
724 with contextlib.suppress(KeyError): 888 with contextlib.suppress(KeyError):
725 if self.__fileTypeCallbacks[self.pdata["PROJECTTYPE"]] is not None: 889 if self.__fileTypeCallbacks[self.__pdata["PROJECTTYPE"]] is not None:
726 ftypes = self.__fileTypeCallbacks[self.pdata["PROJECTTYPE"]]() 890 ftypes = self.__fileTypeCallbacks[self.__pdata["PROJECTTYPE"]]()
727 for pattern, ftype in list(ftypes.items()): 891 for pattern, ftype in list(ftypes.items()):
728 if pattern not in self.pdata["FILETYPES"]: 892 if pattern not in self.__pdata["FILETYPES"]:
729 self.pdata["FILETYPES"][pattern] = ftype 893 self.__pdata["FILETYPES"][pattern] = ftype
730 self.setDirty(True) 894 self.setDirty(True)
731 895
732 def __loadRecent(self): 896 def __loadRecent(self):
733 """ 897 """
734 Private method to load the recently opened project filenames. 898 Private method to load the recently opened project filenames.
843 1007
844 @param index key of the list to be checked (string) 1008 @param index key of the list to be checked (string)
845 """ 1009 """
846 removed = False 1010 removed = False
847 removelist = [] 1011 removelist = []
848 for file in self.pdata[index]: 1012 for file in self.__pdata[index]:
849 if not os.path.exists(os.path.join(self.ppath, file)): 1013 if not os.path.exists(os.path.join(self.ppath, file)):
850 removelist.append(file) 1014 removelist.append(file)
851 removed = True 1015 removed = True
852 1016
853 if removed: 1017 if removed:
854 for file in removelist: 1018 for file in removelist:
855 self.pdata[index].remove(file) 1019 self.__pdata[index].remove(file)
856 self.setDirty(True) 1020 self.setDirty(True)
857 1021
858 def __readProject(self, fn): 1022 def __readProject(self, fn):
859 """ 1023 """
860 Private method to read in a project (.epj or .e4p) file. 1024 Private method to read in a project (.epj or .e4p) file.
868 res = self.__projectFile.readFile(fn) 1032 res = self.__projectFile.readFile(fn)
869 else: 1033 else:
870 # old XML based format 1034 # old XML based format
871 f = QFile(fn) 1035 f = QFile(fn)
872 if f.open(QIODevice.OpenModeFlag.ReadOnly): 1036 if f.open(QIODevice.OpenModeFlag.ReadOnly):
873 from eric7.EricXML.ProjectReader import ProjectReader
874
875 reader = ProjectReader(f, self) 1037 reader = ProjectReader(f, self)
876 reader.readXML() 1038 reader.readXML()
877 res = not reader.hasError() 1039 res = not reader.hasError()
878 f.close() 1040 f.close()
879 1041
880 # create hash value, if it doesn't have one 1042 # create hash value, if it doesn't have one
881 if reader.version.startswith("5.") and not self.pdata["HASH"]: 1043 if reader.version.startswith("5.") and not self.__pdata["HASH"]:
882 hashStr = str( 1044 hashStr = str(
883 QCryptographicHash.hash( 1045 QCryptographicHash.hash(
884 QByteArray(self.ppath.encode("utf-8")), 1046 QByteArray(self.ppath.encode("utf-8")),
885 QCryptographicHash.Algorithm.Sha1, 1047 QCryptographicHash.Algorithm.Sha1,
886 ).toHex(), 1048 ).toHex(),
887 encoding="utf-8", 1049 encoding="utf-8",
888 ) 1050 )
889 self.pdata["HASH"] = hashStr 1051 self.__pdata["HASH"] = hashStr
890 self.setDirty(True) 1052 self.setDirty(True)
891 else: 1053 else:
892 EricMessageBox.critical( 1054 EricMessageBox.critical(
893 self.ui, 1055 self.ui,
894 self.tr("Read Project File"), 1056 self.tr("Read Project File"),
903 self.ppath = os.path.abspath(os.path.dirname(fn)) 1065 self.ppath = os.path.abspath(os.path.dirname(fn))
904 1066
905 # insert filename into list of recently opened projects 1067 # insert filename into list of recently opened projects
906 self.__syncRecent() 1068 self.__syncRecent()
907 1069
908 if self.pdata["TRANSLATIONPATTERN"]: 1070 if self.__pdata["TRANSLATIONPATTERN"]:
909 self.translationsRoot = self.pdata["TRANSLATIONPATTERN"].split( 1071 self.translationsRoot = self.__pdata["TRANSLATIONPATTERN"].split(
910 "%language%" 1072 "%language%"
911 )[0] 1073 )[0]
912 elif self.pdata["MAINSCRIPT"]: 1074 elif self.__pdata["MAINSCRIPT"]:
913 self.translationsRoot = os.path.splitext(self.pdata["MAINSCRIPT"])[0] 1075 self.translationsRoot = os.path.splitext(self.__pdata["MAINSCRIPT"])[0]
914 if os.path.isdir(os.path.join(self.ppath, self.translationsRoot)): 1076 if os.path.isdir(os.path.join(self.ppath, self.translationsRoot)):
915 dn = self.translationsRoot 1077 dn = self.translationsRoot
916 else: 1078 else:
917 dn = os.path.dirname(self.translationsRoot) 1079 dn = os.path.dirname(self.translationsRoot)
918 if dn not in self.subdirs: 1080 if dn not in self.subdirs:
920 1082
921 self.name = os.path.splitext(os.path.basename(fn))[0] 1083 self.name = os.path.splitext(os.path.basename(fn))[0]
922 1084
923 # check, if the files of the project still exist in the 1085 # check, if the files of the project still exist in the
924 # project directory 1086 # project directory
925 self.__checkFilesExist("SOURCES") 1087 for fileCategory in self.getFileCategories():
926 self.__checkFilesExist("FORMS") 1088 self.__checkFilesExist(fileCategory)
927 self.__checkFilesExist("INTERFACES")
928 self.__checkFilesExist("PROTOCOLS")
929 self.__checkFilesExist("TRANSLATIONS")
930 self.__checkFilesExist("RESOURCES")
931 self.__checkFilesExist("OTHERS")
932 1089
933 # get the names of subdirectories the files are stored in 1090 # get the names of subdirectories the files are stored in
934 for fn in ( 1091 for fileCategory in [c for c in self.getFileCategories() if c != "OTHERS"]:
935 self.pdata["SOURCES"] 1092 for fn in self.__pdata[fileCategory]:
936 + self.pdata["FORMS"] 1093 dn = os.path.dirname(fn)
937 + self.pdata["INTERFACES"] 1094 if dn not in self.subdirs:
938 + self.pdata["PROTOCOLS"] 1095 self.subdirs.append(dn)
939 + self.pdata["RESOURCES"]
940 + self.pdata["TRANSLATIONS"]
941 ):
942 dn = os.path.dirname(fn)
943 if dn not in self.subdirs:
944 self.subdirs.append(dn)
945 1096
946 # get the names of other subdirectories 1097 # get the names of other subdirectories
947 for fn in self.pdata["OTHERS"]: 1098 for fn in self.__pdata["OTHERS"]:
948 dn = os.path.dirname(fn) 1099 dn = os.path.dirname(fn)
949 if dn not in self.otherssubdirs: 1100 if dn not in self.otherssubdirs:
950 self.otherssubdirs.append(dn) 1101 self.otherssubdirs.append(dn)
951 1102
952 return res 1103 return res
961 is used instead of the one in the project object. This is the 1112 is used instead of the one in the project object. This is the
962 'save as' action. 1113 'save as' action.
963 @return flag indicating success 1114 @return flag indicating success
964 """ 1115 """
965 if self.vcs is not None: 1116 if self.vcs is not None:
966 self.pdata["VCSOPTIONS"] = copy.deepcopy(self.vcs.vcsGetOptions()) 1117 self.__pdata["VCSOPTIONS"] = copy.deepcopy(self.vcs.vcsGetOptions())
967 self.pdata["VCSOTHERDATA"] = copy.deepcopy(self.vcs.vcsGetOtherData()) 1118 self.__pdata["VCSOTHERDATA"] = copy.deepcopy(self.vcs.vcsGetOtherData())
968 1119
969 if not self.pdata["HASH"]: 1120 if not self.__pdata["HASH"]:
970 hashStr = str( 1121 hashStr = str(
971 QCryptographicHash.hash( 1122 QCryptographicHash.hash(
972 QByteArray(self.ppath.encode("utf-8")), 1123 QByteArray(self.ppath.encode("utf-8")),
973 QCryptographicHash.Algorithm.Sha1, 1124 QCryptographicHash.Algorithm.Sha1,
974 ).toHex(), 1125 ).toHex(),
975 encoding="utf-8", 1126 encoding="utf-8",
976 ) 1127 )
977 self.pdata["HASH"] = hashStr 1128 self.__pdata["HASH"] = hashStr
978 1129
979 if fn is None: 1130 if fn is None:
980 fn = self.pfile 1131 fn = self.pfile
981 1132
982 with EricOverrideCursor(): 1133 with EricOverrideCursor():
1010 # try the old XML based format second 1161 # try the old XML based format second
1011 fn = os.path.join(self.getProjectManagementDir(), "{0}.e4q".format(fn1)) 1162 fn = os.path.join(self.getProjectManagementDir(), "{0}.e4q".format(fn1))
1012 if os.path.exists(fn): 1163 if os.path.exists(fn):
1013 f = QFile(fn) 1164 f = QFile(fn)
1014 if f.open(QIODevice.OpenModeFlag.ReadOnly): 1165 if f.open(QIODevice.OpenModeFlag.ReadOnly):
1015 from eric7.EricXML.UserProjectReader import UserProjectReader
1016
1017 reader = UserProjectReader(f, self) 1166 reader = UserProjectReader(f, self)
1018 reader.readXML() 1167 reader.readXML()
1019 f.close() 1168 f.close()
1020 else: 1169 else:
1021 EricMessageBox.critical( 1170 EricMessageBox.critical(
1086 self.getProjectManagementDir(), "{0}{1}.e5s".format(fn1, indicator) 1235 self.getProjectManagementDir(), "{0}{1}.e5s".format(fn1, indicator)
1087 ) 1236 )
1088 if os.path.exists(fn): 1237 if os.path.exists(fn):
1089 f = QFile(fn) 1238 f = QFile(fn)
1090 if f.open(QIODevice.OpenModeFlag.ReadOnly): 1239 if f.open(QIODevice.OpenModeFlag.ReadOnly):
1091 from eric7.EricXML.SessionReader import SessionReader
1092
1093 reader = SessionReader(f, False) 1240 reader = SessionReader(f, False)
1094 reader.readXML(quiet=quiet) 1241 reader.readXML(quiet=quiet)
1095 f.close() 1242 f.close()
1096 else: 1243 else:
1097 if not quiet: 1244 if not quiet:
1181 # try old style XML file second 1328 # try old style XML file second
1182 fn = os.path.join(self.getProjectManagementDir(), "{0}.e6t".format(base)) 1329 fn = os.path.join(self.getProjectManagementDir(), "{0}.e6t".format(base))
1183 if os.path.exists(fn): 1330 if os.path.exists(fn):
1184 f = QFile(fn) 1331 f = QFile(fn)
1185 if f.open(QIODevice.OpenModeFlag.ReadOnly): 1332 if f.open(QIODevice.OpenModeFlag.ReadOnly):
1186 from eric7.EricXML.TasksReader import TasksReader
1187
1188 reader = TasksReader(f, True) 1333 reader = TasksReader(f, True)
1189 reader.readXML() 1334 reader.readXML()
1190 f.close() 1335 f.close()
1191 else: 1336 else:
1192 EricMessageBox.critical( 1337 EricMessageBox.critical(
1260 # try the old XML based format second 1405 # try the old XML based format second
1261 fn = os.path.join(self.getProjectManagementDir(), "{0}.e4d".format(fn1)) 1406 fn = os.path.join(self.getProjectManagementDir(), "{0}.e4d".format(fn1))
1262 1407
1263 f = QFile(fn) 1408 f = QFile(fn)
1264 if f.open(QIODevice.OpenModeFlag.ReadOnly): 1409 if f.open(QIODevice.OpenModeFlag.ReadOnly):
1265 from eric7.EricXML.DebuggerPropertiesReader import (
1266 DebuggerPropertiesReader,
1267 )
1268
1269 reader = DebuggerPropertiesReader(f, self) 1410 reader = DebuggerPropertiesReader(f, self)
1270 reader.readXML(quiet=quiet) 1411 reader.readXML(quiet=quiet)
1271 f.close() 1412 f.close()
1272 self.debugPropertiesLoaded = True 1413 self.debugPropertiesLoaded = True
1273 self.debugPropertiesChanged = False 1414 self.debugPropertiesChanged = False
1364 """ 1505 """
1365 Public method to return the status of the debug properties. 1506 Public method to return the status of the debug properties.
1366 1507
1367 @return load status of debug properties (boolean) 1508 @return load status of debug properties (boolean)
1368 """ 1509 """
1369 return self.debugPropertiesLoaded or self.pdata["EMBEDDED_VENV"] 1510 return self.debugPropertiesLoaded or self.__pdata["EMBEDDED_VENV"]
1370 1511
1371 def __showDebugProperties(self): 1512 def __showDebugProperties(self):
1372 """ 1513 """
1373 Private slot to display the debugger properties dialog. 1514 Private slot to display the debugger properties dialog.
1374 """ 1515 """
1469 """ 1610 """
1470 Public method to get the translation pattern. 1611 Public method to get the translation pattern.
1471 1612
1472 @return translation pattern (string) 1613 @return translation pattern (string)
1473 """ 1614 """
1474 return self.pdata["TRANSLATIONPATTERN"] 1615 return self.__pdata["TRANSLATIONPATTERN"]
1475 1616
1476 def setTranslationPattern(self, pattern): 1617 def setTranslationPattern(self, pattern):
1477 """ 1618 """
1478 Public method to set the translation pattern. 1619 Public method to set the translation pattern.
1479 1620
1480 @param pattern translation pattern 1621 @param pattern translation pattern
1481 @type str 1622 @type str
1482 """ 1623 """
1483 self.pdata["TRANSLATIONPATTERN"] = pattern 1624 self.__pdata["TRANSLATIONPATTERN"] = pattern
1484 1625
1485 def addLanguage(self): 1626 def addLanguage(self):
1486 """ 1627 """
1487 Public slot used to add a language to the project. 1628 Public slot used to add a language to the project.
1488 """ 1629 """
1489 if not self.pdata["TRANSLATIONPATTERN"]: 1630 from .AddLanguageDialog import AddLanguageDialog
1631
1632 if not self.__pdata["TRANSLATIONPATTERN"]:
1490 EricMessageBox.critical( 1633 EricMessageBox.critical(
1491 self.ui, 1634 self.ui,
1492 self.tr("Add Language"), 1635 self.tr("Add Language"),
1493 self.tr("You have to specify a translation pattern first."), 1636 self.tr("You have to specify a translation pattern first."),
1494 ) 1637 )
1495 return 1638 return
1496 1639
1497 from .AddLanguageDialog import AddLanguageDialog
1498
1499 dlg = AddLanguageDialog(self.parent()) 1640 dlg = AddLanguageDialog(self.parent())
1500 if dlg.exec() == QDialog.DialogCode.Accepted: 1641 if dlg.exec() == QDialog.DialogCode.Accepted:
1501 lang = dlg.getSelectedLanguage() 1642 lang = dlg.getSelectedLanguage()
1502 if self.pdata["PROJECTTYPE"] in [ 1643 if self.__pdata["PROJECTTYPE"] in [
1503 "PyQt5", 1644 "PyQt5",
1504 "PyQt5C", 1645 "PyQt5C",
1505 "PyQt6", 1646 "PyQt6",
1506 "PyQt6C", 1647 "PyQt6C",
1507 "E7Plugin", 1648 "E7Plugin",
1508 "PySide2", 1649 "PySide2",
1509 "PySide2C", 1650 "PySide2C",
1510 "PySide6", 1651 "PySide6",
1511 "PySide6C", 1652 "PySide6C",
1512 ]: 1653 ]:
1513 langFile = self.pdata["TRANSLATIONPATTERN"].replace("%language%", lang) 1654 langFile = self.__pdata["TRANSLATIONPATTERN"].replace(
1655 "%language%", lang
1656 )
1514 self.appendFile(langFile) 1657 self.appendFile(langFile)
1515 self.projectLanguageAddedByCode.emit(lang) 1658 self.projectLanguageAddedByCode.emit(lang)
1516 1659
1517 def __binaryTranslationFile(self, langFile): 1660 def __binaryTranslationFile(self, langFile):
1518 """ 1661 """
1523 @return name of the binary translations file (string) 1666 @return name of the binary translations file (string)
1524 """ 1667 """
1525 qmFile = "" 1668 qmFile = ""
1526 try: 1669 try:
1527 if ( 1670 if (
1528 self.__binaryTranslationsCallbacks[self.pdata["PROJECTTYPE"]] 1671 self.__binaryTranslationsCallbacks[self.__pdata["PROJECTTYPE"]]
1529 is not None 1672 is not None
1530 ): 1673 ):
1531 qmFile = self.__binaryTranslationsCallbacks[self.pdata["PROJECTTYPE"]]( 1674 qmFile = self.__binaryTranslationsCallbacks[
1532 langFile 1675 self.__pdata["PROJECTTYPE"]
1533 ) 1676 ](langFile)
1534 except KeyError: 1677 except KeyError:
1535 qmFile = langFile.replace(".ts", ".qm") 1678 qmFile = langFile.replace(".ts", ".qm")
1536 if qmFile == langFile: 1679 if qmFile == langFile:
1537 qmFile = "" 1680 qmFile = ""
1538 return qmFile 1681 return qmFile
1539 1682
1540 def checkLanguageFiles(self): 1683 def checkLanguageFiles(self):
1541 """ 1684 """
1542 Public slot to check the language files after a release process. 1685 Public slot to check the language files after a release process.
1543 """ 1686 """
1544 tbPath = self.pdata["TRANSLATIONSBINPATH"] 1687 tbPath = self.__pdata["TRANSLATIONSBINPATH"]
1545 for langFile in self.pdata["TRANSLATIONS"][:]: 1688 for langFile in self.__pdata["TRANSLATIONS"][:]:
1546 qmFile = self.__binaryTranslationFile(langFile) 1689 qmFile = self.__binaryTranslationFile(langFile)
1547 if qmFile: 1690 if qmFile:
1548 if qmFile not in self.pdata["TRANSLATIONS"] and os.path.exists( 1691 if qmFile not in self.__pdata["TRANSLATIONS"] and os.path.exists(
1549 os.path.join(self.ppath, qmFile) 1692 os.path.join(self.ppath, qmFile)
1550 ): 1693 ):
1551 self.appendFile(qmFile) 1694 self.appendFile(qmFile)
1552 if tbPath: 1695 if tbPath:
1553 qmFile = os.path.join(tbPath, os.path.basename(qmFile)) 1696 qmFile = os.path.join(tbPath, os.path.basename(qmFile))
1554 if qmFile not in self.pdata["TRANSLATIONS"] and os.path.exists( 1697 if qmFile not in self.__pdata["TRANSLATIONS"] and os.path.exists(
1555 os.path.join(self.ppath, qmFile) 1698 os.path.join(self.ppath, qmFile)
1556 ): 1699 ):
1557 self.appendFile(qmFile) 1700 self.appendFile(qmFile)
1558 1701
1559 def removeLanguageFile(self, langFile): 1702 def removeLanguageFile(self, langFile):
1564 1707
1565 @param langFile the translation file to be removed (string) 1708 @param langFile the translation file to be removed (string)
1566 """ 1709 """
1567 langFile = self.getRelativePath(langFile) 1710 langFile = self.getRelativePath(langFile)
1568 qmFile = self.__binaryTranslationFile(langFile) 1711 qmFile = self.__binaryTranslationFile(langFile)
1569 self.pdata["TRANSLATIONS"].remove(langFile) 1712 self.__pdata["TRANSLATIONS"].remove(langFile)
1570 self.__model.removeItem(langFile) 1713 self.__model.removeItem(langFile)
1571 if qmFile: 1714 if qmFile:
1572 with contextlib.suppress(ValueError): 1715 with contextlib.suppress(ValueError):
1573 if self.pdata["TRANSLATIONSBINPATH"]: 1716 if self.__pdata["TRANSLATIONSBINPATH"]:
1574 qmFile = self.getRelativePath( 1717 qmFile = self.getRelativePath(
1575 os.path.join( 1718 os.path.join(
1576 self.pdata["TRANSLATIONSBINPATH"], os.path.basename(qmFile) 1719 self.__pdata["TRANSLATIONSBINPATH"],
1720 os.path.basename(qmFile),
1577 ) 1721 )
1578 ) 1722 )
1579 self.pdata["TRANSLATIONS"].remove(qmFile) 1723 self.__pdata["TRANSLATIONS"].remove(qmFile)
1580 self.__model.removeItem(qmFile) 1724 self.__model.removeItem(qmFile)
1581 self.setDirty(True) 1725 self.setDirty(True)
1582 1726
1583 def deleteLanguageFile(self, langFile): 1727 def deleteLanguageFile(self, langFile):
1584 """ 1728 """
1585 Public slot to delete a translation from the project directory. 1729 Public slot to delete a translation from the project directory.
1586 1730
1587 @param langFile the translation file to be removed (string) 1731 @param langFile the translation file to be removed (string)
1588 """ 1732 """
1589 try: 1733 try:
1590 from send2trash import send2trash as s2t 1734 from send2trash import send2trash as s2t # __IGNORE_WARNING_I10__
1591 except ImportError: 1735 except ImportError:
1592 s2t = os.remove 1736 s2t = os.remove
1593 1737
1594 langFile = self.getRelativePath(langFile) 1738 langFile = self.getRelativePath(langFile)
1595 qmFile = self.__binaryTranslationFile(langFile) 1739 qmFile = self.__binaryTranslationFile(langFile)
1612 self.removeLanguageFile(langFile) 1756 self.removeLanguageFile(langFile)
1613 1757
1614 # now get rid of the .qm file 1758 # now get rid of the .qm file
1615 if qmFile: 1759 if qmFile:
1616 try: 1760 try:
1617 if self.pdata["TRANSLATIONSBINPATH"]: 1761 if self.__pdata["TRANSLATIONSBINPATH"]:
1618 qmFile = self.getRelativePath( 1762 qmFile = self.getRelativePath(
1619 os.path.join( 1763 os.path.join(
1620 self.pdata["TRANSLATIONSBINPATH"], os.path.basename(qmFile) 1764 self.__pdata["TRANSLATIONSBINPATH"],
1765 os.path.basename(qmFile),
1621 ) 1766 )
1622 ) 1767 )
1623 fn = os.path.join(self.ppath, qmFile) 1768 fn = os.path.join(self.ppath, qmFile)
1624 if os.path.exists(fn): 1769 if os.path.exists(fn):
1625 s2t(fn) 1770 s2t(fn)
1657 filetype = "OTHERS" 1802 filetype = "OTHERS"
1658 bfn = os.path.basename(newfn) 1803 bfn = os.path.basename(newfn)
1659 if fnmatch.fnmatch(bfn, "*.ts") or fnmatch.fnmatch(bfn, "*.qm"): 1804 if fnmatch.fnmatch(bfn, "*.ts") or fnmatch.fnmatch(bfn, "*.qm"):
1660 filetype = "TRANSLATIONS" 1805 filetype = "TRANSLATIONS"
1661 else: 1806 else:
1662 for pattern in sorted(self.pdata["FILETYPES"].keys(), reverse=True): 1807 for pattern in sorted(self.__pdata["FILETYPES"].keys(), reverse=True):
1663 if fnmatch.fnmatch(bfn, pattern): 1808 if fnmatch.fnmatch(bfn, pattern):
1664 filetype = self.pdata["FILETYPES"][pattern] 1809 filetype = self.__pdata["FILETYPES"][pattern]
1665 break 1810 break
1666 1811
1667 if filetype == "__IGNORE__": 1812 if filetype == "__IGNORE__":
1668 return 1813 return
1669 1814
1670 if filetype in ["SOURCES", "FORMS", "INTERFACES", "PROTOCOLS", "RESOURCES"]: 1815 if filetype in (
1671 if filetype == "SOURCES": 1816 category
1672 if newfn not in self.pdata["SOURCES"]: 1817 for category in self.getFileCategories()
1673 self.pdata["SOURCES"].append(newfn) 1818 if category not in ("TRANSLATIONS", "OTHERS")
1674 self.projectSourceAdded.emit(newfn) 1819 ):
1675 updateModel and self.__model.addNewItem("SOURCES", newfn) 1820 if newfn not in self.__pdata[filetype]:
1676 dirty = True 1821 self.__pdata[filetype].append(newfn)
1677 else: 1822 self.projectFileAdded.emit(newfn, filetype)
1678 updateModel and self.repopulateItem(newfn) 1823 updateModel and self.__model.addNewItem(filetype, newfn)
1679 elif filetype == "FORMS": 1824 dirty = True
1680 if newfn not in self.pdata["FORMS"]: 1825 else:
1681 self.pdata["FORMS"].append(newfn) 1826 updateModel and self.repopulateItem(newfn)
1682 self.projectFormAdded.emit(newfn)
1683 updateModel and self.__model.addNewItem("FORMS", newfn)
1684 dirty = True
1685 else:
1686 updateModel and self.repopulateItem(newfn)
1687 elif filetype == "INTERFACES":
1688 if newfn not in self.pdata["INTERFACES"]:
1689 self.pdata["INTERFACES"].append(newfn)
1690 self.projectInterfaceAdded.emit(newfn)
1691 (updateModel and self.__model.addNewItem("INTERFACES", newfn))
1692 dirty = True
1693 else:
1694 updateModel and self.repopulateItem(newfn)
1695 elif filetype == "PROTOCOLS":
1696 if newfn not in self.pdata["PROTOCOLS"]:
1697 self.pdata["PROTOCOLS"].append(newfn)
1698 self.projectProtocolAdded.emit(newfn)
1699 (updateModel and self.__model.addNewItem("PROTOCOLS", newfn))
1700 dirty = True
1701 else:
1702 updateModel and self.repopulateItem(newfn)
1703 elif filetype == "RESOURCES":
1704 if newfn not in self.pdata["RESOURCES"]:
1705 self.pdata["RESOURCES"].append(newfn)
1706 self.projectResourceAdded.emit(newfn)
1707 updateModel and self.__model.addNewItem("RESOURCES", newfn)
1708 dirty = True
1709 else:
1710 updateModel and self.repopulateItem(newfn)
1711 if newdir not in self.subdirs: 1827 if newdir not in self.subdirs:
1712 self.subdirs.append(newdir) 1828 self.subdirs.append(newdir)
1713 elif filetype == "TRANSLATIONS": 1829 elif filetype == "TRANSLATIONS":
1714 if newfn not in self.pdata["TRANSLATIONS"]: 1830 if newfn not in self.__pdata["TRANSLATIONS"]:
1715 self.pdata["TRANSLATIONS"].append(newfn) 1831 self.__pdata["TRANSLATIONS"].append(newfn)
1716 updateModel and self.__model.addNewItem("TRANSLATIONS", newfn) 1832 updateModel and self.__model.addNewItem("TRANSLATIONS", newfn)
1717 self.projectLanguageAdded.emit(newfn) 1833 self.projectFileAdded.emit(newfn, "TRANSLATIONS")
1718 dirty = True 1834 dirty = True
1719 else: 1835 else:
1720 updateModel and self.repopulateItem(newfn) 1836 updateModel and self.repopulateItem(newfn)
1721 else: # filetype == "OTHERS" 1837 elif filetype == "OTHERS":
1722 if newfn not in self.pdata["OTHERS"]: 1838 if newfn not in self.__pdata["OTHERS"]:
1723 self.pdata["OTHERS"].append(newfn) 1839 self.__pdata["OTHERS"].append(newfn)
1724 self.othersAdded(newfn, updateModel) 1840 self.othersAdded(newfn, updateModel)
1725 dirty = True 1841 dirty = True
1726 else: 1842 else:
1727 updateModel and self.repopulateItem(newfn) 1843 updateModel and self.repopulateItem(newfn)
1728 if newdir not in self.otherssubdirs: 1844 if newdir not in self.otherssubdirs:
1739 @param fileTypeFilter filter to be used by the add file dialog 1855 @param fileTypeFilter filter to be used by the add file dialog
1740 @type str out of source, form, resource, interface, protocol, others 1856 @type str out of source, form, resource, interface, protocol, others
1741 @param startdir start directory for the selection dialog 1857 @param startdir start directory for the selection dialog
1742 @type str 1858 @type str
1743 """ 1859 """
1860 from .AddFileDialog import AddFileDialog
1861
1744 if startdir is None: 1862 if startdir is None:
1745 startdir = self.ppath 1863 startdir = self.ppath
1746 from .AddFileDialog import AddFileDialog
1747 1864
1748 dlg = AddFileDialog(self, self.parent(), fileTypeFilter, startdir=startdir) 1865 dlg = AddFileDialog(self, self.parent(), fileTypeFilter, startdir=startdir)
1749 if dlg.exec() == QDialog.DialogCode.Accepted: 1866 if dlg.exec() == QDialog.DialogCode.Accepted:
1750 fnames, target, isSource = dlg.getData() 1867 fnames, target, isSource = dlg.getData()
1751 if target != "": 1868 if target != "":
1801 @param quiet flag indicating quiet operations (boolean) 1918 @param quiet flag indicating quiet operations (boolean)
1802 """ 1919 """
1803 # get all relevant filename patterns 1920 # get all relevant filename patterns
1804 patterns = [] 1921 patterns = []
1805 ignorePatterns = [] 1922 ignorePatterns = []
1806 for pattern, patterntype in list(self.pdata["FILETYPES"].items()): 1923 for pattern, patterntype in list(self.__pdata["FILETYPES"].items()):
1807 if patterntype == filetype: 1924 if patterntype == filetype:
1808 patterns.append(pattern) 1925 patterns.append(pattern)
1809 elif patterntype == "__IGNORE__": 1926 elif patterntype == "__IGNORE__":
1810 ignorePatterns.append(pattern) 1927 ignorePatterns.append(pattern)
1811 1928
1881 # first perform the addition of source 1998 # first perform the addition of source
1882 self.__addSingleDirectory(filetype, source, target, True) 1999 self.__addSingleDirectory(filetype, source, target, True)
1883 2000
1884 ignore_patterns = [ 2001 ignore_patterns = [
1885 pattern 2002 pattern
1886 for pattern, filetype in self.pdata["FILETYPES"].items() 2003 for pattern, filetype in self.__pdata["FILETYPES"].items()
1887 if filetype == "__IGNORE__" 2004 if filetype == "__IGNORE__"
1888 ] 2005 ]
1889 2006
1890 # now recurse into subdirectories 2007 # now recurse into subdirectories
1891 for name in os.listdir(source): 2008 for name in os.listdir(source):
1910 @param fileTypeFilter filter to be used by the add directory dialog 2027 @param fileTypeFilter filter to be used by the add directory dialog
1911 @type str out of source, form, resource, interface, protocol, others 2028 @type str out of source, form, resource, interface, protocol, others
1912 @param startdir start directory for the selection dialog 2029 @param startdir start directory for the selection dialog
1913 @type str 2030 @type str
1914 """ 2031 """
2032 from .AddDirectoryDialog import AddDirectoryDialog
2033
1915 if startdir is None: 2034 if startdir is None:
1916 startdir = self.ppath 2035 startdir = self.ppath
1917 from .AddDirectoryDialog import AddDirectoryDialog
1918 2036
1919 dlg = AddDirectoryDialog(self, fileTypeFilter, self.parent(), startdir=startdir) 2037 dlg = AddDirectoryDialog(self, fileTypeFilter, self.parent(), startdir=startdir)
1920 if dlg.exec() == QDialog.DialogCode.Accepted: 2038 if dlg.exec() == QDialog.DialogCode.Accepted:
1921 filetype, source, target, recursive = dlg.getData() 2039 filetype, source, target, recursive = dlg.getData()
1922 if target == "": 2040 if target == "":
1956 2074
1957 # if it ends with the directory separator character, remove it 2075 # if it ends with the directory separator character, remove it
1958 if fn.endswith(os.sep): 2076 if fn.endswith(os.sep):
1959 fn = fn[:-1] 2077 fn = fn[:-1]
1960 2078
1961 if fn not in self.pdata["OTHERS"]: 2079 if fn not in self.__pdata["OTHERS"]:
1962 self.pdata["OTHERS"].append(fn) 2080 self.__pdata["OTHERS"].append(fn)
1963 self.othersAdded(fn) 2081 self.othersAdded(fn)
1964 self.setDirty(True) 2082 self.setDirty(True)
1965 2083
1966 if os.path.isdir(fn) and fn not in self.otherssubdirs: 2084 if os.path.isdir(fn) and fn not in self.otherssubdirs:
1967 self.otherssubdirs.append(fn) 2085 self.otherssubdirs.append(fn)
1968 2086
1969 def addSourceFiles(self):
1970 """
1971 Public slot to add source files to the current project.
1972 """
1973 self.addFiles("source")
1974
1975 def addUiFiles(self):
1976 """
1977 Public slot to add forms to the current project.
1978 """
1979 self.addFiles("form")
1980
1981 def addIdlFiles(self):
1982 """
1983 Public slot to add IDL interfaces to the current project.
1984 """
1985 self.addFiles("interface")
1986
1987 def addProtoFiles(self):
1988 """
1989 Public slot to add protocol files to the current project.
1990 """
1991 self.addFiles("protocol")
1992
1993 def addResourceFiles(self):
1994 """
1995 Public slot to add Qt resources to the current project.
1996 """
1997 self.addFiles("resource")
1998
1999 def addOthersFiles(self):
2000 """
2001 Public slot to add files to the OTHERS project data.
2002 """
2003 self.addFiles("others")
2004
2005 def addSourceDir(self):
2006 """
2007 Public slot to add all source files of a directory to the current
2008 project.
2009 """
2010 self.addDirectory("source")
2011
2012 def addUiDir(self):
2013 """
2014 Public slot to add all forms of a directory to the current project.
2015 """
2016 self.addDirectory("form")
2017
2018 def addIdlDir(self):
2019 """
2020 Public slot to add all IDL interfaces of a directory to the current
2021 project.
2022 """
2023 self.addDirectory("interface")
2024
2025 def addProtoDir(self):
2026 """
2027 Public slot to add all protocol files of a directory to the current
2028 project.
2029 """
2030 self.addDirectory("protocol")
2031
2032 def addResourceDir(self):
2033 """
2034 Public slot to add all Qt resource files of a directory to the current
2035 project.
2036 """
2037 self.addDirectory("resource")
2038
2039 def addOthersDir(self):
2040 """
2041 Public slot to add a directory to the OTHERS project data.
2042 """
2043 self.addDirectory("others")
2044
2045 def renameMainScript(self, oldfn, newfn): 2087 def renameMainScript(self, oldfn, newfn):
2046 """ 2088 """
2047 Public method to rename the main script. 2089 Public method to rename the main script.
2048 2090
2049 @param oldfn old filename (string) 2091 @param oldfn old filename (string)
2050 @param newfn new filename of the main script (string) 2092 @param newfn new filename of the main script (string)
2051 """ 2093 """
2052 if self.pdata["MAINSCRIPT"]: 2094 if self.__pdata["MAINSCRIPT"]:
2053 ofn = self.getRelativePath(oldfn) 2095 ofn = self.getRelativePath(oldfn)
2054 if ofn != self.pdata["MAINSCRIPT"]: 2096 if ofn != self.__pdata["MAINSCRIPT"]:
2055 return 2097 return
2056 2098
2057 fn = self.getRelativePath(newfn) 2099 fn = self.getRelativePath(newfn)
2058 self.pdata["MAINSCRIPT"] = fn 2100 self.__pdata["MAINSCRIPT"] = fn
2059 self.setDirty(True) 2101 self.setDirty(True)
2060 2102
2061 def renameFile(self, oldfn, newfn=None): 2103 def renameFile(self, oldfn, newfn=None):
2062 """ 2104 """
2063 Public slot to rename a file of the project. 2105 Public slot to rename a file of the project.
2065 @param oldfn old filename of the file (string) 2107 @param oldfn old filename of the file (string)
2066 @param newfn new filename of the file (string) 2108 @param newfn new filename of the file (string)
2067 @return flag indicating success 2109 @return flag indicating success
2068 """ 2110 """
2069 fn = self.getRelativePath(oldfn) 2111 fn = self.getRelativePath(oldfn)
2070 isSourceFile = fn in self.pdata["SOURCES"] 2112 isSourceFile = fn in self.__pdata["SOURCES"]
2071 2113
2072 if newfn is None: 2114 if newfn is None:
2073 newfn = EricFileDialog.getSaveFileName( 2115 newfn = EricFileDialog.getSaveFileName(
2074 None, 2116 None,
2075 self.tr("Rename file"), 2117 self.tr("Rename file"),
2105 """Reason: {1}</p>""" 2147 """Reason: {1}</p>"""
2106 ).format(oldfn, str(msg)), 2148 ).format(oldfn, str(msg)),
2107 ) 2149 )
2108 return False 2150 return False
2109 2151
2110 if ( 2152 if any(fn in self.__pdata[category] for category in self.getFileCategories()):
2111 fn in self.pdata["SOURCES"]
2112 or fn in self.pdata["FORMS"]
2113 or fn in self.pdata["TRANSLATIONS"]
2114 or fn in self.pdata["INTERFACES"]
2115 or fn in self.pdata["PROTOCOLS"]
2116 or fn in self.pdata["RESOURCES"]
2117 or fn in self.pdata["OTHERS"]
2118 ):
2119 self.renameFileInPdata(oldfn, newfn, isSourceFile) 2153 self.renameFileInPdata(oldfn, newfn, isSourceFile)
2120 2154
2121 return True 2155 return True
2122 2156
2123 def renameFileInPdata(self, oldname, newname, isSourceFile=False): 2157 def renameFileInPdata(self, oldname, newname, isSourceFile=False):
2124 """ 2158 """
2125 Public method to rename a file in the pdata structure. 2159 Public method to rename a file in the __pdata structure.
2126 2160
2127 @param oldname old filename (string) 2161 @param oldname old filename (string)
2128 @param newname new filename (string) 2162 @param newname new filename (string)
2129 @param isSourceFile flag indicating that this is a source file 2163 @param isSourceFile flag indicating that this is a source file
2130 even if it doesn't have the source extension (boolean) 2164 even if it doesn't have the source extension (boolean)
2149 @param start prefix (string) 2183 @param start prefix (string)
2150 @return list of files starting with a common prefix (list of strings) 2184 @return list of files starting with a common prefix (list of strings)
2151 """ 2185 """
2152 filelist = [] 2186 filelist = []
2153 start = self.getRelativePath(start) 2187 start = self.getRelativePath(start)
2154 for key in [ 2188 for fileCategory in [
2155 "SOURCES", 2189 c for c in self.getFileCategories() if c != "TRANSLATIONS"
2156 "FORMS",
2157 "INTERFACES",
2158 "PROTOCOLS",
2159 "RESOURCES",
2160 "OTHERS",
2161 ]: 2190 ]:
2162 for entry in self.pdata[key][:]: 2191 for entry in self.__pdata[fileCategory][:]:
2163 if entry.startswith(start): 2192 if entry.startswith(start):
2164 filelist.append(os.path.join(self.ppath, entry)) 2193 filelist.append(os.path.join(self.ppath, entry))
2165 return filelist 2194 return filelist
2166 2195
2167 def __reorganizeFiles(self): 2196 def __reorganizeFiles(self):
2170 """ 2199 """
2171 reorganized = False 2200 reorganized = False
2172 2201
2173 # init data store for the reorganization 2202 # init data store for the reorganization
2174 newPdata = {} 2203 newPdata = {}
2175 for key in [ 2204 for fileCategory in self.getFileCategories():
2176 "SOURCES", 2205 newPdata[fileCategory] = []
2177 "FORMS",
2178 "INTERFACES",
2179 "PROTOCOLS",
2180 "RESOURCES",
2181 "OTHERS",
2182 "TRANSLATIONS",
2183 ]:
2184 newPdata[key] = []
2185 2206
2186 # iterate over all files checking for a reassignment 2207 # iterate over all files checking for a reassignment
2187 for key in [ 2208 for fileCategory in self.getFileCategories():
2188 "SOURCES", 2209 for fn in self.__pdata[fileCategory][:]:
2189 "FORMS", 2210 filetype = fileCategory
2190 "INTERFACES",
2191 "PROTOCOLS",
2192 "RESOURCES",
2193 "OTHERS",
2194 "TRANSLATIONS",
2195 ]:
2196 for fn in self.pdata[key][:]:
2197 filetype = key
2198 bfn = os.path.basename(fn) 2211 bfn = os.path.basename(fn)
2199 for pattern in sorted(self.pdata["FILETYPES"].keys(), reverse=True): 2212 for pattern in sorted(self.__pdata["FILETYPES"].keys(), reverse=True):
2200 if fnmatch.fnmatch(bfn, pattern): 2213 if fnmatch.fnmatch(bfn, pattern):
2201 filetype = self.pdata["FILETYPES"][pattern] 2214 filetype = self.__pdata["FILETYPES"][pattern]
2202 break 2215 break
2203 2216
2204 if filetype != "__IGNORE__": 2217 if filetype != "__IGNORE__":
2205 newPdata[filetype].append(fn) 2218 newPdata[filetype].append(fn)
2206 if filetype != key: 2219 if filetype != fileCategory:
2207 reorganized = True 2220 reorganized = True
2208 2221
2209 if reorganized: 2222 if reorganized:
2210 # copy the reorganized files back to the project 2223 # copy the reorganized files back to the project
2211 for key in [ 2224 ##for key in [
2212 "SOURCES", 2225 ##"SOURCES",
2213 "FORMS", 2226 ##"FORMS",
2214 "INTERFACES", 2227 ##"INTERFACES",
2215 "PROTOCOLS", 2228 ##"PROTOCOLS",
2216 "RESOURCES", 2229 ##"RESOURCES",
2217 "OTHERS", 2230 ##"OTHERS",
2218 "TRANSLATIONS", 2231 ##"TRANSLATIONS",
2219 ]: 2232 ##]:
2220 self.pdata[key] = newPdata[key][:] 2233 for fileCategory in self.getFileCategories():
2234 self.__pdata[fileCategory] = newPdata[fileCategory][:]
2221 2235
2222 # repopulate the model 2236 # repopulate the model
2223 self.__model.projectClosed(False) 2237 self.__model.projectClosed(False)
2224 self.__model.projectOpened() 2238 self.__model.projectOpened()
2225 2239
2230 @param olddn original directory name (string) 2244 @param olddn original directory name (string)
2231 @param newdn new directory name (string) 2245 @param newdn new directory name (string)
2232 """ 2246 """
2233 olddn = self.getRelativePath(olddn) 2247 olddn = self.getRelativePath(olddn)
2234 newdn = self.getRelativePath(newdn) 2248 newdn = self.getRelativePath(newdn)
2235 for key in [ 2249 ##for key in [
2236 "SOURCES", 2250 ##"SOURCES",
2237 "FORMS", 2251 ##"FORMS",
2238 "INTERFACES", 2252 ##"INTERFACES",
2239 "PROTOCOLS", 2253 ##"PROTOCOLS",
2240 "RESOURCES", 2254 ##"RESOURCES",
2241 "OTHERS", 2255 ##"OTHERS",
2256 ##]:
2257 for fileCategory in [
2258 c for c in self.getFileCategories() if c != "TRANSLATIONS"
2242 ]: 2259 ]:
2243 for entry in self.pdata[key][:]: 2260 for entry in self.__pdata[fileCategory][:]:
2244 if entry.startswith(olddn): 2261 if entry.startswith(olddn):
2245 entry = entry.replace(olddn, newdn) 2262 entry = entry.replace(olddn, newdn)
2246 self.appendFile(os.path.join(self.ppath, entry), key == "SOURCES") 2263 self.appendFile(
2264 os.path.join(self.ppath, entry), fileCategory == "SOURCES"
2265 )
2247 self.setDirty(True) 2266 self.setDirty(True)
2248 2267
2249 def moveDirectory(self, olddn, newdn): 2268 def moveDirectory(self, olddn, newdn):
2250 """ 2269 """
2251 Public slot to move a directory. 2270 Public slot to move a directory.
2254 @param newdn new directory name (string) 2273 @param newdn new directory name (string)
2255 """ 2274 """
2256 olddn = self.getRelativePath(olddn) 2275 olddn = self.getRelativePath(olddn)
2257 newdn = self.getRelativePath(newdn) 2276 newdn = self.getRelativePath(newdn)
2258 typeStrings = [] 2277 typeStrings = []
2259 for key in [ 2278 ##for key in [
2260 "SOURCES", 2279 ##"SOURCES",
2261 "FORMS", 2280 ##"FORMS",
2262 "INTERFACES", 2281 ##"INTERFACES",
2263 "PROTOCOLS", 2282 ##"PROTOCOLS",
2264 "RESOURCES", 2283 ##"RESOURCES",
2265 "OTHERS", 2284 ##"OTHERS",
2285 ##]:
2286 for fileCategory in [
2287 c for c in self.getFileCategories() if c != "TRANSLATIONS"
2266 ]: 2288 ]:
2267 for entry in self.pdata[key][:]: 2289 for entry in self.__pdata[fileCategory][:]:
2268 if entry.startswith(olddn): 2290 if entry.startswith(olddn):
2269 if key not in typeStrings: 2291 if fileCategory not in typeStrings:
2270 typeStrings.append(key) 2292 typeStrings.append(fileCategory)
2271 self.pdata[key].remove(entry) 2293 self.__pdata[fileCategory].remove(entry)
2272 entry = entry.replace(olddn, newdn) 2294 entry = entry.replace(olddn, newdn)
2273 self.pdata[key].append(entry) 2295 self.__pdata[fileCategory].append(entry)
2274 if key == "OTHERS": 2296 if fileCategory == "OTHERS":
2275 if newdn not in self.otherssubdirs: 2297 if newdn not in self.otherssubdirs:
2276 self.otherssubdirs.append(newdn) 2298 self.otherssubdirs.append(newdn)
2277 else: 2299 else:
2278 if newdn not in self.subdirs: 2300 if newdn not in self.subdirs:
2279 self.subdirs.append(newdn) 2301 self.subdirs.append(newdn)
2297 @param fn filename to be removed from the project 2319 @param fn filename to be removed from the project
2298 @param updateModel flag indicating an update of the model is 2320 @param updateModel flag indicating an update of the model is
2299 requested (boolean) 2321 requested (boolean)
2300 """ 2322 """
2301 fn = self.getRelativePath(fn) 2323 fn = self.getRelativePath(fn)
2302 dirty = True 2324 for fileCategory in self.getFileCategories():
2303 if fn in self.pdata["SOURCES"]: 2325 if fn in self.__pdata[fileCategory]:
2304 self.pdata["SOURCES"].remove(fn) 2326 self.__pdata[fileCategory].remove(fn)
2305 self.projectSourceRemoved.emit(fn) 2327 self.projectFileRemoved.emit(fn, fileCategory)
2306 elif fn in self.pdata["FORMS"]: 2328 self.setDirty(True)
2307 self.pdata["FORMS"].remove(fn) 2329 if updateModel:
2308 self.projectFormRemoved.emit(fn) 2330 self.__model.removeItem(fn)
2309 elif fn in self.pdata["INTERFACES"]: 2331 break
2310 self.pdata["INTERFACES"].remove(fn)
2311 self.projectInterfaceRemoved.emit(fn)
2312 elif fn in self.pdata["PROTOCOLS"]:
2313 self.pdata["PROTOCOLS"].remove(fn)
2314 self.projectProtocolRemoved.emit(fn)
2315 elif fn in self.pdata["RESOURCES"]:
2316 self.pdata["RESOURCES"].remove(fn)
2317 self.projectResourceRemoved.emit(fn)
2318 elif fn in self.pdata["OTHERS"]:
2319 self.pdata["OTHERS"].remove(fn)
2320 self.projectOthersRemoved.emit(fn)
2321 elif fn in self.pdata["TRANSLATIONS"]:
2322 self.pdata["TRANSLATIONS"].remove(fn)
2323 self.projectLanguageRemoved.emit(fn)
2324 else:
2325 dirty = False
2326 updateModel and self.__model.removeItem(fn)
2327 if dirty:
2328 self.setDirty(True)
2329 2332
2330 def removeDirectory(self, dn): 2333 def removeDirectory(self, dn):
2331 """ 2334 """
2332 Public method to remove a directory from the project. 2335 Public method to remove a directory from the project.
2333 2336
2335 2338
2336 @param dn directory name to be removed from the project 2339 @param dn directory name to be removed from the project
2337 """ 2340 """
2338 dirty = False 2341 dirty = False
2339 dn = self.getRelativePath(dn) 2342 dn = self.getRelativePath(dn)
2340 for entry in self.pdata["OTHERS"][:]: 2343 for entry in self.__pdata["OTHERS"][:]:
2341 if entry.startswith(dn): 2344 if entry.startswith(dn):
2342 self.pdata["OTHERS"].remove(entry) 2345 self.__pdata["OTHERS"].remove(entry)
2343 dirty = True 2346 dirty = True
2344 dn2 = dn if dn.endswith(os.sep) else dn + os.sep 2347 dn2 = dn if dn.endswith(os.sep) else dn + os.sep
2345 for key in [ 2348 for fileCategory in [c for c in self.getFileCategories() if c != "OTHERS"]:
2346 "SOURCES", 2349 for entry in self.__pdata[fileCategory][:]:
2347 "FORMS",
2348 "INTERFACES",
2349 "PROTOCOLS",
2350 "RESOURCES",
2351 "TRANSLATIONS",
2352 ]:
2353 for entry in self.pdata[key][:]:
2354 if entry.startswith(dn2): 2350 if entry.startswith(dn2):
2355 self.pdata[key].remove(entry) 2351 self.__pdata[fileCategory].remove(entry)
2356 dirty = True 2352 dirty = True
2357 self.__model.removeItem(dn) 2353 self.__model.removeItem(dn)
2358 if dirty: 2354 if dirty:
2359 self.setDirty(True) 2355 self.setDirty(True)
2360 self.directoryRemoved.emit(dn) 2356 self.directoryRemoved.emit(dn)
2365 2361
2366 @param fn filename to be deleted from the project 2362 @param fn filename to be deleted from the project
2367 @return flag indicating success (boolean) 2363 @return flag indicating success (boolean)
2368 """ 2364 """
2369 try: 2365 try:
2370 from send2trash import send2trash as s2t 2366 from send2trash import send2trash as s2t # __IGNORE_WARNING_I10__
2371 except ImportError: 2367 except ImportError:
2372 s2t = os.remove 2368 s2t = os.remove
2373 2369
2374 try: 2370 try:
2375 s2t(os.path.join(self.ppath, fn)) 2371 s2t(os.path.join(self.ppath, fn))
2413 """ 2409 """
2414 if not os.path.isabs(dn): 2410 if not os.path.isabs(dn):
2415 dn = os.path.join(self.ppath, dn) 2411 dn = os.path.join(self.ppath, dn)
2416 try: 2412 try:
2417 try: 2413 try:
2418 from send2trash import send2trash 2414 from send2trash import send2trash # __IGNORE_WARNING_I10__
2419 2415
2420 send2trash(dn) 2416 send2trash(dn)
2421 except ImportError: 2417 except ImportError:
2422 shutil.rmtree(dn, True) 2418 shutil.rmtree(dn, True)
2423 except OSError as err: 2419 except OSError as err:
2440 2436
2441 @param fn filename to be checked (string) 2437 @param fn filename to be checked (string)
2442 @return flag indicating, if the project contains the file (boolean) 2438 @return flag indicating, if the project contains the file (boolean)
2443 """ 2439 """
2444 fn = self.getRelativePath(fn) 2440 fn = self.getRelativePath(fn)
2445 return ( 2441 return any(
2446 fn in self.pdata["SOURCES"] 2442 fn in self.__pdata[category]
2447 or fn in self.pdata["FORMS"] 2443 for category in self.getFileCategories()
2448 or fn in self.pdata["INTERFACES"] 2444 if category != "TRANSLATIONS"
2449 or fn in self.pdata["PROTOCOLS"]
2450 or fn in self.pdata["RESOURCES"]
2451 or fn in self.pdata["OTHERS"]
2452 ) 2445 )
2453 2446
2454 def createNewProject(self): 2447 def createNewProject(self):
2455 """ 2448 """
2456 Public slot to built a new project. 2449 Public slot to built a new project.
2457 2450
2458 This method displays the new project dialog and initializes 2451 This method displays the new project dialog and initializes
2459 the project object with the data entered. 2452 the project object with the data entered.
2460 """ 2453 """
2454 from eric7.VCS.CommandOptionsDialog import VcsCommandOptionsDialog
2455
2456 from .PropertiesDialog import PropertiesDialog
2457
2461 if not self.checkDirty(): 2458 if not self.checkDirty():
2462 return 2459 return
2463
2464 from .PropertiesDialog import PropertiesDialog
2465 2460
2466 dlg = PropertiesDialog(self, True) 2461 dlg = PropertiesDialog(self, True)
2467 if dlg.exec() == QDialog.DialogCode.Accepted: 2462 if dlg.exec() == QDialog.DialogCode.Accepted:
2468 self.closeProject() 2463 self.closeProject()
2469 dlg.storeData() 2464 dlg.storeData()
2470 self.pdata["VCS"] = "None" 2465 self.__pdata["VCS"] = "None"
2471 self.opened = True 2466 self.opened = True
2472 if not self.pdata["FILETYPES"]: 2467 if not self.__pdata["FILETYPES"]:
2473 self.initFileTypes() 2468 self.initFileTypes()
2474 self.setDirty(True) 2469 self.setDirty(True)
2470 self.reloadAct.setEnabled(True)
2475 self.closeAct.setEnabled(True) 2471 self.closeAct.setEnabled(True)
2476 self.saveasAct.setEnabled(True) 2472 self.saveasAct.setEnabled(True)
2477 self.actGrp2.setEnabled(True) 2473 self.actGrp2.setEnabled(True)
2478 self.propsAct.setEnabled(True) 2474 self.propsAct.setEnabled(True)
2479 self.userPropsAct.setEnabled(True) 2475 self.userPropsAct.setEnabled(True)
2486 self.menuCheckAct.setEnabled(True) 2482 self.menuCheckAct.setEnabled(True)
2487 self.menuShowAct.setEnabled(True) 2483 self.menuShowAct.setEnabled(True)
2488 self.menuDiagramAct.setEnabled(True) 2484 self.menuDiagramAct.setEnabled(True)
2489 self.menuApidocAct.setEnabled(True) 2485 self.menuApidocAct.setEnabled(True)
2490 self.menuPackagersAct.setEnabled(True) 2486 self.menuPackagersAct.setEnabled(True)
2491 self.pluginGrp.setEnabled(self.pdata["PROJECTTYPE"] in ["E7Plugin"]) 2487 self.pluginGrp.setEnabled(self.__pdata["PROJECTTYPE"] in ["E7Plugin"])
2492 self.addLanguageAct.setEnabled(bool(self.pdata["TRANSLATIONPATTERN"])) 2488 self.addLanguageAct.setEnabled(bool(self.__pdata["TRANSLATIONPATTERN"]))
2493 self.makeGrp.setEnabled(self.pdata["MAKEPARAMS"]["MakeEnabled"]) 2489 self.makeGrp.setEnabled(self.__pdata["MAKEPARAMS"]["MakeEnabled"])
2494 self.menuMakeAct.setEnabled(self.pdata["MAKEPARAMS"]["MakeEnabled"]) 2490 self.menuMakeAct.setEnabled(self.__pdata["MAKEPARAMS"]["MakeEnabled"])
2495 self.menuOtherToolsAct.setEnabled(True) 2491 self.menuOtherToolsAct.setEnabled(True)
2496 self.menuFormattingAct.setEnabled(True) 2492 self.menuFormattingAct.setEnabled(True)
2497 2493
2498 self.projectAboutToBeCreated.emit() 2494 self.projectAboutToBeCreated.emit()
2499 2495
2502 QByteArray(self.ppath.encode("utf-8")), 2498 QByteArray(self.ppath.encode("utf-8")),
2503 QCryptographicHash.Algorithm.Sha1, 2499 QCryptographicHash.Algorithm.Sha1,
2504 ).toHex(), 2500 ).toHex(),
2505 encoding="utf-8", 2501 encoding="utf-8",
2506 ) 2502 )
2507 self.pdata["HASH"] = hashStr 2503 self.__pdata["HASH"] = hashStr
2508 2504
2509 if self.pdata["PROGLANGUAGE"] == "MicroPython": 2505 if self.__pdata["PROGLANGUAGE"] == "MicroPython":
2510 # change the lexer association for *.py files 2506 # change the lexer association for *.py files
2511 self.pdata["LEXERASSOCS"] = { 2507 self.__pdata["LEXERASSOCS"] = {
2512 "*.py": "MicroPython", 2508 "*.py": "MicroPython",
2513 } 2509 }
2514 2510
2515 # create the project directory if it doesn't exist already 2511 # create the project directory if it doesn't exist already
2516 if not os.path.isdir(self.ppath): 2512 if not os.path.isdir(self.ppath):
2528 self.vcs = self.initVCS() 2524 self.vcs = self.initVCS()
2529 return 2525 return
2530 2526
2531 # create an empty __init__.py file to make it a Python package 2527 # create an empty __init__.py file to make it a Python package
2532 # (only for Python and Python3) 2528 # (only for Python and Python3)
2533 if self.pdata["PROGLANGUAGE"] in ["Python3", "MicroPython"]: 2529 if self.__pdata["PROGLANGUAGE"] in ["Python3", "MicroPython"]:
2534 fn = os.path.join(self.ppath, "__init__.py") 2530 fn = os.path.join(self.ppath, "__init__.py")
2535 with open(fn, "w", encoding="utf-8"): 2531 with open(fn, "w", encoding="utf-8"):
2536 pass 2532 pass
2537 self.appendFile(fn, True) 2533 self.appendFile(fn, True)
2538 2534
2539 # create an empty main script file, if a name was given 2535 # create an empty main script file, if a name was given
2540 if self.pdata["MAINSCRIPT"]: 2536 if self.__pdata["MAINSCRIPT"]:
2541 if not os.path.isabs(self.pdata["MAINSCRIPT"]): 2537 if not os.path.isabs(self.__pdata["MAINSCRIPT"]):
2542 ms = os.path.join(self.ppath, self.pdata["MAINSCRIPT"]) 2538 ms = os.path.join(self.ppath, self.__pdata["MAINSCRIPT"])
2543 else: 2539 else:
2544 ms = self.pdata["MAINSCRIPT"] 2540 ms = self.__pdata["MAINSCRIPT"]
2545 os.makedirs(os.path.dirname(ms), exist_ok=True) 2541 os.makedirs(os.path.dirname(ms), exist_ok=True)
2546 with open(ms, "w"): 2542 with open(ms, "w"):
2547 pass 2543 pass
2548 self.appendFile(ms, True) 2544 self.appendFile(ms, True)
2549 2545
2550 if self.pdata["MAKEPARAMS"]["MakeEnabled"]: 2546 if self.__pdata["MAKEPARAMS"]["MakeEnabled"]:
2551 mf = self.pdata["MAKEPARAMS"]["MakeFile"] 2547 mf = self.__pdata["MAKEPARAMS"]["MakeFile"]
2552 if mf: 2548 if mf:
2553 if not os.path.isabs(mf): 2549 if not os.path.isabs(mf):
2554 mf = os.path.join(self.ppath, mf) 2550 mf = os.path.join(self.ppath, mf)
2555 else: 2551 else:
2556 mf = os.path.join(self.ppath, Project.DefaultMakefile) 2552 mf = os.path.join(self.ppath, Project.DefaultMakefile)
2562 tpd = os.path.join(self.ppath, self.translationsRoot) 2558 tpd = os.path.join(self.ppath, self.translationsRoot)
2563 if not self.translationsRoot.endswith(os.sep): 2559 if not self.translationsRoot.endswith(os.sep):
2564 tpd = os.path.dirname(tpd) 2560 tpd = os.path.dirname(tpd)
2565 if not os.path.isdir(tpd): 2561 if not os.path.isdir(tpd):
2566 os.makedirs(tpd, exist_ok=True) 2562 os.makedirs(tpd, exist_ok=True)
2567 if self.pdata["TRANSLATIONSBINPATH"]: 2563 if self.__pdata["TRANSLATIONSBINPATH"]:
2568 tpd = os.path.join(self.ppath, self.pdata["TRANSLATIONSBINPATH"]) 2564 tpd = os.path.join(self.ppath, self.__pdata["TRANSLATIONSBINPATH"])
2569 if not os.path.isdir(tpd): 2565 if not os.path.isdir(tpd):
2570 os.makedirs(tpd, exist_ok=True) 2566 os.makedirs(tpd, exist_ok=True)
2571 2567
2572 # create management directory if not present 2568 # create management directory if not present
2573 self.createProjectManagementDir() 2569 self.createProjectManagementDir()
2587 " writable.</p>" 2583 " writable.</p>"
2588 ).format(self.ppath), 2584 ).format(self.ppath),
2589 ) 2585 )
2590 return 2586 return
2591 2587
2592 if self.pdata["MAINSCRIPT"]: 2588 if self.__pdata["MAINSCRIPT"]:
2593 if not os.path.isabs(self.pdata["MAINSCRIPT"]): 2589 if not os.path.isabs(self.__pdata["MAINSCRIPT"]):
2594 ms = os.path.join(self.ppath, self.pdata["MAINSCRIPT"]) 2590 ms = os.path.join(self.ppath, self.__pdata["MAINSCRIPT"])
2595 else: 2591 else:
2596 ms = self.pdata["MAINSCRIPT"] 2592 ms = self.__pdata["MAINSCRIPT"]
2597 if not os.path.exists(ms): 2593 if not os.path.exists(ms):
2598 try: 2594 try:
2599 os.makedirs(os.path.dirname(ms)) 2595 os.makedirs(os.path.dirname(ms))
2600 with open(ms, "w"): 2596 with open(ms, "w"):
2601 pass 2597 pass
2610 ) 2606 )
2611 self.appendFile(ms, True) 2607 self.appendFile(ms, True)
2612 else: 2608 else:
2613 ms = "" 2609 ms = ""
2614 2610
2615 if self.pdata["MAKEPARAMS"]["MakeEnabled"]: 2611 if self.__pdata["MAKEPARAMS"]["MakeEnabled"]:
2616 mf = self.pdata["MAKEPARAMS"]["MakeFile"] 2612 mf = self.__pdata["MAKEPARAMS"]["MakeFile"]
2617 if mf: 2613 if mf:
2618 if not os.path.isabs(mf): 2614 if not os.path.isabs(mf):
2619 mf = os.path.join(self.ppath, mf) 2615 mf = os.path.join(self.ppath, mf)
2620 else: 2616 else:
2621 mf = os.path.join(self.ppath, Project.DefaultMakefile) 2617 mf = os.path.join(self.ppath, Project.DefaultMakefile)
2645 if res: 2641 if res:
2646 self.newProjectAddFiles(ms) 2642 self.newProjectAddFiles(ms)
2647 addAllToVcs = res 2643 addAllToVcs = res
2648 # create an empty __init__.py file to make it a Python package 2644 # create an empty __init__.py file to make it a Python package
2649 # if none exists (only for Python and Python3) 2645 # if none exists (only for Python and Python3)
2650 if self.pdata["PROGLANGUAGE"] in ["Python3", "MicroPython"]: 2646 if self.__pdata["PROGLANGUAGE"] in ["Python3", "MicroPython"]:
2651 fn = os.path.join(self.ppath, "__init__.py") 2647 fn = os.path.join(self.ppath, "__init__.py")
2652 if not os.path.exists(fn): 2648 if not os.path.exists(fn):
2653 with open(fn, "w", encoding="utf-8"): 2649 with open(fn, "w", encoding="utf-8"):
2654 pass 2650 pass
2655 self.appendFile(fn, True) 2651 self.appendFile(fn, True)
2683 vcsSystem = "None" 2679 vcsSystem = "None"
2684 else: 2680 else:
2685 vcsSystem = "None" 2681 vcsSystem = "None"
2686 else: 2682 else:
2687 vcsSystem = vcsData[0][1] 2683 vcsSystem = vcsData[0][1]
2688 self.pdata["VCS"] = vcsSystem 2684 self.__pdata["VCS"] = vcsSystem
2689 self.vcs = self.initVCS() 2685 self.vcs = self.initVCS()
2690 self.setDirty(True) 2686 self.setDirty(True)
2691 if self.vcs is not None: 2687 if self.vcs is not None:
2692 # edit VCS command options 2688 # edit VCS command options
2693 if self.vcs.vcsSupportCommandOptions(): 2689 if self.vcs.vcsSupportCommandOptions():
2700 ), 2696 ),
2701 ) 2697 )
2702 else: 2698 else:
2703 vcores = False 2699 vcores = False
2704 if vcores: 2700 if vcores:
2705 from eric7.VCS.CommandOptionsDialog import (
2706 VcsCommandOptionsDialog,
2707 )
2708
2709 codlg = VcsCommandOptionsDialog(self.vcs) 2701 codlg = VcsCommandOptionsDialog(self.vcs)
2710 if codlg.exec() == QDialog.DialogCode.Accepted: 2702 if codlg.exec() == QDialog.DialogCode.Accepted:
2711 self.vcs.vcsSetOptions(codlg.getOptions()) 2703 self.vcs.vcsSetOptions(codlg.getOptions())
2712 # add project file to repository 2704 # add project file to repository
2713 if res == 0: 2705 if res == 0:
2722 ) 2714 )
2723 if apres: 2715 if apres:
2724 self.saveProject() 2716 self.saveProject()
2725 self.vcs.vcsAdd(self.pfile) 2717 self.vcs.vcsAdd(self.pfile)
2726 else: 2718 else:
2727 self.pdata["VCS"] = "None" 2719 self.__pdata["VCS"] = "None"
2728 self.saveProject() 2720 self.saveProject()
2729 break 2721 break
2730 2722
2731 # put the project under VCS control 2723 # put the project under VCS control
2732 if self.vcs is None and self.vcsSoftwareAvailable() and self.vcsRequested: 2724 if self.vcs is None and self.vcsSoftwareAvailable() and self.vcsRequested:
2748 False, 2740 False,
2749 ) 2741 )
2750 if ok and vcsSelected != self.tr("None"): 2742 if ok and vcsSelected != self.tr("None"):
2751 for vcsSystem, vcsSystemDisplay in vcsSystemsDict.items(): 2743 for vcsSystem, vcsSystemDisplay in vcsSystemsDict.items():
2752 if vcsSystemDisplay == vcsSelected: 2744 if vcsSystemDisplay == vcsSelected:
2753 self.pdata["VCS"] = vcsSystem 2745 self.__pdata["VCS"] = vcsSystem
2754 break 2746 break
2755 else: 2747 else:
2756 self.pdata["VCS"] = "None" 2748 self.__pdata["VCS"] = "None"
2757 else: 2749 else:
2758 self.pdata["VCS"] = "None" 2750 self.__pdata["VCS"] = "None"
2759 self.vcs = self.initVCS() 2751 self.vcs = self.initVCS()
2760 if self.vcs is not None: 2752 if self.vcs is not None:
2761 vcsdlg = self.vcs.vcsOptionsDialog(self, self.name) 2753 vcsdlg = self.vcs.vcsOptionsDialog(self, self.name)
2762 if vcsdlg.exec() == QDialog.DialogCode.Accepted: 2754 if vcsdlg.exec() == QDialog.DialogCode.Accepted:
2763 vcsDataDict = vcsdlg.getData() 2755 vcsDataDict = vcsdlg.getData()
2764 else: 2756 else:
2765 self.pdata["VCS"] = "None" 2757 self.__pdata["VCS"] = "None"
2766 self.vcs = self.initVCS() 2758 self.vcs = self.initVCS()
2767 self.setDirty(True) 2759 self.setDirty(True)
2768 if self.vcs is not None: 2760 if self.vcs is not None:
2769 # edit VCS command options 2761 # edit VCS command options
2770 if self.vcs.vcsSupportCommandOptions(): 2762 if self.vcs.vcsSupportCommandOptions():
2777 ), 2769 ),
2778 ) 2770 )
2779 else: 2771 else:
2780 vcores = False 2772 vcores = False
2781 if vcores: 2773 if vcores:
2782 from eric7.VCS.CommandOptionsDialog import (
2783 VcsCommandOptionsDialog,
2784 )
2785
2786 codlg = VcsCommandOptionsDialog(self.vcs) 2774 codlg = VcsCommandOptionsDialog(self.vcs)
2787 if codlg.exec() == QDialog.DialogCode.Accepted: 2775 if codlg.exec() == QDialog.DialogCode.Accepted:
2788 self.vcs.vcsSetOptions(codlg.getOptions()) 2776 self.vcs.vcsSetOptions(codlg.getOptions())
2789 2777
2790 # create the project in the VCS 2778 # create the project in the VCS
2797 2785
2798 else: 2786 else:
2799 self.newProjectHooks.emit() 2787 self.newProjectHooks.emit()
2800 self.newProject.emit() 2788 self.newProject.emit()
2801 2789
2802 if self.pdata["EMBEDDED_VENV"]: 2790 if self.__pdata["EMBEDDED_VENV"]:
2803 self.__createEmbeddedEnvironment() 2791 self.__createEmbeddedEnvironment()
2804 self.menuEnvironmentAct.setEnabled(self.pdata["EMBEDDED_VENV"]) 2792 self.menuEnvironmentAct.setEnabled(self.__pdata["EMBEDDED_VENV"])
2805 2793
2806 def newProjectAddFiles(self, mainscript): 2794 def newProjectAddFiles(self, mainscript):
2807 """ 2795 """
2808 Public method to add files to a new project. 2796 Public method to add files to a new project.
2809 2797
2812 # Show the file type associations for the user to change 2800 # Show the file type associations for the user to change
2813 self.__showFiletypeAssociations() 2801 self.__showFiletypeAssociations()
2814 2802
2815 with EricOverrideCursor(): 2803 with EricOverrideCursor():
2816 # search the project directory for files with known extensions 2804 # search the project directory for files with known extensions
2817 filespecs = list(self.pdata["FILETYPES"].keys()) 2805 filespecs = list(self.__pdata["FILETYPES"].keys())
2818 for filespec in filespecs: 2806 for filespec in filespecs:
2819 files = Utilities.direntries(self.ppath, True, filespec) 2807 files = Utilities.direntries(self.ppath, True, filespec)
2820 for file in files: 2808 for file in files:
2821 self.appendFile(file) 2809 self.appendFile(file)
2822 2810
2826 if not self.translationsRoot.endswith(os.sep): 2814 if not self.translationsRoot.endswith(os.sep):
2827 tpd = os.path.dirname(tpd) 2815 tpd = os.path.dirname(tpd)
2828 else: 2816 else:
2829 tpd = self.ppath 2817 tpd = self.ppath
2830 tslist = [] 2818 tslist = []
2831 if self.pdata["TRANSLATIONPATTERN"]: 2819 if self.__pdata["TRANSLATIONPATTERN"]:
2832 pattern = os.path.basename(self.pdata["TRANSLATIONPATTERN"]) 2820 pattern = os.path.basename(self.__pdata["TRANSLATIONPATTERN"])
2833 if "%language%" in pattern: 2821 if "%language%" in pattern:
2834 pattern = pattern.replace("%language%", "*") 2822 pattern = pattern.replace("%language%", "*")
2835 else: 2823 else:
2836 tpd = self.pdata["TRANSLATIONPATTERN"].split("%language%")[0] 2824 tpd = self.__pdata["TRANSLATIONPATTERN"].split("%language%")[0]
2837 else: 2825 else:
2838 pattern = "*.ts" 2826 pattern = "*.ts"
2839 tslist.extend(Utilities.direntries(tpd, True, pattern)) 2827 tslist.extend(Utilities.direntries(tpd, True, pattern))
2840 pattern = self.__binaryTranslationFile(pattern) 2828 pattern = self.__binaryTranslationFile(pattern)
2841 if pattern: 2829 if pattern:
2845 # the first entry determines the mainscript name 2833 # the first entry determines the mainscript name
2846 mainscriptname = ( 2834 mainscriptname = (
2847 os.path.splitext(mainscript)[0] 2835 os.path.splitext(mainscript)[0]
2848 or os.path.basename(tslist[0]).split("_")[0] 2836 or os.path.basename(tslist[0]).split("_")[0]
2849 ) 2837 )
2850 self.pdata["TRANSLATIONPATTERN"] = os.path.join( 2838 self.__pdata["TRANSLATIONPATTERN"] = os.path.join(
2851 os.path.dirname(tslist[0]), 2839 os.path.dirname(tslist[0]),
2852 "{0}_%language%{1}".format( 2840 "{0}_%language%{1}".format(
2853 os.path.basename(tslist[0]).split("_")[0], 2841 os.path.basename(tslist[0]).split("_")[0],
2854 os.path.splitext(tslist[0])[1], 2842 os.path.splitext(tslist[0])[1],
2855 ), 2843 ),
2866 ), 2854 ),
2867 QLineEdit.EchoMode.Normal, 2855 QLineEdit.EchoMode.Normal,
2868 tslist[0], 2856 tslist[0],
2869 ) 2857 )
2870 if pattern: 2858 if pattern:
2871 self.pdata["TRANSLATIONPATTERN"] = pattern 2859 self.__pdata["TRANSLATIONPATTERN"] = pattern
2872 if self.pdata["TRANSLATIONPATTERN"]: 2860 if self.__pdata["TRANSLATIONPATTERN"]:
2873 self.pdata["TRANSLATIONPATTERN"] = self.getRelativePath( 2861 self.__pdata["TRANSLATIONPATTERN"] = self.getRelativePath(
2874 self.pdata["TRANSLATIONPATTERN"] 2862 self.__pdata["TRANSLATIONPATTERN"]
2875 ) 2863 )
2876 pattern = self.pdata["TRANSLATIONPATTERN"].replace( 2864 pattern = self.__pdata["TRANSLATIONPATTERN"].replace(
2877 "%language%", "*" 2865 "%language%", "*"
2878 ) 2866 )
2879 for ts in tslist: 2867 for ts in tslist:
2880 if fnmatch.fnmatch(ts, pattern): 2868 if fnmatch.fnmatch(ts, pattern):
2881 self.pdata["TRANSLATIONS"].append(ts) 2869 self.__pdata["TRANSLATIONS"].append(ts)
2882 self.projectLanguageAdded.emit(ts) 2870 self.projectFileAdded.emit(ts, "TRANSLATIONS")
2883 if self.pdata["TRANSLATIONSBINPATH"]: 2871 if self.__pdata["TRANSLATIONSBINPATH"]:
2884 tpd = os.path.join( 2872 tpd = os.path.join(
2885 self.ppath, self.pdata["TRANSLATIONSBINPATH"] 2873 self.ppath, self.__pdata["TRANSLATIONSBINPATH"]
2886 ) 2874 )
2887 pattern = os.path.basename( 2875 pattern = os.path.basename(
2888 self.pdata["TRANSLATIONPATTERN"] 2876 self.__pdata["TRANSLATIONPATTERN"]
2889 ).replace("%language%", "*") 2877 ).replace("%language%", "*")
2890 pattern = self.__binaryTranslationFile(pattern) 2878 pattern = self.__binaryTranslationFile(pattern)
2891 qmlist = Utilities.direntries(tpd, True, pattern) 2879 qmlist = Utilities.direntries(tpd, True, pattern)
2892 for qm in qmlist: 2880 for qm in qmlist:
2893 self.pdata["TRANSLATIONS"].append(qm) 2881 self.__pdata["TRANSLATIONS"].append(qm)
2894 self.projectLanguageAdded.emit(qm) 2882 self.projectFileAdded.emit(qm, "TRANSLATIONS")
2895 if not self.pdata["MAINSCRIPT"] and bool(mainscriptname): 2883 if not self.__pdata["MAINSCRIPT"] and bool(mainscriptname):
2896 if self.pdata["PROGLANGUAGE"] in ["Python3", "MicroPython"]: 2884 if self.__pdata["PROGLANGUAGE"] in ["Python3", "MicroPython"]:
2897 self.pdata["MAINSCRIPT"] = "{0}.py".format(mainscriptname) 2885 self.__pdata["MAINSCRIPT"] = "{0}.py".format(mainscriptname)
2898 elif self.pdata["PROGLANGUAGE"] == "Ruby": 2886 elif self.__pdata["PROGLANGUAGE"] == "Ruby":
2899 self.pdata["MAINSCRIPT"] = "{0}.rb".format(mainscriptname) 2887 self.__pdata["MAINSCRIPT"] = "{0}.rb".format(mainscriptname)
2900 self.setDirty(True) 2888 self.setDirty(True)
2901 2889
2902 def __showProperties(self): 2890 def __showProperties(self):
2903 """ 2891 """
2904 Private slot to display the properties dialog. 2892 Private slot to display the properties dialog.
2905 """ 2893 """
2906 from .PropertiesDialog import PropertiesDialog 2894 from .PropertiesDialog import PropertiesDialog
2907 2895
2908 dlg = PropertiesDialog(self, False) 2896 dlg = PropertiesDialog(self, False)
2909 if dlg.exec() == QDialog.DialogCode.Accepted: 2897 if dlg.exec() == QDialog.DialogCode.Accepted:
2910 projectType = self.pdata["PROJECTTYPE"] 2898 projectType = self.__pdata["PROJECTTYPE"]
2911 dlg.storeData() 2899 dlg.storeData()
2912 self.setDirty(True) 2900 self.setDirty(True)
2913 if self.pdata["MAINSCRIPT"]: 2901 if self.__pdata["MAINSCRIPT"]:
2914 if not os.path.isabs(self.pdata["MAINSCRIPT"]): 2902 if not os.path.isabs(self.__pdata["MAINSCRIPT"]):
2915 ms = os.path.join(self.ppath, self.pdata["MAINSCRIPT"]) 2903 ms = os.path.join(self.ppath, self.__pdata["MAINSCRIPT"])
2916 else: 2904 else:
2917 ms = self.pdata["MAINSCRIPT"] 2905 ms = self.__pdata["MAINSCRIPT"]
2918 if os.path.exists(ms): 2906 if os.path.exists(ms):
2919 self.appendFile(ms) 2907 self.appendFile(ms)
2920 2908
2921 if self.pdata["MAKEPARAMS"]["MakeEnabled"]: 2909 if self.__pdata["MAKEPARAMS"]["MakeEnabled"]:
2922 mf = self.pdata["MAKEPARAMS"]["MakeFile"] 2910 mf = self.__pdata["MAKEPARAMS"]["MakeFile"]
2923 if mf: 2911 if mf:
2924 if not os.path.isabs(mf): 2912 if not os.path.isabs(mf):
2925 mf = os.path.join(self.ppath, mf) 2913 mf = os.path.join(self.ppath, mf)
2926 else: 2914 else:
2927 mf = os.path.join(self.ppath, Project.DefaultMakefile) 2915 mf = os.path.join(self.ppath, Project.DefaultMakefile)
2938 " be created.<br/>Reason: {1}</p>" 2926 " be created.<br/>Reason: {1}</p>"
2939 ).format(mf, str(err)), 2927 ).format(mf, str(err)),
2940 ) 2928 )
2941 self.appendFile(mf) 2929 self.appendFile(mf)
2942 2930
2943 if self.pdata["PROJECTTYPE"] != projectType: 2931 if self.__pdata["PROJECTTYPE"] != projectType:
2944 # reinitialize filetype associations 2932 # reinitialize filetype associations
2945 self.initFileTypes() 2933 self.initFileTypes()
2946 2934
2947 if self.translationsRoot: 2935 if self.translationsRoot:
2948 tp = os.path.join(self.ppath, self.translationsRoot) 2936 tp = os.path.join(self.ppath, self.translationsRoot)
2953 if not os.path.isdir(tp): 2941 if not os.path.isdir(tp):
2954 os.makedirs(tp) 2942 os.makedirs(tp)
2955 if tp != self.ppath and tp not in self.subdirs: 2943 if tp != self.ppath and tp not in self.subdirs:
2956 self.subdirs.append(tp) 2944 self.subdirs.append(tp)
2957 2945
2958 if self.pdata["TRANSLATIONSBINPATH"]: 2946 if self.__pdata["TRANSLATIONSBINPATH"]:
2959 tp = os.path.join(self.ppath, self.pdata["TRANSLATIONSBINPATH"]) 2947 tp = os.path.join(self.ppath, self.__pdata["TRANSLATIONSBINPATH"])
2960 if not os.path.isdir(tp): 2948 if not os.path.isdir(tp):
2961 os.makedirs(tp) 2949 os.makedirs(tp)
2962 if tp != self.ppath and tp not in self.subdirs: 2950 if tp != self.ppath and tp not in self.subdirs:
2963 self.subdirs.append(tp) 2951 self.subdirs.append(tp)
2964 2952
2965 self.pluginGrp.setEnabled(self.pdata["PROJECTTYPE"] in ["E7Plugin"]) 2953 self.pluginGrp.setEnabled(self.__pdata["PROJECTTYPE"] in ["E7Plugin"])
2966 2954
2967 self.__model.projectPropertiesChanged() 2955 self.__model.projectPropertiesChanged()
2968 self.projectPropertiesChanged.emit() 2956 self.projectPropertiesChanged.emit()
2969 2957
2970 if self.pdata["PROJECTTYPE"] != projectType: 2958 if self.__pdata["PROJECTTYPE"] != projectType:
2971 self.__reorganizeFiles() 2959 self.__reorganizeFiles()
2972 2960
2973 if self.pdata["EMBEDDED_VENV"] and not self.__findEmbeddedEnvironment(): 2961 if self.__pdata["EMBEDDED_VENV"] and not self.__findEmbeddedEnvironment():
2974 self.__createEmbeddedEnvironment() 2962 self.__createEmbeddedEnvironment()
2975 2963
2976 def __showUserProperties(self): 2964 def __showUserProperties(self):
2977 """ 2965 """
2978 Private slot to display the user specific properties dialog. 2966 Private slot to display the user specific properties dialog.
2979 """ 2967 """
2980 vcsSystem = self.pdata["VCS"] or None 2968 from .UserPropertiesDialog import UserPropertiesDialog
2969
2970 vcsSystem = self.__pdata["VCS"] or None
2981 vcsSystemOverride = self.pudata["VCSOVERRIDE"] or None 2971 vcsSystemOverride = self.pudata["VCSOVERRIDE"] or None
2982
2983 from .UserPropertiesDialog import UserPropertiesDialog
2984 2972
2985 dlg = UserPropertiesDialog(self) 2973 dlg = UserPropertiesDialog(self)
2986 if dlg.exec() == QDialog.DialogCode.Accepted: 2974 if dlg.exec() == QDialog.DialogCode.Accepted:
2987 dlg.storeData() 2975 dlg.storeData()
2988 2976
2989 if ( 2977 if (
2990 (self.pdata["VCS"] and self.pdata["VCS"] != vcsSystem) 2978 (self.__pdata["VCS"] and self.__pdata["VCS"] != vcsSystem)
2991 or ( 2979 or (
2992 self.pudata["VCSOVERRIDE"] 2980 self.pudata["VCSOVERRIDE"]
2993 and self.pudata["VCSOVERRIDE"] != vcsSystemOverride 2981 and self.pudata["VCSOVERRIDE"] != vcsSystemOverride
2994 ) 2982 )
2995 or (vcsSystemOverride is not None and not self.pudata["VCSOVERRIDE"]) 2983 or (vcsSystemOverride is not None and not self.pudata["VCSOVERRIDE"])
3029 def getFiletypeAssociations(self, associationType): 3017 def getFiletypeAssociations(self, associationType):
3030 """ 3018 """
3031 Public method to get the list of file type associations for 3019 Public method to get the list of file type associations for
3032 the given association type. 3020 the given association type.
3033 3021
3034 @param associationType type of the association (one of FORMS, 3022 @param associationType type of the association (one of the known file categories
3035 INTERFACES, OTHERS, PROTOCOLS, RESOURCES, SOURCES, 3023 or __IGNORE__)
3036 TRANSLATIONS or __IGNORE__)
3037 @type str 3024 @type str
3038 @return list of file patterns for the given type 3025 @return list of file patterns for the given type
3039 @rtype list of str 3026 @rtype list of str
3040 """ 3027 """
3041 return [ 3028 return [
3042 assoc 3029 assoc
3043 for assoc in self.pdata["FILETYPES"] 3030 for assoc in self.__pdata["FILETYPES"]
3044 if self.pdata["FILETYPES"][assoc] == associationType 3031 if self.__pdata["FILETYPES"][assoc] == associationType
3045 ] 3032 ]
3046 3033
3047 def __showLexerAssociations(self): 3034 def __showLexerAssociations(self):
3048 """ 3035 """
3049 Private slot to display the lexer association dialog. 3036 Private slot to display the lexer association dialog.
3063 @param filename filename used to determine the associated lexer 3050 @param filename filename used to determine the associated lexer
3064 language (string) 3051 language (string)
3065 @return the requested lexer language (string) 3052 @return the requested lexer language (string)
3066 """ 3053 """
3067 # try user settings first 3054 # try user settings first
3068 for pattern, language in list(self.pdata["LEXERASSOCS"].items()): 3055 for pattern, language in list(self.__pdata["LEXERASSOCS"].items()):
3069 if fnmatch.fnmatch(filename, pattern): 3056 if fnmatch.fnmatch(filename, pattern):
3070 return language 3057 return language
3071 3058
3072 # try project type specific defaults next 3059 # try project type specific defaults next
3073 projectType = self.pdata["PROJECTTYPE"] 3060 projectType = self.__pdata["PROJECTTYPE"]
3074 with contextlib.suppress(KeyError): 3061 with contextlib.suppress(KeyError):
3075 if self.__lexerAssociationCallbacks[projectType] is not None: 3062 if self.__lexerAssociationCallbacks[projectType] is not None:
3076 return self.__lexerAssociationCallbacks[projectType](filename) 3063 return self.__lexerAssociationCallbacks[projectType](filename)
3077 3064
3078 # return empty string to signal to use the global setting 3065 # return empty string to signal to use the global setting
3113 if fn and self.closeProject(): 3100 if fn and self.closeProject():
3114 with EricOverrideCursor(): 3101 with EricOverrideCursor():
3115 ok = self.__readProject(fn) 3102 ok = self.__readProject(fn)
3116 if ok: 3103 if ok:
3117 self.opened = True 3104 self.opened = True
3118 if not self.pdata["FILETYPES"]: 3105 if not self.__pdata["FILETYPES"]:
3119 self.initFileTypes() 3106 self.initFileTypes()
3120 else: 3107 else:
3121 self.updateFileTypes() 3108 self.updateFileTypes()
3122 3109
3123 try: 3110 try:
3170 vcsSystem = "None" 3157 vcsSystem = "None"
3171 else: 3158 else:
3172 vcsSystem = "None" 3159 vcsSystem = "None"
3173 else: 3160 else:
3174 vcsSystem = vcsData[0][0] 3161 vcsSystem = vcsData[0][0]
3175 self.pdata["VCS"] = vcsSystem 3162 self.__pdata["VCS"] = vcsSystem
3176 self.vcs = self.initVCS() 3163 self.vcs = self.initVCS()
3177 self.setDirty(True) 3164 self.setDirty(True)
3178 if self.vcs is not None and ( 3165 if self.vcs is not None and (
3179 self.vcs.vcsRegisteredState(self.ppath) 3166 self.vcs.vcsRegisteredState(self.ppath)
3180 != self.vcs.canBeCommitted 3167 != self.vcs.canBeCommitted
3181 ): 3168 ):
3182 self.pdata["VCS"] = "None" 3169 self.__pdata["VCS"] = "None"
3183 self.vcs = self.initVCS() 3170 self.vcs = self.initVCS()
3171 self.reloadAct.setEnabled(True)
3184 self.closeAct.setEnabled(True) 3172 self.closeAct.setEnabled(True)
3185 self.saveasAct.setEnabled(True) 3173 self.saveasAct.setEnabled(True)
3186 self.actGrp2.setEnabled(True) 3174 self.actGrp2.setEnabled(True)
3187 self.propsAct.setEnabled(True) 3175 self.propsAct.setEnabled(True)
3188 self.userPropsAct.setEnabled(True) 3176 self.userPropsAct.setEnabled(True)
3195 self.menuCheckAct.setEnabled(True) 3183 self.menuCheckAct.setEnabled(True)
3196 self.menuShowAct.setEnabled(True) 3184 self.menuShowAct.setEnabled(True)
3197 self.menuDiagramAct.setEnabled(True) 3185 self.menuDiagramAct.setEnabled(True)
3198 self.menuApidocAct.setEnabled(True) 3186 self.menuApidocAct.setEnabled(True)
3199 self.menuPackagersAct.setEnabled(True) 3187 self.menuPackagersAct.setEnabled(True)
3200 self.pluginGrp.setEnabled(self.pdata["PROJECTTYPE"] in ["E7Plugin"]) 3188 self.pluginGrp.setEnabled(
3189 self.__pdata["PROJECTTYPE"] in ["E7Plugin"]
3190 )
3201 self.addLanguageAct.setEnabled( 3191 self.addLanguageAct.setEnabled(
3202 bool(self.pdata["TRANSLATIONPATTERN"]) 3192 bool(self.__pdata["TRANSLATIONPATTERN"])
3203 ) 3193 )
3204 self.makeGrp.setEnabled(self.pdata["MAKEPARAMS"]["MakeEnabled"]) 3194 self.makeGrp.setEnabled(self.__pdata["MAKEPARAMS"]["MakeEnabled"])
3205 self.menuMakeAct.setEnabled(self.pdata["MAKEPARAMS"]["MakeEnabled"]) 3195 self.menuMakeAct.setEnabled(
3196 self.__pdata["MAKEPARAMS"]["MakeEnabled"]
3197 )
3206 self.menuOtherToolsAct.setEnabled(True) 3198 self.menuOtherToolsAct.setEnabled(True)
3207 self.menuFormattingAct.setEnabled(True) 3199 self.menuFormattingAct.setEnabled(True)
3208 3200
3209 # open a project debugger properties file being quiet 3201 # open a project debugger properties file being quiet
3210 # about errors 3202 # about errors
3211 if Preferences.getProject("AutoLoadDbgProperties"): 3203 if Preferences.getProject("AutoLoadDbgProperties"):
3212 self.__readDebugProperties(True) 3204 self.__readDebugProperties(True)
3213 3205
3214 self.__model.projectOpened() 3206 self.__model.projectOpened()
3215 3207
3216 if self.pdata["EMBEDDED_VENV"]: 3208 if self.__pdata["EMBEDDED_VENV"]:
3217 envPath = self.__findEmbeddedEnvironment() 3209 envPath = self.__findEmbeddedEnvironment()
3218 if bool(envPath): 3210 if bool(envPath):
3219 self.__loadEnvironmentConfiguration() 3211 self.__loadEnvironmentConfiguration()
3220 if not bool( 3212 if not bool(
3221 self.__venvConfiguration["interpreter"] 3213 self.__venvConfiguration["interpreter"]
3223 self.__venvConfiguration["interpreter"], os.X_OK 3215 self.__venvConfiguration["interpreter"], os.X_OK
3224 ): 3216 ):
3225 self.__configureEnvironment(envPath) 3217 self.__configureEnvironment(envPath)
3226 else: 3218 else:
3227 self.__createEmbeddedEnvironment() 3219 self.__createEmbeddedEnvironment()
3228 self.menuEnvironmentAct.setEnabled(self.pdata["EMBEDDED_VENV"]) 3220 self.menuEnvironmentAct.setEnabled(self.__pdata["EMBEDDED_VENV"])
3229 3221
3230 self.projectOpenedHooks.emit() 3222 self.projectOpenedHooks.emit()
3231 self.projectOpened.emit() 3223 self.projectOpened.emit()
3232 3224
3233 if Preferences.getProject("SearchNewFiles"): 3225 if Preferences.getProject("SearchNewFiles"):
3240 if Preferences.getProject("TasksProjectRescanOnOpen"): 3232 if Preferences.getProject("TasksProjectRescanOnOpen"):
3241 ericApp().getObject("TaskViewer").regenerateProjectTasks(quiet=True) 3233 ericApp().getObject("TaskViewer").regenerateProjectTasks(quiet=True)
3242 3234
3243 if restoreSession: 3235 if restoreSession:
3244 # open the main script 3236 # open the main script
3245 if self.pdata["MAINSCRIPT"]: 3237 if self.__pdata["MAINSCRIPT"]:
3246 if not os.path.isabs(self.pdata["MAINSCRIPT"]): 3238 if not os.path.isabs(self.__pdata["MAINSCRIPT"]):
3247 ms = os.path.join(self.ppath, self.pdata["MAINSCRIPT"]) 3239 ms = os.path.join(self.ppath, self.__pdata["MAINSCRIPT"])
3248 else: 3240 else:
3249 ms = self.pdata["MAINSCRIPT"] 3241 ms = self.__pdata["MAINSCRIPT"]
3250 self.sourceFile.emit(ms) 3242 self.sourceFile.emit(ms)
3251 3243
3252 # open a project session file being quiet about errors 3244 # open a project session file being quiet about errors
3253 if reopen: 3245 if reopen:
3254 self.__readSession(quiet=True, indicator="_tmp") 3246 self.__readSession(quiet=True, indicator="_tmp")
3457 3449
3458 # now close all project related tool windows 3450 # now close all project related tool windows
3459 self.__closeAllWindows() 3451 self.__closeAllWindows()
3460 3452
3461 self.__initData() 3453 self.__initData()
3454 self.reloadAct.setEnabled(False)
3462 self.closeAct.setEnabled(False) 3455 self.closeAct.setEnabled(False)
3463 self.saveasAct.setEnabled(False) 3456 self.saveasAct.setEnabled(False)
3464 self.saveAct.setEnabled(False) 3457 self.saveAct.setEnabled(False)
3465 self.actGrp2.setEnabled(False) 3458 self.actGrp2.setEnabled(False)
3466 self.propsAct.setEnabled(False) 3459 self.propsAct.setEnabled(False)
3500 vm = ericApp().getObject("ViewManager") 3493 vm = ericApp().getObject("ViewManager")
3501 success = True 3494 success = True
3502 filesWithSyntaxErrors = 0 3495 filesWithSyntaxErrors = 0
3503 for fn in vm.getOpenFilenames(): 3496 for fn in vm.getOpenFilenames():
3504 rfn = self.getRelativePath(fn) 3497 rfn = self.getRelativePath(fn)
3505 if rfn in self.pdata["SOURCES"] or rfn in self.pdata["OTHERS"]: 3498 if rfn in self.__pdata["SOURCES"] or rfn in self.__pdata["OTHERS"]:
3506 editor = vm.getOpenEditor(fn) 3499 editor = vm.getOpenEditor(fn)
3507 success &= vm.saveEditorEd(editor) 3500 success &= vm.saveEditorEd(editor)
3508 if reportSyntaxErrors and editor.hasSyntaxErrors(): 3501 if reportSyntaxErrors and editor.hasSyntaxErrors():
3509 filesWithSyntaxErrors += 1 3502 filesWithSyntaxErrors += 1
3510 3503
3534 vm = ericApp().getObject("ViewManager") 3527 vm = ericApp().getObject("ViewManager")
3535 success = True 3528 success = True
3536 filesWithSyntaxErrors = 0 3529 filesWithSyntaxErrors = 0
3537 for fn in vm.getOpenFilenames(): 3530 for fn in vm.getOpenFilenames():
3538 rfn = self.getRelativePath(fn) 3531 rfn = self.getRelativePath(fn)
3539 if rfn in self.pdata["SOURCES"] or rfn in self.pdata["OTHERS"]: 3532 if rfn in self.__pdata["SOURCES"] or rfn in self.__pdata["OTHERS"]:
3540 editor = vm.getOpenEditor(fn) 3533 editor = vm.getOpenEditor(fn)
3541 success &= editor.checkDirty() 3534 success &= editor.checkDirty()
3542 if reportSyntaxErrors and editor.hasSyntaxErrors(): 3535 if reportSyntaxErrors and editor.hasSyntaxErrors():
3543 filesWithSyntaxErrors += 1 3536 filesWithSyntaxErrors += 1
3544 3537
3566 @param normalized flag indicating a normalized filename is wanted 3559 @param normalized flag indicating a normalized filename is wanted
3567 @type bool 3560 @type bool
3568 @return filename of the projects main script 3561 @return filename of the projects main script
3569 @rtype str 3562 @rtype str
3570 """ 3563 """
3571 if self.pdata["MAINSCRIPT"]: 3564 if self.__pdata["MAINSCRIPT"]:
3572 if normalized: 3565 if normalized:
3573 return os.path.join(self.ppath, self.pdata["MAINSCRIPT"]) 3566 return os.path.join(self.ppath, self.__pdata["MAINSCRIPT"])
3574 else: 3567 else:
3575 return self.pdata["MAINSCRIPT"] 3568 return self.__pdata["MAINSCRIPT"]
3576 else: 3569 else:
3577 return "" 3570 return ""
3578 3571
3579 def getSources(self, normalized=False): 3572 def getSources(self, normalized=False):
3580 """ 3573 """
3589 3582
3590 def getProjectFiles(self, fileType, normalized=False): 3583 def getProjectFiles(self, fileType, normalized=False):
3591 """ 3584 """
3592 Public method to get the file entries of the given type. 3585 Public method to get the file entries of the given type.
3593 3586
3594 @param fileType project file type (one of SOURCES, FORMS, RESOURCES, 3587 @param fileType project file type (one of the known file categories)
3595 INTERFACES, PROTOCOLS, OTHERS, TRANSLATIONS)
3596 @type str 3588 @type str
3597 @param normalized flag indicating normalized file names are wanted 3589 @param normalized flag indicating normalized file names are wanted
3598 @type boolean 3590 @type boolean
3599 @return list of file names 3591 @return list of file names
3600 @rtype list of str 3592 @rtype list of str
3601 @exception ValueError raised when an unsupported file type is given 3593 @exception ValueError raised when an unsupported file type is given
3602 """ 3594 """
3603 if fileType not in [ 3595 if fileType not in self.getFileCategories():
3604 "SOURCES",
3605 "FORMS",
3606 "RESOURCES",
3607 "INTERFACES",
3608 "PROTOCOLS",
3609 "OTHERS",
3610 "TRANSLATIONS",
3611 ]:
3612 raise ValueError("Given file type has incorrect value.") 3596 raise ValueError("Given file type has incorrect value.")
3613 3597
3614 if normalized: 3598 if normalized:
3615 return [os.path.join(self.ppath, fn) for fn in self.pdata[fileType]] 3599 return [os.path.join(self.ppath, fn) for fn in self.__pdata[fileType]]
3616 else: 3600 else:
3617 return self.pdata[fileType] 3601 return self.__pdata[fileType]
3618 3602
3619 def getProjectType(self): 3603 def getProjectType(self):
3620 """ 3604 """
3621 Public method to get the type of the project. 3605 Public method to get the type of the project.
3622 3606
3623 @return UI type of the project (string) 3607 @return UI type of the project (string)
3624 """ 3608 """
3625 return self.pdata["PROJECTTYPE"] 3609 return self.__pdata["PROJECTTYPE"]
3626 3610
3627 def getProjectLanguage(self): 3611 def getProjectLanguage(self):
3628 """ 3612 """
3629 Public method to get the project's programming language. 3613 Public method to get the project's programming language.
3630 3614
3631 @return programming language (string) 3615 @return programming language (string)
3632 """ 3616 """
3633 return self.pdata["PROGLANGUAGE"] 3617 return self.__pdata["PROGLANGUAGE"]
3634 3618
3635 def isMixedLanguageProject(self): 3619 def isMixedLanguageProject(self):
3636 """ 3620 """
3637 Public method to check, if this is a mixed language project. 3621 Public method to check, if this is a mixed language project.
3638 3622
3639 @return flag indicating a mixed language project 3623 @return flag indicating a mixed language project
3640 @rtype bool 3624 @rtype bool
3641 """ 3625 """
3642 return self.pdata["MIXEDLANGUAGE"] 3626 return self.__pdata["MIXEDLANGUAGE"]
3643 3627
3644 def isPythonProject(self): 3628 def isPythonProject(self):
3645 """ 3629 """
3646 Public method to check, if this project is a Python3 or MicroPython 3630 Public method to check, if this project is a Python3 or MicroPython
3647 project. 3631 project.
3648 3632
3649 @return flag indicating a Python project (boolean) 3633 @return flag indicating a Python project (boolean)
3650 """ 3634 """
3651 return self.pdata["PROGLANGUAGE"] in ["Python3", "MicroPython"] 3635 return self.__pdata["PROGLANGUAGE"] in ["Python3", "MicroPython"]
3652 3636
3653 def isPy3Project(self): 3637 def isPy3Project(self):
3654 """ 3638 """
3655 Public method to check, if this project is a Python3 project. 3639 Public method to check, if this project is a Python3 project.
3656 3640
3657 @return flag indicating a Python3 project (boolean) 3641 @return flag indicating a Python3 project (boolean)
3658 """ 3642 """
3659 return self.pdata["PROGLANGUAGE"] == "Python3" 3643 return self.__pdata["PROGLANGUAGE"] == "Python3"
3660 3644
3661 def isMicroPythonProject(self): 3645 def isMicroPythonProject(self):
3662 """ 3646 """
3663 Public method to check, if this project is a MicroPython project. 3647 Public method to check, if this project is a MicroPython project.
3664 3648
3665 @return flag indicating a MicroPython project 3649 @return flag indicating a MicroPython project
3666 @rtype bool 3650 @rtype bool
3667 """ 3651 """
3668 return self.pdata["PROGLANGUAGE"] == "MicroPython" 3652 return self.__pdata["PROGLANGUAGE"] == "MicroPython"
3669 3653
3670 def isRubyProject(self): 3654 def isRubyProject(self):
3671 """ 3655 """
3672 Public method to check, if this project is a Ruby project. 3656 Public method to check, if this project is a Ruby project.
3673 3657
3674 @return flag indicating a Ruby project (boolean) 3658 @return flag indicating a Ruby project (boolean)
3675 """ 3659 """
3676 return self.pdata["PROGLANGUAGE"] == "Ruby" 3660 return self.__pdata["PROGLANGUAGE"] == "Ruby"
3677 3661
3678 def isJavaScriptProject(self): 3662 def isJavaScriptProject(self):
3679 """ 3663 """
3680 Public method to check, if this project is a JavaScript project. 3664 Public method to check, if this project is a JavaScript project.
3681 3665
3682 @return flag indicating a JavaScript project (boolean) 3666 @return flag indicating a JavaScript project (boolean)
3683 """ 3667 """
3684 return self.pdata["PROGLANGUAGE"] == "JavaScript" 3668 return self.__pdata["PROGLANGUAGE"] == "JavaScript"
3685 3669
3686 def getProjectSpellLanguage(self): 3670 def getProjectSpellLanguage(self):
3687 """ 3671 """
3688 Public method to get the project's programming language. 3672 Public method to get the project's programming language.
3689 3673
3690 @return programming language (string) 3674 @return programming language (string)
3691 """ 3675 """
3692 return self.pdata["SPELLLANGUAGE"] 3676 return self.__pdata["SPELLLANGUAGE"]
3693 3677
3694 def getProjectDictionaries(self): 3678 def getProjectDictionaries(self):
3695 """ 3679 """
3696 Public method to get the names of the project specific dictionaries. 3680 Public method to get the names of the project specific dictionaries.
3697 3681
3698 @return tuple of two strings giving the absolute path names of the 3682 @return tuple of two strings giving the absolute path names of the
3699 project specific word and exclude list 3683 project specific word and exclude list
3700 """ 3684 """
3701 pwl = "" 3685 pwl = ""
3702 if self.pdata["SPELLWORDS"]: 3686 if self.__pdata["SPELLWORDS"]:
3703 pwl = os.path.join(self.ppath, self.pdata["SPELLWORDS"]) 3687 pwl = os.path.join(self.ppath, self.__pdata["SPELLWORDS"])
3704 if not os.path.isfile(pwl): 3688 if not os.path.isfile(pwl):
3705 pwl = "" 3689 pwl = ""
3706 3690
3707 pel = "" 3691 pel = ""
3708 if self.pdata["SPELLEXCLUDES"]: 3692 if self.__pdata["SPELLEXCLUDES"]:
3709 pel = os.path.join(self.ppath, self.pdata["SPELLEXCLUDES"]) 3693 pel = os.path.join(self.ppath, self.__pdata["SPELLEXCLUDES"])
3710 if not os.path.isfile(pel): 3694 if not os.path.isfile(pel):
3711 pel = "" 3695 pel = ""
3712 3696
3713 return (pwl, pel) 3697 return (pwl, pel)
3714 3698
3717 Public method to get the default extension for the project's 3701 Public method to get the default extension for the project's
3718 programming language. 3702 programming language.
3719 3703
3720 @return default extension (including the dot) (string) 3704 @return default extension (including the dot) (string)
3721 """ 3705 """
3722 lang = self.pdata["PROGLANGUAGE"] 3706 lang = self.__pdata["PROGLANGUAGE"]
3723 if lang in ("", "Python"): 3707 if lang in ("", "Python"):
3724 lang = "Python3" 3708 lang = "Python3"
3725 return self.__sourceExtensions(lang)[0] 3709 return self.__sourceExtensions(lang)[0]
3726 3710
3727 def getProjectPath(self): 3711 def getProjectPath(self):
3793 """ 3777 """
3794 Public method to get the project hash. 3778 Public method to get the project hash.
3795 3779
3796 @return project hash as a hex string (string) 3780 @return project hash as a hex string (string)
3797 """ 3781 """
3798 return self.pdata["HASH"] 3782 return self.__pdata["HASH"]
3799 3783
3800 def getRelativePath(self, path): 3784 def getRelativePath(self, path):
3801 """ 3785 """
3802 Public method to convert a file path to a project relative 3786 Public method to convert a file path to a project relative
3803 file path. 3787 file path.
3850 """ 3834 """
3851 Public method to get the EOL-string to be used by the project. 3835 Public method to get the EOL-string to be used by the project.
3852 3836
3853 @return eol string (string) 3837 @return eol string (string)
3854 """ 3838 """
3855 if self.pdata["EOL"] >= 0: 3839 if self.__pdata["EOL"] >= 0:
3856 return self.eols[self.pdata["EOL"]] 3840 return self.eols[self.__pdata["EOL"]]
3857 else: 3841 else:
3858 eolMode = Preferences.getEditor("EOLMode") 3842 eolMode = Preferences.getEditor("EOLMode")
3859 if eolMode == QsciScintilla.EolMode.EolWindows: 3843 if eolMode == QsciScintilla.EolMode.EolWindows:
3860 eol = "\r\n" 3844 eol = "\r\n"
3861 elif eolMode == QsciScintilla.EolMode.EolUnix: 3845 elif eolMode == QsciScintilla.EolMode.EolUnix:
3870 """ 3854 """
3871 Public method to check, if the project uses the system eol setting. 3855 Public method to check, if the project uses the system eol setting.
3872 3856
3873 @return flag indicating the usage of system eol (boolean) 3857 @return flag indicating the usage of system eol (boolean)
3874 """ 3858 """
3875 return self.pdata["EOL"] == 0 3859 return self.__pdata["EOL"] == 0
3876 3860
3877 def getProjectVersion(self): 3861 def getProjectVersion(self):
3878 """ 3862 """
3879 Public mehod to get the version number of the project. 3863 Public mehod to get the version number of the project.
3880 3864
3881 @return version number 3865 @return version number
3882 @rtype str 3866 @rtype str
3883 """ 3867 """
3884 return self.pdata["VERSION"] 3868 return self.__pdata["VERSION"]
3885 3869
3886 def getProjectAuthor(self): 3870 def getProjectAuthor(self):
3887 """ 3871 """
3888 Public method to get the author of the project. 3872 Public method to get the author of the project.
3889 3873
3890 @return author name 3874 @return author name
3891 @rtype str 3875 @rtype str
3892 """ 3876 """
3893 return self.pdata["AUTHOR"] 3877 return self.__pdata["AUTHOR"]
3894 3878
3895 def getProjectAuthorEmail(self): 3879 def getProjectAuthorEmail(self):
3896 """ 3880 """
3897 Public method to get the email address of the project author. 3881 Public method to get the email address of the project author.
3898 3882
3899 @return project author email 3883 @return project author email
3900 @rtype str 3884 @rtype str
3901 """ 3885 """
3902 return self.pdata["EMAIL"] 3886 return self.__pdata["EMAIL"]
3903 3887
3904 def getProjectDescription(self): 3888 def getProjectDescription(self):
3905 """ 3889 """
3906 Public method to get the description of the project. 3890 Public method to get the description of the project.
3907 3891
3908 @return project description 3892 @return project description
3909 @rtype str 3893 @rtype str
3910 """ 3894 """
3911 return self.pdata["DESCRIPTION"] 3895 return self.__pdata["DESCRIPTION"]
3912 3896
3913 def getProjectVenv(self, resolveDebugger=True): 3897 def getProjectVenv(self, resolveDebugger=True):
3914 """ 3898 """
3915 Public method to get the name of the virtual environment used by the 3899 Public method to get the name of the virtual environment used by the
3916 project. 3900 project.
3921 @return name of the project's virtual environment 3905 @return name of the project's virtual environment
3922 @rtype str 3906 @rtype str
3923 """ 3907 """
3924 venvName = ( 3908 venvName = (
3925 self.__venvConfiguration["name"] 3909 self.__venvConfiguration["name"]
3926 if self.pdata["EMBEDDED_VENV"] and bool(self.__venvConfiguration["name"]) 3910 if self.__pdata["EMBEDDED_VENV"] and bool(self.__venvConfiguration["name"])
3927 else self.getDebugProperty("VIRTUALENV") 3911 else self.getDebugProperty("VIRTUALENV")
3928 ) 3912 )
3929 if ( 3913 if (
3930 not venvName 3914 not venvName
3931 and resolveDebugger 3915 and resolveDebugger
3946 @return path of the project's interpreter 3930 @return path of the project's interpreter
3947 @rtype str 3931 @rtype str
3948 """ 3932 """
3949 interpreter = ( 3933 interpreter = (
3950 self.__venvConfiguration["interpreter"] 3934 self.__venvConfiguration["interpreter"]
3951 if self.pdata["EMBEDDED_VENV"] 3935 if self.__pdata["EMBEDDED_VENV"]
3952 else "" 3936 else ""
3953 ) 3937 )
3954 if not interpreter: 3938 if not interpreter:
3955 venvName = self.getProjectVenv() 3939 venvName = self.getProjectVenv()
3956 if venvName: 3940 if venvName:
3969 Public method to get the executable search path prefix of the project. 3953 Public method to get the executable search path prefix of the project.
3970 3954
3971 @return executable search path prefix 3955 @return executable search path prefix
3972 @rtype str 3956 @rtype str
3973 """ 3957 """
3974 if self.pdata["EMBEDDED_VENV"]: 3958 if self.__pdata["EMBEDDED_VENV"]:
3975 execPath = self.__venvConfiguration["exec_path"] 3959 execPath = self.__venvConfiguration["exec_path"]
3976 else: 3960 else:
3977 execPath = "" 3961 execPath = ""
3978 venvName = self.getProjectVenv() 3962 venvName = self.getProjectVenv()
3979 if venvName: 3963 if venvName:
3991 3975
3992 @return testing framework name of the project 3976 @return testing framework name of the project
3993 @rtype str 3977 @rtype str
3994 """ 3978 """
3995 try: 3979 try:
3996 return self.pdata["TESTING_FRAMEWORK"] 3980 return self.__pdata["TESTING_FRAMEWORK"]
3997 except KeyError: 3981 except KeyError:
3998 return "" 3982 return ""
3999 3983
4000 def getProjectLicense(self): 3984 def getProjectLicense(self):
4001 """ 3985 """
4003 3987
4004 @return license type of the project 3988 @return license type of the project
4005 @rtype str 3989 @rtype str
4006 """ 3990 """
4007 try: 3991 try:
4008 return self.pdata["LICENSE"] 3992 return self.__pdata["LICENSE"]
4009 except KeyError: 3993 except KeyError:
4010 return "" 3994 return ""
4011 3995
4012 def __isInPdata(self, fn): 3996 def __isInPdata(self, fn):
4013 """ 3997 """
4020 @rtype bool 4004 @rtype bool
4021 """ 4005 """
4022 newfn = os.path.abspath(fn) 4006 newfn = os.path.abspath(fn)
4023 newfn = self.getRelativePath(newfn) 4007 newfn = self.getRelativePath(newfn)
4024 return any( 4008 return any(
4025 newfn in self.pdata[group] 4009 newfn in self.__pdata[category] for category in self.getFileCategories()
4026 for group in [
4027 "SOURCES",
4028 "FORMS",
4029 "INTERFACES",
4030 "PROTOCOLS",
4031 "RESOURCES",
4032 "TRANSLATIONS",
4033 "OTHERS",
4034 ]
4035 ) 4010 )
4036 4011
4037 def isProjectFile(self, fn): 4012 def isProjectFile(self, fn):
4038 """ 4013 """
4039 Public method used to check, if the passed in filename belongs to the 4014 Public method used to check, if the passed in filename belongs to the
4041 4016
4042 @param fn filename to be checked (string) 4017 @param fn filename to be checked (string)
4043 @return flag indicating membership (boolean) 4018 @return flag indicating membership (boolean)
4044 """ 4019 """
4045 return any( 4020 return any(
4046 self.__checkProjectFileGroup(fn, group) 4021 self.__checkProjectFileGroup(fn, category)
4047 for group in [ 4022 for category in self.getFileCategories()
4048 "SOURCES",
4049 "FORMS",
4050 "INTERFACES",
4051 "PROTOCOLS",
4052 "RESOURCES",
4053 "TRANSLATIONS",
4054 "OTHERS",
4055 ]
4056 ) 4023 )
4057 4024
4058 def __checkProjectFileGroup(self, fn, group): 4025 def __checkProjectFileGroup(self, fn, group):
4059 """ 4026 """
4060 Private method to check, if a file is in a specific file group of the 4027 Private method to check, if a file is in a specific file group of the
4064 @param group group to check (string) 4031 @param group group to check (string)
4065 @return flag indicating membership (boolean) 4032 @return flag indicating membership (boolean)
4066 """ 4033 """
4067 newfn = os.path.abspath(fn) 4034 newfn = os.path.abspath(fn)
4068 newfn = self.getRelativePath(newfn) 4035 newfn = self.getRelativePath(newfn)
4069 if newfn in self.pdata[group] or ( 4036 if newfn in self.__pdata[group] or (
4070 group == "OTHERS" 4037 group == "OTHERS"
4071 and any(newfn.startswith(entry) for entry in self.pdata[group]) 4038 and any(newfn.startswith(entry) for entry in self.__pdata[group])
4072 ): 4039 ):
4073 return True 4040 return True
4074 4041
4075 if Utilities.isWindowsPlatform(): 4042 if Utilities.isWindowsPlatform():
4076 # try the above case-insensitive 4043 # try the above case-insensitive
4077 newfn = newfn.lower() 4044 newfn = newfn.lower()
4078 if any(entry.lower() == newfn for entry in self.pdata[group]): 4045 if any(entry.lower() == newfn for entry in self.__pdata[group]):
4079 return True 4046 return True
4080 elif group == "OTHERS" and any( 4047
4081 newfn.startswith(entry.lower()) for entry in self.pdata[group] 4048 elif group == "OTHERS" and any(
4082 ): 4049 newfn.startswith(entry.lower()) for entry in self.__pdata[group]
4083 return True 4050 ):
4051 return True
4084 4052
4085 return False 4053 return False
4086 4054
4087 def isProjectSource(self, fn): 4055 def isProjectCategory(self, fn, category):
4088 """ 4056 """
4089 Public method used to check, if the passed in filename belongs to the 4057 Public method to check, if the passed in filename belongs to the given
4090 project sources. 4058 category.
4091
4092 @param fn filename to be checked (string)
4093 @return flag indicating membership (boolean)
4094 """
4095 return self.__checkProjectFileGroup(fn, "SOURCES")
4096
4097 def isProjectForm(self, fn):
4098 """
4099 Public method used to check, if the passed in filename belongs to the
4100 project forms.
4101
4102 @param fn filename to be checked (string)
4103 @return flag indicating membership (boolean)
4104 """
4105 return self.__checkProjectFileGroup(fn, "FORMS")
4106
4107 def isProjectInterface(self, fn):
4108 """
4109 Public method used to check, if the passed in filename belongs to the
4110 project interfaces.
4111
4112 @param fn filename to be checked (string)
4113 @return flag indicating membership (boolean)
4114 """
4115 return self.__checkProjectFileGroup(fn, "INTERFACES")
4116
4117 def isProjectProtocol(self, fn):
4118 """
4119 Public method used to check, if the passed in filename belongs to the
4120 project protocols.
4121 4059
4122 @param fn filename to be checked 4060 @param fn filename to be checked
4061 @type str
4062 @param category file category to check against
4123 @type str 4063 @type str
4124 @return flag indicating membership 4064 @return flag indicating membership
4125 @rtype bool 4065 @rtype bool
4126 """ 4066 """
4127 return self.__checkProjectFileGroup(fn, "PROTOCOLS") 4067 if category in self.getFileCategories():
4128 4068 return self.__checkProjectFileGroup(fn, category)
4129 def isProjectResource(self, fn): 4069 else:
4130 """ 4070 return False # unknown category always returns False
4131 Public method used to check, if the passed in filename belongs to the
4132 project resources.
4133
4134 @param fn filename to be checked (string)
4135 @return flag indicating membership (boolean)
4136 """
4137 return self.__checkProjectFileGroup(fn, "RESOURCES")
4138 4071
4139 def initActions(self): 4072 def initActions(self):
4140 """ 4073 """
4141 Public slot to initialize the project related actions. 4074 Public slot to initialize the project related actions.
4142 """ 4075 """
4177 self.actGrp1, 4110 self.actGrp1,
4178 "project_open", 4111 "project_open",
4179 ) 4112 )
4180 act.setStatusTip(self.tr("Open an existing project")) 4113 act.setStatusTip(self.tr("Open an existing project"))
4181 act.setWhatsThis( 4114 act.setWhatsThis(
4182 self.tr("""<b>Open...</b>""" """<p>This opens an existing project.</p>""") 4115 self.tr("""<b>Open...</b><p>This opens an existing project.</p>""")
4183 ) 4116 )
4184 act.triggered.connect(self.openProject) 4117 act.triggered.connect(self.openProject)
4185 self.actions.append(act) 4118 self.actions.append(act)
4119
4120 self.reloadAct = EricAction(
4121 self.tr("Reload project"),
4122 EricPixmapCache.getIcon("projectReload"),
4123 self.tr("&Reload"),
4124 0,
4125 0,
4126 self.actGrp1,
4127 "project_reload",
4128 )
4129 self.reloadAct.setStatusTip(self.tr("Reload the current project"))
4130 self.reloadAct.setWhatsThis(
4131 self.tr("""<b>Reload</b><p>This reloads the current project.</p>""")
4132 )
4133 self.reloadAct.triggered.connect(self.reopenProject)
4134 self.actions.append(self.reloadAct)
4186 4135
4187 self.closeAct = EricAction( 4136 self.closeAct = EricAction(
4188 self.tr("Close project"), 4137 self.tr("Close project"),
4189 EricPixmapCache.getIcon("projectClose"), 4138 EricPixmapCache.getIcon("projectClose"),
4190 self.tr("&Close"), 4139 self.tr("&Close"),
4193 self, 4142 self,
4194 "project_close", 4143 "project_close",
4195 ) 4144 )
4196 self.closeAct.setStatusTip(self.tr("Close the current project")) 4145 self.closeAct.setStatusTip(self.tr("Close the current project"))
4197 self.closeAct.setWhatsThis( 4146 self.closeAct.setWhatsThis(
4198 self.tr("""<b>Close</b>""" """<p>This closes the current project.</p>""") 4147 self.tr("""<b>Close</b><p>This closes the current project.</p>""")
4199 ) 4148 )
4200 self.closeAct.triggered.connect(self.closeProject) 4149 self.closeAct.triggered.connect(self.closeProject)
4201 self.actions.append(self.closeAct) 4150 self.actions.append(self.closeAct)
4202 4151
4203 self.saveAct = EricAction( 4152 self.saveAct = EricAction(
4209 self, 4158 self,
4210 "project_save", 4159 "project_save",
4211 ) 4160 )
4212 self.saveAct.setStatusTip(self.tr("Save the current project")) 4161 self.saveAct.setStatusTip(self.tr("Save the current project"))
4213 self.saveAct.setWhatsThis( 4162 self.saveAct.setWhatsThis(
4214 self.tr("""<b>Save</b>""" """<p>This saves the current project.</p>""") 4163 self.tr("""<b>Save</b><p>This saves the current project.</p>""")
4215 ) 4164 )
4216 self.saveAct.triggered.connect(self.saveProject) 4165 self.saveAct.triggered.connect(self.saveProject)
4217 self.actions.append(self.saveAct) 4166 self.actions.append(self.saveAct)
4218 4167
4219 self.saveasAct = EricAction( 4168 self.saveasAct = EricAction(
4865 ) 4814 )
4866 self.createSBOMAct.triggered.connect(self.__createSBOMFile) 4815 self.createSBOMAct.triggered.connect(self.__createSBOMFile)
4867 self.actions.append(self.createSBOMAct) 4816 self.actions.append(self.createSBOMAct)
4868 4817
4869 ################################################################### 4818 ###################################################################
4870 ## Project Tools - code formatting actions 4819 ## Project Tools - code formatting actions - Black
4871 ################################################################### 4820 ###################################################################
4872 4821
4873 self.blackFormattingGrp = createActionGroup(self) 4822 self.blackFormattingGrp = createActionGroup(self)
4874 4823
4875 self.blackAboutAct = EricAction( 4824 self.blackAboutAct = EricAction(
4989 " project sources with 'Black'.</p>" 4938 " project sources with 'Black'.</p>"
4990 ) 4939 )
4991 ) 4940 )
4992 self.blackConfigureAct.triggered.connect(self.__configureBlack) 4941 self.blackConfigureAct.triggered.connect(self.__configureBlack)
4993 self.actions.append(self.blackConfigureAct) 4942 self.actions.append(self.blackConfigureAct)
4943
4944 ###################################################################
4945 ## Project Tools - code formatting actions - isort
4946 ###################################################################
4947
4948 self.isortFormattingGrp = createActionGroup(self)
4949
4950 self.isortAboutAct = EricAction(
4951 self.tr("About isort"),
4952 self.tr("&isort"),
4953 0,
4954 0,
4955 self.isortFormattingGrp,
4956 "project_isort_about",
4957 )
4958 self.isortAboutAct.setStatusTip(self.tr("Show some information about 'isort'."))
4959 self.isortAboutAct.setWhatsThis(
4960 self.tr(
4961 "<b>isort</b>"
4962 "<p>This shows some information about the installed 'isort' tool.</p>"
4963 )
4964 )
4965 self.isortAboutAct.triggered.connect(aboutIsort)
4966 self.actions.append(self.isortAboutAct)
4967 font = self.isortAboutAct.font()
4968 font.setBold(True)
4969 self.isortAboutAct.setFont(font)
4970
4971 self.isortSortImportsAct = EricAction(
4972 self.tr("Sort Imports"),
4973 self.tr("Sort Imports"),
4974 0,
4975 0,
4976 self.isortFormattingGrp,
4977 "project_isort_sort_imports",
4978 )
4979 self.isortSortImportsAct.setStatusTip(
4980 self.tr("Sort the import statements of the project sources with 'isort'.")
4981 )
4982 self.isortSortImportsAct.setWhatsThis(
4983 self.tr(
4984 "<b>Sort Imports</b>"
4985 "<p>This shows a dialog to enter parameters for the imports sorting"
4986 " run and sorts the import statements of the project sources using"
4987 " 'isort'.</p>"
4988 )
4989 )
4990 self.isortSortImportsAct.triggered.connect(
4991 lambda: self.__performImportSortingWithIsort(IsortFormattingAction.Sort)
4992 )
4993 self.actions.append(self.isortSortImportsAct)
4994
4995 self.isortDiffSortingAct = EricAction(
4996 self.tr("Imports Sorting Diff"),
4997 self.tr("Imports Sorting Diff"),
4998 0,
4999 0,
5000 self.isortFormattingGrp,
5001 "project_isort_diff_code",
5002 )
5003 self.isortDiffSortingAct.setStatusTip(
5004 self.tr(
5005 "Generate a unified diff of potential project source imports"
5006 " resorting with 'isort'."
5007 )
5008 )
5009 self.isortDiffSortingAct.setWhatsThis(
5010 self.tr(
5011 "<b>Imports Sorting Diff</b>"
5012 "<p>This shows a dialog to enter parameters for the imports sorting"
5013 " diff run and generates a unified diff of potential project source"
5014 " changes using 'isort'.</p>"
5015 )
5016 )
5017 self.isortDiffSortingAct.triggered.connect(
5018 lambda: self.__performImportSortingWithIsort(IsortFormattingAction.Diff)
5019 )
5020 self.actions.append(self.isortDiffSortingAct)
5021
5022 self.isortConfigureAct = EricAction(
5023 self.tr("Configure"),
5024 self.tr("Configure"),
5025 0,
5026 0,
5027 self.isortFormattingGrp,
5028 "project_isort_configure",
5029 )
5030 self.isortConfigureAct.setStatusTip(
5031 self.tr(
5032 "Enter the parameters for resorting the project sources import"
5033 " statements with 'isort'."
5034 )
5035 )
5036 self.isortConfigureAct.setWhatsThis(
5037 self.tr(
5038 "<b>Configure</b>"
5039 "<p>This shows a dialog to enter the parameters for resorting the"
5040 " import statements of the project sources with 'isort'.</p>"
5041 )
5042 )
5043 self.isortConfigureAct.triggered.connect(self.__configureIsort)
5044 self.actions.append(self.isortConfigureAct)
4994 5045
4995 ################################################################### 5046 ###################################################################
4996 ## Project - embedded environment actions 5047 ## Project - embedded environment actions
4997 ################################################################### 5048 ###################################################################
4998 5049
5079 ) 5130 )
5080 ) 5131 )
5081 self.recreateVenvAct.triggered.connect(self.__createEmbeddedEnvironment) 5132 self.recreateVenvAct.triggered.connect(self.__createEmbeddedEnvironment)
5082 self.actions.append(self.recreateVenvAct) 5133 self.actions.append(self.recreateVenvAct)
5083 5134
5135 self.reloadAct.setEnabled(False)
5084 self.closeAct.setEnabled(False) 5136 self.closeAct.setEnabled(False)
5085 self.saveAct.setEnabled(False) 5137 self.saveAct.setEnabled(False)
5086 self.saveasAct.setEnabled(False) 5138 self.saveasAct.setEnabled(False)
5087 self.actGrp2.setEnabled(False) 5139 self.actGrp2.setEnabled(False)
5088 self.propsAct.setEnabled(False) 5140 self.propsAct.setEnabled(False)
5202 self.othersMenu.addSeparator() 5254 self.othersMenu.addSeparator()
5203 5255
5204 # build the 'Code Formatting' menu 5256 # build the 'Code Formatting' menu
5205 self.formattingMenu.setTearOffEnabled(True) 5257 self.formattingMenu.setTearOffEnabled(True)
5206 self.formattingMenu.addActions(self.blackFormattingGrp.actions()) 5258 self.formattingMenu.addActions(self.blackFormattingGrp.actions())
5259 self.formattingMenu.addSeparator()
5260 self.formattingMenu.addActions(self.isortFormattingGrp.actions())
5207 self.formattingMenu.addSeparator() 5261 self.formattingMenu.addSeparator()
5208 5262
5209 # build the project main menu 5263 # build the project main menu
5210 menu.setTearOffEnabled(True) 5264 menu.setTearOffEnabled(True)
5211 menu.addActions(self.actGrp1.actions()) 5265 menu.addActions(self.actGrp1.actions())
5273 5327
5274 @param toolbarManager reference to a toolbar manager object 5328 @param toolbarManager reference to a toolbar manager object
5275 (EricToolBarManager) 5329 (EricToolBarManager)
5276 @return tuple of the generated toolbars (tuple of two QToolBar) 5330 @return tuple of the generated toolbars (tuple of two QToolBar)
5277 """ 5331 """
5332 from eric7 import VCS
5333
5278 tb = QToolBar(self.tr("Project"), self.ui) 5334 tb = QToolBar(self.tr("Project"), self.ui)
5279 tb.setIconSize(Config.ToolBarIconSize) 5335 tb.setIconSize(Config.ToolBarIconSize)
5280 tb.setObjectName("ProjectToolbar") 5336 tb.setObjectName("ProjectToolbar")
5281 tb.setToolTip(self.tr("Project")) 5337 tb.setToolTip(self.tr("Project"))
5282 5338
5291 toolbarManager.addAction(self.addDirectoryAct, tb.windowTitle()) 5347 toolbarManager.addAction(self.addDirectoryAct, tb.windowTitle())
5292 toolbarManager.addAction(self.addLanguageAct, tb.windowTitle()) 5348 toolbarManager.addAction(self.addLanguageAct, tb.windowTitle())
5293 toolbarManager.addAction(self.propsAct, tb.windowTitle()) 5349 toolbarManager.addAction(self.propsAct, tb.windowTitle())
5294 toolbarManager.addAction(self.userPropsAct, tb.windowTitle()) 5350 toolbarManager.addAction(self.userPropsAct, tb.windowTitle())
5295 5351
5296 from eric7 import VCS
5297
5298 vcstb = VCS.getBasicHelper(self).initBasicToolbar(self.ui, toolbarManager) 5352 vcstb = VCS.getBasicHelper(self).initBasicToolbar(self.ui, toolbarManager)
5299 5353
5300 return tb, vcstb 5354 return tb, vcstb
5301 5355
5302 def __showMenu(self): 5356 def __showMenu(self):
5303 """ 5357 """
5304 Private method to set up the project menu. 5358 Private method to set up the project menu.
5305 """ 5359 """
5306 self.menuRecentAct.setEnabled(len(self.recent) > 0) 5360 self.menuRecentAct.setEnabled(len(self.recent) > 0)
5307 self.menuEnvironmentAct.setEnabled(self.pdata["EMBEDDED_VENV"]) 5361 self.menuEnvironmentAct.setEnabled(self.__pdata["EMBEDDED_VENV"])
5308 5362
5309 self.showMenu.emit("Main", self.__menus["Main"]) 5363 self.showMenu.emit("Main", self.__menus["Main"])
5310 5364
5311 def __syncRecent(self): 5365 def __syncRecent(self):
5312 """ 5366 """
5379 5433
5380 def __searchProjectFile(self): 5434 def __searchProjectFile(self):
5381 """ 5435 """
5382 Private slot to show the Find Project File dialog. 5436 Private slot to show the Find Project File dialog.
5383 """ 5437 """
5438 from .QuickFindFileDialog import QuickFindFileDialog
5439
5384 if self.__findProjectFileDialog is None: 5440 if self.__findProjectFileDialog is None:
5385 from .QuickFindFileDialog import QuickFindFileDialog
5386
5387 self.__findProjectFileDialog = QuickFindFileDialog(self) 5441 self.__findProjectFileDialog = QuickFindFileDialog(self)
5388 self.__findProjectFileDialog.sourceFile.connect(self.sourceFile) 5442 self.__findProjectFileDialog.sourceFile.connect(self.sourceFile)
5389 self.__findProjectFileDialog.designerFile.connect(self.designerFile) 5443 self.__findProjectFileDialog.designerFile.connect(self.designerFile)
5390 self.__findProjectFileDialog.linguistFile.connect(self.linguistFile) 5444 self.__findProjectFileDialog.linguistFile.connect(self.linguistFile)
5391 self.__findProjectFileDialog.show() 5445 self.__findProjectFileDialog.show()
5404 @param AI flag indicating whether the automatic inclusion should 5458 @param AI flag indicating whether the automatic inclusion should
5405 be honoured (boolean) 5459 be honoured (boolean)
5406 @param onUserDemand flag indicating whether this method was 5460 @param onUserDemand flag indicating whether this method was
5407 requested by the user via a menu action (boolean) 5461 requested by the user via a menu action (boolean)
5408 """ 5462 """
5463 from .AddFoundFilesDialog import AddFoundFilesDialog
5464
5409 autoInclude = Preferences.getProject("AutoIncludeNewFiles") 5465 autoInclude = Preferences.getProject("AutoIncludeNewFiles")
5410 recursiveSearch = Preferences.getProject("SearchNewFilesRecursively") 5466 recursiveSearch = Preferences.getProject("SearchNewFilesRecursively")
5411 newFiles = [] 5467 newFiles = []
5412 5468
5413 ignore_patterns = [ 5469 ignore_patterns = [
5414 pattern 5470 pattern
5415 for pattern, filetype in self.pdata["FILETYPES"].items() 5471 for pattern, filetype in self.__pdata["FILETYPES"].items()
5416 if filetype == "__IGNORE__" 5472 if filetype == "__IGNORE__"
5417 ] 5473 ]
5418 5474
5419 dirs = self.subdirs[:] 5475 dirs = self.subdirs[:]
5420 for directory in dirs: 5476 for directory in dirs:
5430 try: 5486 try:
5431 newSources = os.listdir(curpath) 5487 newSources = os.listdir(curpath)
5432 except OSError: 5488 except OSError:
5433 newSources = [] 5489 newSources = []
5434 pattern = ( 5490 pattern = (
5435 self.pdata["TRANSLATIONPATTERN"].replace("%language%", "*") 5491 self.__pdata["TRANSLATIONPATTERN"].replace("%language%", "*")
5436 if self.pdata["TRANSLATIONPATTERN"] 5492 if self.__pdata["TRANSLATIONPATTERN"]
5437 else "*.ts" 5493 else "*.ts"
5438 ) 5494 )
5439 binpattern = self.__binaryTranslationFile(pattern) 5495 binpattern = self.__binaryTranslationFile(pattern)
5440 for ns in newSources: 5496 for ns in newSources:
5441 # ignore hidden files and directories 5497 # ignore hidden files and directories
5463 dirs.append(d) 5519 dirs.append(d)
5464 continue 5520 continue
5465 5521
5466 filetype = "" 5522 filetype = ""
5467 bfn = os.path.basename(fn) 5523 bfn = os.path.basename(fn)
5468 for pattern in sorted(self.pdata["FILETYPES"].keys(), reverse=True): 5524 for pattern in sorted(self.__pdata["FILETYPES"].keys(), reverse=True):
5469 if fnmatch.fnmatch(bfn, pattern): 5525 if fnmatch.fnmatch(bfn, pattern):
5470 filetype = self.pdata["FILETYPES"][pattern] 5526 filetype = self.__pdata["FILETYPES"][pattern]
5471 break 5527 break
5472 5528
5473 if ( 5529 if (
5474 (filetype == "SOURCES" and fn not in self.pdata["SOURCES"]) 5530 filetype in self.getFileCategories()
5475 or (filetype == "FORMS" and fn not in self.pdata["FORMS"]) 5531 and fn not in self.__pdata[filetype]
5476 or (filetype == "INTERFACES" and fn not in self.pdata["INTERFACES"]) 5532 and (
5477 or (filetype == "PROTOCOLS" and fn not in self.pdata["PROTOCOLS"]) 5533 filetype != "TRANSLATIONS"
5478 or (filetype == "RESOURCES" and fn not in self.pdata["RESOURCES"]) 5534 or (
5479 or (filetype == "OTHERS" and fn not in self.pdata["OTHERS"]) 5535 filetype == "TRANSLATIONS"
5480 or ( 5536 and (
5481 filetype == "TRANSLATIONS" 5537 fnmatch.fnmatch(ns, pattern)
5482 and fn not in self.pdata["TRANSLATIONS"] 5538 or fnmatch.fnmatch(ns, binpattern)
5483 and ( 5539 )
5484 fnmatch.fnmatch(ns, pattern)
5485 or fnmatch.fnmatch(ns, binpattern)
5486 ) 5540 )
5487 ) 5541 )
5488 ): 5542 ):
5489 if autoInclude and AI: 5543 if autoInclude and AI:
5490 self.appendFile(ns) 5544 self.appendFile(ns)
5504 self.tr("There were no new files found to be added."), 5558 self.tr("There were no new files found to be added."),
5505 ) 5559 )
5506 return 5560 return
5507 5561
5508 # autoInclude is not set, show a dialog 5562 # autoInclude is not set, show a dialog
5509 from .AddFoundFilesDialog import AddFoundFilesDialog
5510
5511 dlg = AddFoundFilesDialog(newFiles, self.parent(), None) 5563 dlg = AddFoundFilesDialog(newFiles, self.parent(), None)
5512 res = dlg.exec() 5564 res = dlg.exec()
5513 5565
5514 # the 'Add All' button was pressed 5566 # the 'Add All' button was pressed
5515 if res == 1: 5567 if res == 1:
5529 5581
5530 @param fn filename or directory name added (string) 5582 @param fn filename or directory name added (string)
5531 @param updateModel flag indicating an update of the model is requested 5583 @param updateModel flag indicating an update of the model is requested
5532 (boolean) 5584 (boolean)
5533 """ 5585 """
5534 self.projectOthersAdded.emit(fn) 5586 self.projectFileAdded.emit(fn, "OTHERS")
5535 updateModel and self.__model.addNewItem("OTHERS", fn) 5587 updateModel and self.__model.addNewItem("OTHERS", fn)
5536 5588
5537 def getActions(self): 5589 def getActions(self):
5538 """ 5590 """
5539 Public method to get a list of all actions. 5591 Public method to get a list of all actions.
5598 @param vcsSystem type of VCS to be used (string) 5650 @param vcsSystem type of VCS to be used (string)
5599 @param nooverride flag indicating to ignore an override request 5651 @param nooverride flag indicating to ignore an override request
5600 (boolean) 5652 (boolean)
5601 @return a reference to the vcs object 5653 @return a reference to the vcs object
5602 """ 5654 """
5655 from eric7 import VCS
5656
5603 vcs = None 5657 vcs = None
5604 forProject = True 5658 forProject = True
5605 override = False 5659 override = False
5606 5660
5607 if vcsSystem is None: 5661 if vcsSystem is None:
5608 if self.pdata["VCS"] and self.pdata["VCS"] != "None": 5662 if self.__pdata["VCS"] and self.__pdata["VCS"] != "None":
5609 vcsSystem = self.pdata["VCS"] 5663 vcsSystem = self.__pdata["VCS"]
5610 else: 5664 else:
5611 forProject = False 5665 forProject = False
5612 5666
5613 if ( 5667 if (
5614 forProject 5668 forProject
5615 and self.pdata["VCS"] 5669 and self.__pdata["VCS"]
5616 and self.pdata["VCS"] != "None" 5670 and self.__pdata["VCS"] != "None"
5617 and self.pudata["VCSOVERRIDE"] 5671 and self.pudata["VCSOVERRIDE"]
5618 and not nooverride 5672 and not nooverride
5619 ): 5673 ):
5620 vcsSystem = self.pudata["VCSOVERRIDE"] 5674 vcsSystem = self.pudata["VCSOVERRIDE"]
5621 override = True 5675 override = True
5622 5676
5623 if vcsSystem is not None: 5677 if vcsSystem is not None:
5624 from eric7 import VCS
5625
5626 try: 5678 try:
5627 vcs = VCS.factory(vcsSystem) 5679 vcs = VCS.factory(vcsSystem)
5628 except ImportError: 5680 except ImportError:
5629 if override: 5681 if override:
5630 # override failed, revert to original 5682 # override failed, revert to original
5659 "<p>{1}</p>" 5711 "<p>{1}</p>"
5660 ).format(vcsSystem, msg), 5712 ).format(vcsSystem, msg),
5661 ) 5713 )
5662 vcs = None 5714 vcs = None
5663 if forProject: 5715 if forProject:
5664 self.pdata["VCS"] = "None" 5716 self.__pdata["VCS"] = "None"
5665 self.setDirty(True) 5717 self.setDirty(True)
5666 else: 5718 else:
5667 vcs.vcsInitConfig(self) 5719 vcs.vcsInitConfig(self)
5668 5720
5669 if vcs and forProject: 5721 if vcs and forProject:
5670 # set the vcs options 5722 # set the vcs options
5671 if vcs.vcsSupportCommandOptions(): 5723 if vcs.vcsSupportCommandOptions():
5672 with contextlib.suppress(LookupError): 5724 with contextlib.suppress(LookupError):
5673 vcsopt = copy.deepcopy(self.pdata["VCSOPTIONS"]) 5725 vcsopt = copy.deepcopy(self.__pdata["VCSOPTIONS"])
5674 vcs.vcsSetOptions(vcsopt) 5726 vcs.vcsSetOptions(vcsopt)
5675 # set vcs specific data 5727 # set vcs specific data
5676 with contextlib.suppress(LookupError): 5728 with contextlib.suppress(LookupError):
5677 vcsother = copy.deepcopy(self.pdata["VCSOTHERDATA"]) 5729 vcsother = copy.deepcopy(self.__pdata["VCSOTHERDATA"])
5678 vcs.vcsSetOtherData(vcsother) 5730 vcs.vcsSetOtherData(vcsother)
5679 5731
5680 if forProject: 5732 if forProject:
5681 if vcs is None: 5733 if vcs is None:
5682 from eric7 import VCS
5683
5684 self.vcsProjectHelper = VCS.getBasicHelper(self) 5734 self.vcsProjectHelper = VCS.getBasicHelper(self)
5685 self.vcsBasicHelper = True 5735 self.vcsBasicHelper = True
5686 else: 5736 else:
5687 self.vcsProjectHelper = vcs.vcsGetProjectHelper(self) 5737 self.vcsProjectHelper = vcs.vcsGetProjectHelper(self)
5688 self.vcsBasicHelper = False 5738 self.vcsBasicHelper = False
5694 5744
5695 def resetVCS(self): 5745 def resetVCS(self):
5696 """ 5746 """
5697 Public method to reset the VCS. 5747 Public method to reset the VCS.
5698 """ 5748 """
5699 self.pdata["VCS"] = "None" 5749 self.__pdata["VCS"] = "None"
5700 self.vcs = self.initVCS() 5750 self.vcs = self.initVCS()
5701 ericApp().getObject("PluginManager").deactivateVcsPlugins() 5751 ericApp().getObject("PluginManager").deactivateVcsPlugins()
5702 5752
5703 def __showContextMenuVCS(self): 5753 def __showContextMenuVCS(self):
5704 """ 5754 """
5779 5829
5780 def __showCodeMetrics(self): 5830 def __showCodeMetrics(self):
5781 """ 5831 """
5782 Private slot used to calculate some code metrics for the project files. 5832 Private slot used to calculate some code metrics for the project files.
5783 """ 5833 """
5834 from eric7.DataViews.CodeMetricsDialog import CodeMetricsDialog
5835
5784 files = [ 5836 files = [
5785 os.path.join(self.ppath, file) 5837 os.path.join(self.ppath, file)
5786 for file in self.pdata["SOURCES"] 5838 for file in self.__pdata["SOURCES"]
5787 if file.endswith(".py") 5839 if file.endswith(".py")
5788 ] 5840 ]
5789 from eric7.DataViews.CodeMetricsDialog import CodeMetricsDialog
5790
5791 self.codemetrics = CodeMetricsDialog() 5841 self.codemetrics = CodeMetricsDialog()
5792 self.codemetrics.show() 5842 self.codemetrics.show()
5793 self.codemetrics.prepare(files) 5843 self.codemetrics.prepare(files)
5794 5844
5795 def __showCodeCoverage(self): 5845 def __showCodeCoverage(self):
5796 """ 5846 """
5797 Private slot used to show the code coverage information for the 5847 Private slot used to show the code coverage information for the
5798 project files. 5848 project files.
5799 """ 5849 """
5850 from eric7.DataViews.PyCoverageDialog import PyCoverageDialog
5851
5800 fn = self.getMainScript(True) 5852 fn = self.getMainScript(True)
5801 if fn is None: 5853 if fn is None:
5802 EricMessageBox.critical( 5854 EricMessageBox.critical(
5803 self.ui, 5855 self.ui,
5804 self.tr("Coverage Data"), 5856 self.tr("Coverage Data"),
5827 else: 5879 else:
5828 return 5880 return
5829 5881
5830 files = [ 5882 files = [
5831 os.path.join(self.ppath, file) 5883 os.path.join(self.ppath, file)
5832 for file in self.pdata["SOURCES"] 5884 for file in self.__pdata["SOURCES"]
5833 if os.path.splitext(file)[1].startswith(".py") 5885 if os.path.splitext(file)[1].startswith(".py")
5834 ] 5886 ]
5835 from eric7.DataViews.PyCoverageDialog import PyCoverageDialog
5836
5837 self.codecoverage = PyCoverageDialog() 5887 self.codecoverage = PyCoverageDialog()
5838 self.codecoverage.show() 5888 self.codecoverage.show()
5839 self.codecoverage.start(fn, files) 5889 self.codecoverage.start(fn, files)
5840 5890
5841 def __showProfileData(self): 5891 def __showProfileData(self):
5842 """ 5892 """
5843 Private slot used to show the profiling information for the project. 5893 Private slot used to show the profiling information for the project.
5844 """ 5894 """
5895 from eric7.DataViews.PyProfileDialog import PyProfileDialog
5896
5845 fn = self.getMainScript(True) 5897 fn = self.getMainScript(True)
5846 if fn is None: 5898 if fn is None:
5847 EricMessageBox.critical( 5899 EricMessageBox.critical(
5848 self.ui, 5900 self.ui,
5849 self.tr("Profile Data"), 5901 self.tr("Profile Data"),
5870 else: 5922 else:
5871 fn = files[0] 5923 fn = files[0]
5872 else: 5924 else:
5873 return 5925 return
5874 5926
5875 from eric7.DataViews.PyProfileDialog import PyProfileDialog
5876
5877 self.profiledata = PyProfileDialog() 5927 self.profiledata = PyProfileDialog()
5878 self.profiledata.show() 5928 self.profiledata.show()
5879 self.profiledata.start(fn) 5929 self.profiledata.start(fn)
5880 5930
5881 def __showContextMenuShow(self): 5931 def __showContextMenuShow(self):
5907 5957
5908 def handleApplicationDiagram(self): 5958 def handleApplicationDiagram(self):
5909 """ 5959 """
5910 Public method to handle the application diagram context menu action. 5960 Public method to handle the application diagram context menu action.
5911 """ 5961 """
5962 from eric7.Graphics.UMLDialog import UMLDialog, UMLDialogType
5963
5912 res = EricMessageBox.yesNo( 5964 res = EricMessageBox.yesNo(
5913 self.ui, 5965 self.ui,
5914 self.tr("Application Diagram"), 5966 self.tr("Application Diagram"),
5915 self.tr("""Include module names?"""), 5967 self.tr("""Include module names?"""),
5916 yesDefault=True, 5968 yesDefault=True,
5917 ) 5969 )
5918
5919 from eric7.Graphics.UMLDialog import UMLDialog, UMLDialogType
5920 5970
5921 self.applicationDiagram = UMLDialog( 5971 self.applicationDiagram = UMLDialog(
5922 UMLDialogType.APPLICATION_DIAGRAM, self, self.parent(), noModules=not res 5972 UMLDialogType.APPLICATION_DIAGRAM, self, self.parent(), noModules=not res
5923 ) 5973 )
5924 self.applicationDiagram.show() 5974 self.applicationDiagram.show()
6057 if not res: 6107 if not res:
6058 return # don't overwrite 6108 return # don't overwrite
6059 6109
6060 # build the list of entries 6110 # build the list of entries
6061 lst_ = [] 6111 lst_ = []
6062 for key in [ 6112 for key in self.getFileCategories():
6063 "SOURCES", 6113 lst_.extend(self.__pdata[key])
6064 "FORMS",
6065 "RESOURCES",
6066 "TRANSLATIONS",
6067 "INTERFACES",
6068 "PROTOCOLS",
6069 "OTHERS",
6070 ]:
6071 lst_.extend(self.pdata[key])
6072 lst = [] 6114 lst = []
6073 for entry in lst_: 6115 for entry in lst_:
6074 if os.path.isdir(self.getAbsolutePath(entry)): 6116 if os.path.isdir(self.getAbsolutePath(entry)):
6075 lst.extend( 6117 lst.extend(
6076 [ 6118 [
6093 " ", 6135 " ",
6094 ] 6136 ]
6095 6137
6096 # write the file 6138 # write the file
6097 try: 6139 try:
6098 newline = None if self.pdata["EOL"] == 0 else self.getEolString() 6140 newline = None if self.__pdata["EOL"] == 0 else self.getEolString()
6099 with open(pkglist, "w", encoding="utf-8", newline=newline) as pkglistFile: 6141 with open(pkglist, "w", encoding="utf-8", newline=newline) as pkglistFile:
6100 pkglistFile.write("\n".join(header) + "\n") 6142 pkglistFile.write("\n".join(header) + "\n")
6101 pkglistFile.write( 6143 pkglistFile.write(
6102 "\n".join([Utilities.fromNativeSeparators(f) for f in lst]) 6144 "\n".join([Utilities.fromNativeSeparators(f) for f in lst])
6103 ) 6145 )
6112 """<p>Reason: {0}</p>""" 6154 """<p>Reason: {0}</p>"""
6113 ).format(str(why)), 6155 ).format(str(why)),
6114 ) 6156 )
6115 return 6157 return
6116 6158
6117 if "PKGLIST" not in self.pdata["OTHERS"]: 6159 if "PKGLIST" not in self.__pdata["OTHERS"]:
6118 self.appendFile("PKGLIST") 6160 self.appendFile("PKGLIST")
6119 6161
6120 @pyqtSlot() 6162 @pyqtSlot()
6121 def __pluginCreateArchives(self, snapshot=False): 6163 def __pluginCreateArchives(self, snapshot=False):
6122 """ 6164 """
6123 Private slot to create eric plugin archives. 6165 Private slot to create eric plugin archives.
6124 6166
6125 @param snapshot flag indicating snapshot archives (boolean) 6167 @param snapshot flag indicating snapshot archives (boolean)
6126 """ 6168 """
6127 if not self.pdata["MAINSCRIPT"]: 6169 if not self.__pdata["MAINSCRIPT"]:
6128 EricMessageBox.critical( 6170 EricMessageBox.critical(
6129 self.ui, 6171 self.ui,
6130 self.tr("Create Plugin Archive"), 6172 self.tr("Create Plugin Archive"),
6131 self.tr( 6173 self.tr(
6132 """The project does not have a main script defined. """ 6174 """The project does not have a main script defined. """
6236 names = sorted(names) 6278 names = sorted(names)
6237 archive = ( 6279 archive = (
6238 os.path.join(self.ppath, archiveName) 6280 os.path.join(self.ppath, archiveName)
6239 if archiveName 6281 if archiveName
6240 else os.path.join( 6282 else os.path.join(
6241 self.ppath, self.pdata["MAINSCRIPT"].replace(".py", ".zip") 6283 self.ppath, self.__pdata["MAINSCRIPT"].replace(".py", ".zip")
6242 ) 6284 )
6243 ) 6285 )
6244 try: 6286 try:
6245 archiveFile = zipfile.ZipFile(archive, "w") 6287 archiveFile = zipfile.ZipFile(archive, "w")
6246 except OSError as why: 6288 except OSError as why:
6258 6300
6259 for name in names: 6301 for name in names:
6260 if name: 6302 if name:
6261 try: 6303 try:
6262 self.__createZipDirEntries(os.path.split(name)[0], archiveFile) 6304 self.__createZipDirEntries(os.path.split(name)[0], archiveFile)
6263 if snapshot and name == self.pdata["MAINSCRIPT"]: 6305 if snapshot and name == self.__pdata["MAINSCRIPT"]:
6264 snapshotSource, version = self.__createSnapshotSource( 6306 snapshotSource, version = self.__createSnapshotSource(
6265 os.path.join(self.ppath, self.pdata["MAINSCRIPT"]) 6307 os.path.join(self.ppath, self.__pdata["MAINSCRIPT"])
6266 ) 6308 )
6267 archiveFile.writestr(name, snapshotSource) 6309 archiveFile.writestr(name, snapshotSource)
6268 else: 6310 else:
6269 archiveFile.write(os.path.join(self.ppath, name), name) 6311 archiveFile.write(os.path.join(self.ppath, name), name)
6270 if name == self.pdata["MAINSCRIPT"]: 6312 if name == self.__pdata["MAINSCRIPT"]:
6271 version = self.__pluginExtractVersion( 6313 version = self.__pluginExtractVersion(
6272 os.path.join(self.ppath, self.pdata["MAINSCRIPT"]) 6314 os.path.join(self.ppath, self.__pdata["MAINSCRIPT"])
6273 ) 6315 )
6274 if archiveVersion and ( 6316 if archiveVersion and (
6275 self.__pluginVersionToTuple(version) 6317 self.__pluginVersionToTuple(version)
6276 < self.__pluginVersionToTuple(archiveVersion) 6318 < self.__pluginVersionToTuple(archiveVersion)
6277 ): 6319 ):
6287 ).format(os.path.join(self.ppath, name), str(why)), 6329 ).format(os.path.join(self.ppath, name), str(why)),
6288 ) 6330 )
6289 archiveFile.writestr("VERSION", version.encode("utf-8")) 6331 archiveFile.writestr("VERSION", version.encode("utf-8"))
6290 archiveFile.close() 6332 archiveFile.close()
6291 6333
6292 if archive not in self.pdata["OTHERS"]: 6334 if archive not in self.__pdata["OTHERS"]:
6293 self.appendFile(archive) 6335 self.appendFile(archive)
6294 6336
6295 progress.setValue(len(selectedLists)) 6337 progress.setValue(len(selectedLists))
6296 6338
6297 if errors: 6339 if errors:
6432 parameters. 6474 parameters.
6433 6475
6434 @return flag indicating default parameter set 6476 @return flag indicating default parameter set
6435 @rtype bool 6477 @rtype bool
6436 """ 6478 """
6437 return self.pdata["MAKEPARAMS"] == { 6479 return self.__pdata["MAKEPARAMS"] == {
6438 "MakeEnabled": False, 6480 "MakeEnabled": False,
6439 "MakeExecutable": "", 6481 "MakeExecutable": "",
6440 "MakeFile": "", 6482 "MakeFile": "",
6441 "MakeTarget": "", 6483 "MakeTarget": "",
6442 "MakeParameters": "", 6484 "MakeParameters": "",
6448 Public method to test, if make is enabled for the project. 6490 Public method to test, if make is enabled for the project.
6449 6491
6450 @return flag indicating enabled make support 6492 @return flag indicating enabled make support
6451 @rtype bool 6493 @rtype bool
6452 """ 6494 """
6453 return self.pdata["MAKEPARAMS"]["MakeEnabled"] 6495 return self.__pdata["MAKEPARAMS"]["MakeEnabled"]
6454 6496
6455 @pyqtSlot() 6497 @pyqtSlot()
6456 def executeMake(self): 6498 def __autoExecuteMake(self):
6457 """ 6499 """
6458 Public slot to execute a project specific make run (auto-run) 6500 Private slot to execute a project specific make run (auto-run)
6459 (execute or question). 6501 (execute or question).
6460 """ 6502 """
6461 self.__executeMake( 6503 if Preferences.getProject("AutoExecuteMake"):
6462 questionOnly=self.pdata["MAKEPARAMS"]["MakeTestOnly"], interactive=False 6504 self.__executeMake(
6463 ) 6505 questionOnly=self.__pdata["MAKEPARAMS"]["MakeTestOnly"],
6506 interactive=False,
6507 )
6464 6508
6465 @pyqtSlot() 6509 @pyqtSlot()
6466 def __executeMake(self, questionOnly=False, interactive=True): 6510 def __executeMake(self, questionOnly=False, interactive=True):
6467 """ 6511 """
6468 Private method to execute a project specific make run. 6512 Private method to execute a project specific make run.
6472 @param interactive flag indicating an interactive invocation (i.e. 6516 @param interactive flag indicating an interactive invocation (i.e.
6473 through a menu action) 6517 through a menu action)
6474 @type bool 6518 @type bool
6475 """ 6519 """
6476 if ( 6520 if (
6477 not self.pdata["MAKEPARAMS"]["MakeEnabled"] 6521 not self.__pdata["MAKEPARAMS"]["MakeEnabled"]
6478 or self.__makeProcess is not None 6522 or self.__makeProcess is not None
6479 ): 6523 ):
6480 return 6524 return
6481 6525
6482 prog = ( 6526 prog = (
6483 self.pdata["MAKEPARAMS"]["MakeExecutable"] 6527 self.__pdata["MAKEPARAMS"]["MakeExecutable"]
6484 if self.pdata["MAKEPARAMS"]["MakeExecutable"] 6528 if self.__pdata["MAKEPARAMS"]["MakeExecutable"]
6485 else Project.DefaultMake 6529 else Project.DefaultMake
6486 ) 6530 )
6487 6531
6488 args = [] 6532 args = []
6489 if self.pdata["MAKEPARAMS"]["MakeParameters"]: 6533 if self.__pdata["MAKEPARAMS"]["MakeParameters"]:
6490 args.extend( 6534 args.extend(
6491 Utilities.parseOptionString(self.pdata["MAKEPARAMS"]["MakeParameters"]) 6535 Utilities.parseOptionString(
6492 ) 6536 self.__pdata["MAKEPARAMS"]["MakeParameters"]
6493 6537 )
6494 if self.pdata["MAKEPARAMS"]["MakeFile"]: 6538 )
6495 args.append("--makefile={0}".format(self.pdata["MAKEPARAMS"]["MakeFile"])) 6539
6540 if self.__pdata["MAKEPARAMS"]["MakeFile"]:
6541 args.append("--makefile={0}".format(self.__pdata["MAKEPARAMS"]["MakeFile"]))
6496 6542
6497 if questionOnly: 6543 if questionOnly:
6498 args.append("--question") 6544 args.append("--question")
6499 6545
6500 if self.pdata["MAKEPARAMS"]["MakeTarget"]: 6546 if self.__pdata["MAKEPARAMS"]["MakeTarget"]:
6501 args.append(self.pdata["MAKEPARAMS"]["MakeTarget"]) 6547 args.append(self.__pdata["MAKEPARAMS"]["MakeTarget"])
6502 6548
6503 self.__makeProcess = QProcess(self) 6549 self.__makeProcess = QProcess(self)
6504 self.__makeProcess.readyReadStandardOutput.connect(self.__makeReadStdOut) 6550 self.__makeProcess.readyReadStandardOutput.connect(self.__makeReadStdOut)
6505 self.__makeProcess.readyReadStandardError.connect(self.__makeReadStdErr) 6551 self.__makeProcess.readyReadStandardError.connect(self.__makeReadStdErr)
6506 self.__makeProcess.finished.connect( 6552 self.__makeProcess.finished.connect(
6569 else: 6615 else:
6570 if questionOnly and exitCode == 1: 6616 if questionOnly and exitCode == 1:
6571 # a rebuild is needed 6617 # a rebuild is needed
6572 title = self.tr("Test for Changes") 6618 title = self.tr("Test for Changes")
6573 6619
6574 if self.pdata["MAKEPARAMS"]["MakeTarget"]: 6620 if self.__pdata["MAKEPARAMS"]["MakeTarget"]:
6575 message = self.tr( 6621 message = self.tr(
6576 """<p>There are changes that require the configured""" 6622 """<p>There are changes that require the configured"""
6577 """ make target <b>{0}</b> to be rebuilt.</p>""" 6623 """ make target <b>{0}</b> to be rebuilt.</p>"""
6578 ).format(self.pdata["MAKEPARAMS"]["MakeTarget"]) 6624 ).format(self.__pdata["MAKEPARAMS"]["MakeTarget"])
6579 else: 6625 else:
6580 message = self.tr( 6626 message = self.tr(
6581 """<p>There are changes that require the default""" 6627 """<p>There are changes that require the default"""
6582 """ make target to be rebuilt.</p>""" 6628 """ make target to be rebuilt.</p>"""
6583 ) 6629 )
6618 parameters. 6664 parameters.
6619 6665
6620 @return flag indicating default parameter set 6666 @return flag indicating default parameter set
6621 @rtype bool 6667 @rtype bool
6622 """ 6668 """
6623 return self.pdata["IDLPARAMS"] == { 6669 return self.__pdata["IDLPARAMS"] == {
6624 "IncludeDirs": [], 6670 "IncludeDirs": [],
6625 "DefinedNames": [], 6671 "DefinedNames": [],
6626 "UndefinedNames": [], 6672 "UndefinedNames": [],
6627 } 6673 }
6628 6674
6636 parameters. 6682 parameters.
6637 6683
6638 @return flag indicating default parameter set 6684 @return flag indicating default parameter set
6639 @rtype bool 6685 @rtype bool
6640 """ 6686 """
6641 return self.pdata["UICPARAMS"] == { 6687 return self.__pdata["UICPARAMS"] == {
6642 "Package": "", 6688 "Package": "",
6643 "RcSuffix": "", 6689 "RcSuffix": "",
6644 "PackagesRoot": "", 6690 "PackagesRoot": "",
6645 } 6691 }
6646 6692
6651 @param name name of the parameter 6697 @param name name of the parameter
6652 @type str 6698 @type str
6653 @return value of the given parameter 6699 @return value of the given parameter
6654 @rtype any, None in case on non-existence 6700 @rtype any, None in case on non-existence
6655 """ 6701 """
6656 if name in self.pdata["UICPARAMS"]: 6702 if name in self.__pdata["UICPARAMS"]:
6657 return self.pdata["UICPARAMS"][name] 6703 return self.__pdata["UICPARAMS"][name]
6658 else: 6704 else:
6659 return None 6705 return None
6660 6706
6661 ######################################################################### 6707 #########################################################################
6662 ## Below are methods implementing some 'RCC' support functions 6708 ## Below are methods implementing some 'RCC' support functions
6668 parameters. 6714 parameters.
6669 6715
6670 @return flag indicating default parameter set 6716 @return flag indicating default parameter set
6671 @rtype bool 6717 @rtype bool
6672 """ 6718 """
6673 return self.pdata["RCCPARAMS"] == self.getDefaultRccCompilerParameters() 6719 return self.__pdata["RCCPARAMS"] == self.getDefaultRccCompilerParameters()
6674 6720
6675 def getDefaultRccCompilerParameters(self): 6721 def getDefaultRccCompilerParameters(self):
6676 """ 6722 """
6677 Public method to get the default rcc compiler parameters. 6723 Public method to get the default rcc compiler parameters.
6678 6724
6696 parameter. 6742 parameter.
6697 6743
6698 @return flag indicating default parameter 6744 @return flag indicating default parameter
6699 @rtype bool 6745 @rtype bool
6700 """ 6746 """
6701 return self.pdata["DOCSTRING"] == "" 6747 return self.__pdata["DOCSTRING"] == ""
6702 6748
6703 def getDocstringType(self): 6749 def getDocstringType(self):
6704 """ 6750 """
6705 Public method to get the configured docstring style. 6751 Public method to get the configured docstring style.
6706 6752
6707 @return configured docstring style 6753 @return configured docstring style
6708 @rtype str 6754 @rtype str
6709 """ 6755 """
6710 return self.pdata["DOCSTRING"] 6756 return self.__pdata["DOCSTRING"]
6711 6757
6712 ######################################################################### 6758 #########################################################################
6713 ## Below are methods implementing the 'SBOM' support 6759 ## Below are methods implementing the 'SBOM' support
6714 ######################################################################### 6760 #########################################################################
6715 6761
6722 @pyqtSlot() 6768 @pyqtSlot()
6723 def __createSBOMFile(self): 6769 def __createSBOMFile(self):
6724 """ 6770 """
6725 Private slot to create a SBOM file of the project dependencies. 6771 Private slot to create a SBOM file of the project dependencies.
6726 """ 6772 """
6727 import CycloneDXInterface 6773 import CycloneDXInterface # __IGNORE_WARNING_I102__
6728 6774
6729 CycloneDXInterface.createCycloneDXFile("<project>") 6775 CycloneDXInterface.createCycloneDXFile("<project>")
6730 6776
6731 ######################################################################### 6777 #########################################################################
6732 ## Below are methods implementing the 'Code Formatting' support 6778 ## Below are methods implementing the 'Code Formatting' support
6785 dlg = BlackConfigurationDialog(withProject=True, onlyProject=True) 6831 dlg = BlackConfigurationDialog(withProject=True, onlyProject=True)
6786 if dlg.exec() == QDialog.DialogCode.Accepted: 6832 if dlg.exec() == QDialog.DialogCode.Accepted:
6787 dlg.getConfiguration(saveToProject=True) 6833 dlg.getConfiguration(saveToProject=True)
6788 # The data is saved to the project as a side effect. 6834 # The data is saved to the project as a side effect.
6789 6835
6836 def __performImportSortingWithIsort(self, action):
6837 """
6838 Private method to format the project sources import statements using the
6839 'isort' tool.
6840
6841 Following actions are supported.
6842 <ul>
6843 <li>IsortFormattingAction.Format - the imports reformatting is performed</li>
6844 <li>IsortFormattingAction.Check - a check is performed, if imports formatting
6845 is necessary</li>
6846 <li>IsortFormattingAction.Diff - a unified diff of potential imports formatting
6847 changes is generated</li>
6848 </ul>
6849
6850 @param action formatting operation to be performed
6851 @type IsortFormattingAction
6852 """
6853 from eric7.CodeFormatting.IsortConfigurationDialog import (
6854 IsortConfigurationDialog,
6855 )
6856 from eric7.CodeFormatting.IsortFormattingDialog import IsortFormattingDialog
6857
6858 if ericApp().getObject("ViewManager").checkAllDirty():
6859 dlg = IsortConfigurationDialog(withProject=True)
6860 if dlg.exec() == QDialog.DialogCode.Accepted:
6861 config = dlg.getConfiguration(saveToProject=True)
6862
6863 isortDialog = IsortFormattingDialog(
6864 config,
6865 self.getProjectFiles("SOURCES", normalized=True),
6866 project=self,
6867 action=action,
6868 )
6869 isortDialog.exec()
6870
6871 @pyqtSlot()
6872 def __configureIsort(self):
6873 """
6874 Private slot to enter the parameters for formatting the import statements of the
6875 project sources with 'isort'.
6876 """
6877 from eric7.CodeFormatting.IsortConfigurationDialog import (
6878 IsortConfigurationDialog,
6879 )
6880
6881 dlg = IsortConfigurationDialog(withProject=True, onlyProject=True)
6882 if dlg.exec() == QDialog.DialogCode.Accepted:
6883 dlg.getConfiguration(saveToProject=True)
6884 # The data is saved to the project as a side effect.
6885
6790 ######################################################################### 6886 #########################################################################
6791 ## Below are methods implementing the 'Embedded Environment' support 6887 ## Below are methods implementing the 'Embedded Environment' support
6792 ######################################################################### 6888 #########################################################################
6793 6889
6794 def __showContextMenuEnvironment(self): 6890 def __showContextMenuEnvironment(self):
6818 Private method to set the embedded environment project configuration. 6914 Private method to set the embedded environment project configuration.
6819 6915
6820 @param value flag indicating an embedded environment 6916 @param value flag indicating an embedded environment
6821 @type bool 6917 @type bool
6822 """ 6918 """
6823 if value != self.pdata["EMBEDDED_VENV"]: 6919 if value != self.__pdata["EMBEDDED_VENV"]:
6824 self.pdata["EMBEDDED_VENV"] = value 6920 self.__pdata["EMBEDDED_VENV"] = value
6825 self.setDirty(True) 6921 self.setDirty(True)
6826 6922
6827 def __initVenvConfiguration(self): 6923 def __initVenvConfiguration(self):
6828 """ 6924 """
6829 Private method to initialize the environment configuration. 6925 Private method to initialize the environment configuration.
6841 6937
6842 @param upgrade flag indicating an upgrade operation (defaults to False) 6938 @param upgrade flag indicating an upgrade operation (defaults to False)
6843 @type bool (optional) 6939 @type bool (optional)
6844 """ 6940 """
6845 from eric7.VirtualEnv.VirtualenvExecDialog import VirtualenvExecDialog 6941 from eric7.VirtualEnv.VirtualenvExecDialog import VirtualenvExecDialog
6942
6846 from .ProjectVenvCreationParametersDialog import ( 6943 from .ProjectVenvCreationParametersDialog import (
6847 ProjectVenvCreationParametersDialog, 6944 ProjectVenvCreationParametersDialog,
6848 ) 6945 )
6849 6946
6850 dlg = ProjectVenvCreationParametersDialog( 6947 dlg = ProjectVenvCreationParametersDialog(

eric ide

mercurial