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) |
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 |
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 |
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. |
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"), |
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 |
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) |
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 != "": |
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. |
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) |
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 |
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 |
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() |
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(): |
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) |
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"]) |
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 |
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"] |
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 |
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. |
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 """ |
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 |
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 """ |
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) |
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 |
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"), |
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 ): |
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( |
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): |