eric6/Project/Project.py

branch
maintenance
changeset 8142
43248bafe9b2
parent 8043
0acf98cd089a
parent 8140
61113590d4ab
child 8176
31965986ecd1
equal deleted inserted replaced
8044:874fdd14d3a2 8142:43248bafe9b2
38 38
39 from E5Gui.E5Action import E5Action, createActionGroup 39 from E5Gui.E5Action import E5Action, createActionGroup
40 40
41 import Preferences 41 import Preferences
42 import Utilities 42 import Utilities
43
44 from .ProjectFile import ProjectFile
45 from .UserProjectFile import UserProjectFile
46 from .DebuggerPropertiesFile import DebuggerPropertiesFile
47
48 from Sessions.SessionFile import SessionFile
49
50 from Tasks.TasksFile import TasksFile
43 51
44 52
45 class Project(QObject): 53 class Project(QObject):
46 """ 54 """
47 Class implementing the project management functionality. 55 Class implementing the project management functionality.
182 190
183 self.__initProjectTypes() 191 self.__initProjectTypes()
184 192
185 self.__initData() 193 self.__initData()
186 194
195 self.__projectFile = ProjectFile(self)
196 self.__userProjectFile = UserProjectFile(self)
197 self.__debuggerPropertiesFile = DebuggerPropertiesFile(self)
198 self.__sessionFile = SessionFile(False)
199 self.__tasksFile = TasksFile(False)
200
187 self.recent = [] 201 self.recent = []
188 self.__loadRecent() 202 self.__loadRecent()
189 203
190 if filename is not None: 204 if filename is not None:
191 self.openProject(filename) 205 self.openProject(filename)
580 "*.md": "OTHERS", 594 "*.md": "OTHERS",
581 "*.rst": "OTHERS", 595 "*.rst": "OTHERS",
582 "README": "OTHERS", 596 "README": "OTHERS",
583 "README.*": "OTHERS", 597 "README.*": "OTHERS",
584 "*.e4p": "OTHERS", 598 "*.e4p": "OTHERS",
599 "*.epj": "OTHERS",
585 "GNUmakefile": "OTHERS", 600 "GNUmakefile": "OTHERS",
586 "makefile": "OTHERS", 601 "makefile": "OTHERS",
587 "Makefile": "OTHERS", 602 "Makefile": "OTHERS",
588 } 603 }
589 604
785 self.pdata[index].remove(file) 800 self.pdata[index].remove(file)
786 self.setDirty(True) 801 self.setDirty(True)
787 802
788 def __readProject(self, fn): 803 def __readProject(self, fn):
789 """ 804 """
790 Private method to read in a project (.e4p) file. 805 Private method to read in a project (.epj or .e4p) file.
791 806
792 @param fn filename of the project file to be read (string) 807 @param fn filename of the project file to be read (string)
793 @return flag indicating success 808 @return flag indicating success
794 """ 809 """
795 f = QFile(fn) 810 if os.path.splitext(fn)[1] == ".epj":
796 if f.open(QIODevice.ReadOnly): 811 # new JSON based format
797 from E5XML.ProjectReader import ProjectReader 812 with E5OverrideCursor():
798 reader = ProjectReader(f, self) 813 res = self.__projectFile.readFile(fn)
799 reader.readXML()
800 res = not reader.hasError()
801 f.close()
802 else: 814 else:
803 E5MessageBox.critical( 815 # old XML based format
804 self.ui, 816 f = QFile(fn)
805 self.tr("Read project file"), 817 if f.open(QIODevice.ReadOnly):
806 self.tr( 818 from E5XML.ProjectReader import ProjectReader
807 "<p>The project file <b>{0}</b> could not be read.</p>") 819 reader = ProjectReader(f, self)
808 .format(fn)) 820 reader.readXML()
809 return False 821 res = not reader.hasError()
810 822 f.close()
811 self.pfile = os.path.abspath(fn) 823
812 self.ppath = os.path.abspath(os.path.dirname(fn)) 824 # create hash value, if it doesn't have one
813 825 if reader.version.startswith("5.") and not self.pdata["HASH"]:
814 # insert filename into list of recently opened projects 826 hashStr = str(QCryptographicHash.hash(
815 self.__syncRecent() 827 QByteArray(self.ppath.encode("utf-8")),
828 QCryptographicHash.Sha1).toHex(),
829 encoding="utf-8")
830 self.pdata["HASH"] = hashStr
831 self.setDirty(True)
832 else:
833 E5MessageBox.critical(
834 self.ui,
835 self.tr("Read Project File"),
836 self.tr(
837 "<p>The project file <b>{0}</b> could not be read."
838 "</p>")
839 .format(fn))
840 res = False
816 841
817 if res: 842 if res:
843 self.pfile = os.path.abspath(fn)
844 self.ppath = os.path.abspath(os.path.dirname(fn))
845
846 # insert filename into list of recently opened projects
847 self.__syncRecent()
848
818 if self.pdata["TRANSLATIONPATTERN"]: 849 if self.pdata["TRANSLATIONPATTERN"]:
819 self.translationsRoot = self.pdata["TRANSLATIONPATTERN"].split( 850 self.translationsRoot = self.pdata["TRANSLATIONPATTERN"].split(
820 "%language%")[0] 851 "%language%")[0]
821 elif self.pdata["MAINSCRIPT"]: 852 elif self.pdata["MAINSCRIPT"]:
822 self.translationsRoot = os.path.splitext( 853 self.translationsRoot = os.path.splitext(
857 for fn in self.pdata["OTHERS"]: 888 for fn in self.pdata["OTHERS"]:
858 dn = os.path.dirname(fn) 889 dn = os.path.dirname(fn)
859 if dn not in self.otherssubdirs: 890 if dn not in self.otherssubdirs:
860 self.otherssubdirs.append(dn) 891 self.otherssubdirs.append(dn)
861 892
862 # create hash value, if it doesn't have one
863 if reader.version.startswith("5.") and not self.pdata["HASH"]:
864 hashStr = str(QCryptographicHash.hash(
865 QByteArray(self.ppath.encode("utf-8")),
866 QCryptographicHash.Sha1).toHex(),
867 encoding="utf-8")
868 self.pdata["HASH"] = hashStr
869 self.setDirty(True)
870
871 return res 893 return res
872 894
873 def __writeProject(self, fn=None): 895 def __writeProject(self, fn=None):
874 """ 896 """
875 Private method to save the project infos to a project file. 897 Private method to save the project infos to a project file.
894 self.pdata["HASH"] = hashStr 916 self.pdata["HASH"] = hashStr
895 917
896 if fn is None: 918 if fn is None:
897 fn = self.pfile 919 fn = self.pfile
898 920
899 f = QFile(fn) 921 if os.path.splitext(fn)[1] == ".epj":
900 if f.open(QIODevice.WriteOnly): 922 # new JSON based format
901 from E5XML.ProjectWriter import ProjectWriter 923 with E5OverrideCursor():
902 ProjectWriter(f, os.path.splitext( 924 res = self.__projectFile.writeFile(fn)
903 os.path.basename(fn))[0]).writeXML()
904 res = True
905 else: 925 else:
906 E5MessageBox.critical( 926 # old XML based format
907 self.ui, 927 f = QFile(fn)
908 self.tr("Save project file"), 928 if f.open(QIODevice.WriteOnly):
909 self.tr( 929 from E5XML.ProjectWriter import ProjectWriter
910 "<p>The project file <b>{0}</b> could not be" 930 ProjectWriter(f, os.path.splitext(
911 " written.</p>").format(fn)) 931 os.path.basename(fn))[0]).writeXML()
912 res = False 932 res = True
933 else:
934 E5MessageBox.critical(
935 self.ui,
936 self.tr("Save Project File"),
937 self.tr(
938 "<p>The project file <b>{0}</b> could not be"
939 " written.</p>").format(fn))
940 res = False
913 941
914 if res: 942 if res:
915 self.pfile = os.path.abspath(fn) 943 self.pfile = os.path.abspath(fn)
916 self.ppath = os.path.abspath(os.path.dirname(fn)) 944 self.ppath = os.path.abspath(os.path.dirname(fn))
917 self.name = os.path.splitext(os.path.basename(fn))[0] 945 self.name = os.path.splitext(os.path.basename(fn))[0]
922 950
923 return res 951 return res
924 952
925 def __readUserProperties(self): 953 def __readUserProperties(self):
926 """ 954 """
927 Private method to read in the user specific project file (.e4q). 955 Private method to read in the user specific project file (.eqj or
956 .e4q).
928 """ 957 """
929 if self.pfile is None: 958 if self.pfile is None:
930 return 959 return
931 960
932 fn, ext = os.path.splitext(os.path.basename(self.pfile)) 961 fn1, ext = os.path.splitext(os.path.basename(self.pfile))
933 fn = os.path.join(self.getProjectManagementDir(), '{0}.e4q'.format(fn)) 962 fn = os.path.join(self.getProjectManagementDir(),
963 '{0}.eqj'.format(fn1))
934 if os.path.exists(fn): 964 if os.path.exists(fn):
935 f = QFile(fn) 965 # try the new JSON based format first
936 if f.open(QIODevice.ReadOnly): 966 self.__userProjectFile.readFile(fn)
937 from E5XML.UserProjectReader import UserProjectReader 967 else:
938 reader = UserProjectReader(f, self) 968 # try the old XML based format second
939 reader.readXML() 969 fn = os.path.join(self.getProjectManagementDir(),
940 f.close() 970 '{0}.e4q'.format(fn1))
941 else: 971 if os.path.exists(fn):
942 E5MessageBox.critical( 972 f = QFile(fn)
943 self.ui, 973 if f.open(QIODevice.ReadOnly):
944 self.tr("Read user project properties"), 974 from E5XML.UserProjectReader import UserProjectReader
945 self.tr( 975 reader = UserProjectReader(f, self)
946 "<p>The user specific project properties file" 976 reader.readXML()
947 " <b>{0}</b> could not be read.</p>").format(fn)) 977 f.close()
978 else:
979 E5MessageBox.critical(
980 self.ui,
981 self.tr("Read User Project Properties"),
982 self.tr(
983 "<p>The user specific project properties file"
984 " <b>{0}</b> could not be read.</p>").format(fn))
948 985
949 def __writeUserProperties(self): 986 def __writeUserProperties(self):
950 """ 987 """
951 Private method to write the project data to an XML file. 988 Private method to write the user specific project data to a JSON file.
952 """ 989 """
953 if self.pfile is None: 990 if self.pfile is None:
954 return 991 return
955 992
956 fn, ext = os.path.splitext(os.path.basename(self.pfile)) 993 fn, ext = os.path.splitext(os.path.basename(self.pfile))
957 fn = os.path.join(self.getProjectManagementDir(), '{0}.e4q'.format(fn)) 994 fn = os.path.join(self.getProjectManagementDir(), '{0}.eqj'.format(fn))
958 995
959 f = QFile(fn) 996 with E5OverrideCursor():
960 if f.open(QIODevice.WriteOnly): 997 self.__userProjectFile.writeFile(fn)
961 from E5XML.UserProjectWriter import UserProjectWriter 998
962 UserProjectWriter(
963 f, os.path.splitext(os.path.basename(fn))[0]).writeXML()
964 f.close()
965 else:
966 E5MessageBox.critical(
967 self.ui,
968 self.tr("Save user project properties"),
969 self.tr(
970 "<p>The user specific project properties file <b>{0}</b>"
971 " could not be written.</p>").format(fn))
972
973 def __showContextMenuSession(self): 999 def __showContextMenuSession(self):
974 """ 1000 """
975 Private slot called before the Session menu is shown. 1001 Private slot called before the Session menu is shown.
976 """ 1002 """
977 enable = True 1003 enable = True
978 if self.pfile is None: 1004 if self.pfile is None:
979 enable = False 1005 enable = False
980 else: 1006 else:
981 fn, ext = os.path.splitext(os.path.basename(self.pfile)) 1007 fn, ext = os.path.splitext(os.path.basename(self.pfile))
982 fn_new = os.path.join(self.getProjectManagementDir(), 1008 fn_new = os.path.join(self.getProjectManagementDir(),
1009 '{0}.esj'.format(fn))
1010 fn_old = os.path.join(self.getProjectManagementDir(),
983 '{0}.e5s'.format(fn)) 1011 '{0}.e5s'.format(fn))
984 fn_old = os.path.join(self.getProjectManagementDir(),
985 '{0}.e4s'.format(fn))
986 enable = os.path.exists(fn_new) or os.path.exists(fn_old) 1012 enable = os.path.exists(fn_new) or os.path.exists(fn_old)
987 self.sessActGrp.findChild( 1013 self.sessActGrp.findChild(
988 QAction, "project_load_session").setEnabled(enable) 1014 QAction, "project_load_session").setEnabled(enable)
989 self.sessActGrp.findChild( 1015 self.sessActGrp.findChild(
990 QAction, "project_delete_session").setEnabled(enable) 1016 QAction, "project_delete_session").setEnabled(enable)
991 1017
992 @pyqtSlot() 1018 @pyqtSlot()
993 def __readSession(self, quiet=False, indicator=""): 1019 def __readSession(self, quiet=False, indicator=""):
994 """ 1020 """
995 Private method to read in the project session file (.e5s or .e4s). 1021 Private method to read in the project session file (.esj or .e5s).
996 1022
997 @param quiet flag indicating quiet operations. 1023 @param quiet flag indicating quiet operations.
998 If this flag is true, no errors are reported. 1024 If this flag is true, no errors are reported.
999 @param indicator indicator string (string) 1025 @param indicator indicator string (string)
1000 """ 1026 """
1001 if self.pfile is None: 1027 if self.pfile is None:
1002 if not quiet: 1028 if not quiet:
1003 E5MessageBox.critical( 1029 E5MessageBox.critical(
1004 self.ui, 1030 self.ui,
1005 self.tr("Read project session"), 1031 self.tr("Read Project Session"),
1006 self.tr("Please save the project first.")) 1032 self.tr("Please save the project first."))
1007 return 1033 return
1008 1034
1009 fn1, ext = os.path.splitext(os.path.basename(self.pfile)) 1035 fn1, ext = os.path.splitext(os.path.basename(self.pfile))
1010 fn = os.path.join(self.getProjectManagementDir(), 1036 fn = os.path.join(self.getProjectManagementDir(),
1011 '{0}{1}.e5s'.format(fn1, indicator)) 1037 '{0}{1}.esj'.format(fn1, indicator))
1012 if not os.path.exists(fn): 1038 if os.path.exists(fn):
1039 # try the new JSON based format first
1040 self.__sessionFile.readFile(fn)
1041 else:
1042 # try the old XML based format second
1013 fn = os.path.join(self.getProjectManagementDir(), 1043 fn = os.path.join(self.getProjectManagementDir(),
1014 '{0}{1}.e4s'.format(fn1, indicator)) 1044 '{0}{1}.e5s'.format(fn1, indicator))
1015 1045 if os.path.exists(fn):
1016 f = QFile(fn) 1046 f = QFile(fn)
1017 if f.open(QIODevice.ReadOnly): 1047 if f.open(QIODevice.ReadOnly):
1018 from E5XML.SessionReader import SessionReader 1048 from E5XML.SessionReader import SessionReader
1019 reader = SessionReader(f, False) 1049 reader = SessionReader(f, False)
1020 reader.readXML(quiet=quiet) 1050 reader.readXML(quiet=quiet)
1021 f.close() 1051 f.close()
1022 else: 1052 else:
1023 if not quiet: 1053 if not quiet:
1024 E5MessageBox.critical( 1054 E5MessageBox.critical(
1025 self.ui, 1055 self.ui,
1026 self.tr("Read project session"), 1056 self.tr("Read project session"),
1027 self.tr( 1057 self.tr(
1028 "<p>The project session file <b>{0}</b> could not be" 1058 "<p>The project session file <b>{0}</b> could"
1029 " read.</p>").format(fn)) 1059 " not be read.</p>").format(fn))
1030 1060
1031 @pyqtSlot() 1061 @pyqtSlot()
1032 def __writeSession(self, quiet=False, indicator=""): 1062 def __writeSession(self, quiet=False, indicator=""):
1033 """ 1063 """
1034 Private method to write the session data to an XML file (.e5s). 1064 Private method to write the session data to an XML file (.esj).
1035 1065
1036 @param quiet flag indicating quiet operations. 1066 @param quiet flag indicating quiet operations.
1037 If this flag is true, no errors are reported. 1067 If this flag is true, no errors are reported.
1038 @param indicator indicator string (string) 1068 @param indicator indicator string (string)
1039 """ 1069 """
1040 if self.pfile is None: 1070 if self.pfile is None:
1041 if not quiet: 1071 if not quiet:
1042 E5MessageBox.critical( 1072 E5MessageBox.critical(
1043 self.ui, 1073 self.ui,
1044 self.tr("Save project session"), 1074 self.tr("Save Project Session"),
1045 self.tr("Please save the project first.")) 1075 self.tr("Please save the project first."))
1046 return 1076 return
1047 1077
1048 fn, ext = os.path.splitext(os.path.basename(self.pfile)) 1078 fn, ext = os.path.splitext(os.path.basename(self.pfile))
1049 fn = os.path.join(self.getProjectManagementDir(), 1079 fn = os.path.join(self.getProjectManagementDir(),
1050 '{0}{1}.e5s'.format(fn, indicator)) 1080 '{0}{1}.esj'.format(fn, indicator))
1051 1081
1052 f = QFile(fn) 1082 self.__sessionFile.writeFile(fn)
1053 if f.open(QIODevice.WriteOnly): 1083
1054 from E5XML.SessionWriter import SessionWriter
1055 SessionWriter(
1056 f, os.path.splitext(os.path.basename(fn))[0]).writeXML()
1057 f.close()
1058 else:
1059 if not quiet:
1060 E5MessageBox.critical(
1061 self.ui,
1062 self.tr("Save project session"),
1063 self.tr(
1064 "<p>The project session file <b>{0}</b> could not be"
1065 " written.</p>").format(fn))
1066
1067 def __deleteSession(self): 1084 def __deleteSession(self):
1068 """ 1085 """
1069 Private method to delete the session file. 1086 Private method to delete the session file.
1070 """ 1087 """
1071 if self.pfile is None: 1088 if self.pfile is None:
1072 E5MessageBox.critical( 1089 E5MessageBox.critical(
1073 self.ui, 1090 self.ui,
1074 self.tr("Delete project session"), 1091 self.tr("Delete Project Session"),
1075 self.tr("Please save the project first.")) 1092 self.tr("Please save the project first."))
1076 return 1093 return
1077 1094
1078 fname, ext = os.path.splitext(os.path.basename(self.pfile)) 1095 fname, ext = os.path.splitext(os.path.basename(self.pfile))
1079 1096
1080 for fn in [ 1097 for ext in (".esj", ".e5s", ".e4s"):
1081 os.path.join( 1098 fn = os.path.join(
1082 self.getProjectManagementDir(), "{0}.e5s".format(fname)), 1099 self.getProjectManagementDir(), "{0}{1}".format(fname, ext)),
1083 os.path.join(
1084 self.getProjectManagementDir(), "{0}.e4s".format(fname))]:
1085 if os.path.exists(fn): 1100 if os.path.exists(fn):
1086 try: 1101 try:
1087 os.remove(fn) 1102 os.remove(fn)
1088 except OSError: 1103 except OSError:
1089 E5MessageBox.critical( 1104 E5MessageBox.critical(
1090 self.ui, 1105 self.ui,
1091 self.tr("Delete project session"), 1106 self.tr("Delete Project Session"),
1092 self.tr( 1107 self.tr(
1093 "<p>The project session file <b>{0}</b> could" 1108 "<p>The project session file <b>{0}</b> could"
1094 " not be deleted.</p>").format(fn)) 1109 " not be deleted.</p>").format(fn))
1095 1110
1096 def __readTasks(self): 1111 def __readTasks(self):
1097 """ 1112 """
1098 Private method to read in the project tasks file (.e6t). 1113 Private method to read in the project tasks file (.etj or .e6t).
1099 """ 1114 """
1100 if self.pfile is None: 1115 if self.pfile is None:
1101 E5MessageBox.critical( 1116 E5MessageBox.critical(
1102 self.ui, 1117 self.ui,
1103 self.tr("Read tasks"), 1118 self.tr("Read Tasks"),
1104 self.tr("Please save the project first.")) 1119 self.tr("Please save the project first."))
1105 return 1120 return
1106 1121
1107 base, ext = os.path.splitext(os.path.basename(self.pfile)) 1122 base, ext = os.path.splitext(os.path.basename(self.pfile))
1108 fn = os.path.join(self.getProjectManagementDir(), 1123 fn = os.path.join(self.getProjectManagementDir(),
1109 '{0}.e6t'.format(base)) 1124 '{0}.etj'.format(base))
1110 if not os.path.exists(fn): 1125 if os.path.exists(fn):
1111 # try again with the old extension 1126 # try new style JSON file first
1127 self.__tasksFile.readFile(fn)
1128 else:
1129 # try old style XML file second
1112 fn = os.path.join(self.getProjectManagementDir(), 1130 fn = os.path.join(self.getProjectManagementDir(),
1113 '{0}.e4t'.format(base)) 1131 '{0}.e6t'.format(base))
1114 if not os.path.exists(fn): 1132 if os.path.exists(fn):
1115 return 1133 f = QFile(fn)
1116 f = QFile(fn) 1134 if f.open(QIODevice.ReadOnly):
1117 if f.open(QIODevice.ReadOnly): 1135 from E5XML.TasksReader import TasksReader
1118 from E5XML.TasksReader import TasksReader 1136 reader = TasksReader(f, True)
1119 reader = TasksReader(f, True) 1137 reader.readXML()
1120 reader.readXML() 1138 f.close()
1121 f.close() 1139 else:
1122 else: 1140 E5MessageBox.critical(
1123 E5MessageBox.critical( 1141 self.ui,
1124 self.ui, 1142 self.tr("Read Tasks"),
1125 self.tr("Read tasks"), 1143 self.tr(
1126 self.tr( 1144 "<p>The tasks file <b>{0}</b> could not be read."
1127 "<p>The tasks file <b>{0}</b> could not be read.</p>") 1145 "</p>")
1128 .format(fn)) 1146 .format(fn))
1129 1147
1130 def writeTasks(self): 1148 def writeTasks(self):
1131 """ 1149 """
1132 Public method to write the tasks data to an XML file (.e6t). 1150 Public method to write the tasks data to a JSON file (.etj).
1133 """ 1151 """
1134 if self.pfile is None: 1152 if self.pfile is None:
1135 return 1153 return
1136 1154
1137 fn, ext = os.path.splitext(os.path.basename(self.pfile)) 1155 fn, ext = os.path.splitext(os.path.basename(self.pfile))
1138 1156
1139 fn = os.path.join(self.getProjectManagementDir(), '{0}.e6t'.format(fn)) 1157 fn = os.path.join(self.getProjectManagementDir(),
1140 f = QFile(fn) 1158 '{0}.etj'.format(fn))
1141 ok = f.open(QIODevice.WriteOnly) 1159 self.__tasksFile.writeFile(fn)
1142 if not ok: 1160
1143 E5MessageBox.critical(
1144 self.ui,
1145 self.tr("Save tasks"),
1146 self.tr(
1147 "<p>The tasks file <b>{0}</b> could not be written.</p>")
1148 .format(fn))
1149 return
1150
1151 from E5XML.TasksWriter import TasksWriter
1152 TasksWriter(
1153 f, True, os.path.splitext(os.path.basename(fn))[0]).writeXML()
1154 f.close()
1155
1156 def __showContextMenuDebugger(self): 1161 def __showContextMenuDebugger(self):
1157 """ 1162 """
1158 Private slot called before the Debugger menu is shown. 1163 Private slot called before the Debugger menu is shown.
1159 """ 1164 """
1160 enable = True 1165 enable = True
1161 if self.pfile is None: 1166 if self.pfile is None:
1162 enable = False 1167 enable = False
1163 else: 1168 else:
1164 fn, ext = os.path.splitext(os.path.basename(self.pfile)) 1169 fn, ext = os.path.splitext(os.path.basename(self.pfile))
1170 # try new style file first
1165 fn = os.path.join(self.getProjectManagementDir(), 1171 fn = os.path.join(self.getProjectManagementDir(),
1166 '{0}.e4d'.format(fn)) 1172 '{0}.edj'.format(fn))
1173 if not os.path.exists(fn):
1174 # try old style file second
1175 fn = os.path.join(self.getProjectManagementDir(),
1176 '{0}.e4d'.format(fn))
1167 enable = os.path.exists(fn) 1177 enable = os.path.exists(fn)
1168 self.dbgActGrp.findChild( 1178 self.dbgActGrp.findChild(
1169 QAction, "project_debugger_properties_load").setEnabled(enable) 1179 QAction, "project_debugger_properties_load").setEnabled(enable)
1170 self.dbgActGrp.findChild( 1180 self.dbgActGrp.findChild(
1171 QAction, "project_debugger_properties_delete").setEnabled(enable) 1181 QAction, "project_debugger_properties_delete").setEnabled(enable)
1172 1182
1173 @pyqtSlot() 1183 @pyqtSlot()
1174 def __readDebugProperties(self, quiet=False): 1184 def __readDebugProperties(self, quiet=False):
1175 """ 1185 """
1176 Private method to read in the project debugger properties file (.e4d). 1186 Private method to read in the project debugger properties file
1187 (.edj or .e4d).
1177 1188
1178 @param quiet flag indicating quiet operations. 1189 @param quiet flag indicating quiet operations.
1179 If this flag is true, no errors are reported. 1190 If this flag is true, no errors are reported.
1180 """ 1191 """
1181 if self.pfile is None: 1192 if self.pfile is None:
1182 if not quiet: 1193 if not quiet:
1183 E5MessageBox.critical( 1194 E5MessageBox.critical(
1184 self.ui, 1195 self.ui,
1185 self.tr("Read debugger properties"), 1196 self.tr("Read Debugger Properties"),
1186 self.tr("Please save the project first.")) 1197 self.tr("Please save the project first."))
1187 return 1198 return
1199
1200 fn1, ext = os.path.splitext(os.path.basename(self.pfile))
1201 fn = os.path.join(self.getProjectManagementDir(),
1202 '{0}.edj'.format(fn1))
1203 if os.path.exists(fn):
1204 # try the new JSON based format first
1205 self.__debuggerPropertiesFile.readFile(fn)
1206 else:
1207 # try the old XML based format second
1208 fn = os.path.join(self.getProjectManagementDir(),
1209 '{0}.e4d'.format(fn1))
1188 1210
1189 fn, ext = os.path.splitext(os.path.basename(self.pfile)) 1211 f = QFile(fn)
1190 fn = os.path.join(self.getProjectManagementDir(), '{0}.e4d'.format(fn)) 1212 if f.open(QIODevice.ReadOnly):
1191 1213 from E5XML.DebuggerPropertiesReader import (
1192 f = QFile(fn) 1214 DebuggerPropertiesReader
1193 if f.open(QIODevice.ReadOnly): 1215 )
1194 from E5XML.DebuggerPropertiesReader import DebuggerPropertiesReader 1216 reader = DebuggerPropertiesReader(f, self)
1195 reader = DebuggerPropertiesReader(f, self) 1217 reader.readXML(quiet=quiet)
1196 reader.readXML(quiet=quiet) 1218 f.close()
1197 f.close() 1219 self.debugPropertiesLoaded = True
1198 self.debugPropertiesLoaded = True 1220 self.debugPropertiesChanged = False
1199 self.debugPropertiesChanged = False 1221 else:
1200 else: 1222 if not quiet:
1201 if not quiet: 1223 E5MessageBox.critical(
1202 E5MessageBox.critical( 1224 self.ui,
1203 self.ui, 1225 self.tr("Read Debugger Properties"),
1204 self.tr("Read debugger properties"), 1226 self.tr(
1205 self.tr( 1227 "<p>The project debugger properties file"
1206 "<p>The project debugger properties file <b>{0}</b>" 1228 " <b>{0}</b> could not be read.</p>").format(fn))
1207 " could not be read.</p>").format(fn)) 1229
1208
1209 @pyqtSlot() 1230 @pyqtSlot()
1210 def __writeDebugProperties(self, quiet=False): 1231 def __writeDebugProperties(self, quiet=False):
1211 """ 1232 """
1212 Private method to write the project debugger properties file (.e4d). 1233 Private method to write the project debugger properties file (.edj).
1213 1234
1214 @param quiet flag indicating quiet operations. 1235 @param quiet flag indicating quiet operations.
1215 If this flag is true, no errors are reported. 1236 If this flag is true, no errors are reported.
1216 """ 1237 """
1217 if self.pfile is None: 1238 if self.pfile is None:
1218 if not quiet: 1239 if not quiet:
1219 E5MessageBox.critical( 1240 E5MessageBox.critical(
1220 self.ui, 1241 self.ui,
1221 self.tr("Save debugger properties"), 1242 self.tr("Save Debugger Properties"),
1222 self.tr("Please save the project first.")) 1243 self.tr("Please save the project first."))
1223 return 1244 return
1224 1245
1225 fn, ext = os.path.splitext(os.path.basename(self.pfile)) 1246 fn, ext = os.path.splitext(os.path.basename(self.pfile))
1226 fn = os.path.join(self.getProjectManagementDir(), '{0}.e4d'.format(fn)) 1247 fn = os.path.join(self.getProjectManagementDir(), '{0}.edj'.format(fn))
1227 1248
1228 f = QFile(fn) 1249 with E5OverrideCursor():
1229 if f.open(QIODevice.WriteOnly): 1250 self.__debuggerPropertiesFile.writeFile(fn)
1230 from E5XML.DebuggerPropertiesWriter import DebuggerPropertiesWriter 1251
1231 DebuggerPropertiesWriter(
1232 f, os.path.splitext(os.path.basename(fn))[0]).writeXML()
1233 f.close()
1234 self.debugPropertiesChanged = False
1235 else:
1236 if not quiet:
1237 E5MessageBox.critical(
1238 self.ui,
1239 self.tr("Save debugger properties"),
1240 self.tr(
1241 "<p>The project debugger properties file <b>{0}</b>"
1242 " could not be written.</p>").format(fn))
1243
1244 def __deleteDebugProperties(self): 1252 def __deleteDebugProperties(self):
1245 """ 1253 """
1246 Private method to delete the project debugger properties file (.e4d). 1254 Private method to delete the project debugger properties file
1255 (.edj or .e4d).
1247 """ 1256 """
1248 if self.pfile is None: 1257 if self.pfile is None:
1249 E5MessageBox.critical( 1258 E5MessageBox.critical(
1250 self.ui, 1259 self.ui,
1251 self.tr("Delete debugger properties"), 1260 self.tr("Delete Debugger Properties"),
1252 self.tr("Please save the project first.")) 1261 self.tr("Please save the project first."))
1253 return 1262 return
1254 1263
1255 fname, ext = os.path.splitext(os.path.basename(self.pfile)) 1264 fname, ext = os.path.splitext(os.path.basename(self.pfile))
1256 1265
1257 for fn in [os.path.join(self.getProjectManagementDir(), 1266 for ext in (".edj", ".e4d"):
1258 "{0}.e4d".format(fname))]: 1267 fn = os.path.join(self.getProjectManagementDir(),
1268 "{0}{1}".format(fname, ext))
1259 if os.path.exists(fn): 1269 if os.path.exists(fn):
1260 try: 1270 try:
1261 os.remove(fn) 1271 os.remove(fn)
1262 except OSError: 1272 except OSError:
1263 E5MessageBox.critical( 1273 E5MessageBox.critical(
1264 self.ui, 1274 self.ui,
1265 self.tr("Delete debugger properties"), 1275 self.tr("Delete Debugger Properties"),
1266 self.tr( 1276 self.tr(
1267 "<p>The project debugger properties file" 1277 "<p>The project debugger properties file"
1268 " <b>{0}</b> could not be deleted.</p>") 1278 " <b>{0}</b> could not be deleted.</p>")
1269 .format(fn)) 1279 .format(fn))
1270 1280
2185 if dirty: 2195 if dirty:
2186 self.setDirty(True) 2196 self.setDirty(True)
2187 2197
2188 def removeDirectory(self, dn): 2198 def removeDirectory(self, dn):
2189 """ 2199 """
2190 Public slot to remove a directory from the project. 2200 Public method to remove a directory from the project.
2191 2201
2192 The directory is not deleted from the project directory. 2202 The directory is not deleted from the project directory.
2193 2203
2194 @param dn directory name to be removed from the project 2204 @param dn directory name to be removed from the project
2195 """ 2205 """
2214 self.setDirty(True) 2224 self.setDirty(True)
2215 self.directoryRemoved.emit(dn) 2225 self.directoryRemoved.emit(dn)
2216 2226
2217 def deleteFile(self, fn): 2227 def deleteFile(self, fn):
2218 """ 2228 """
2219 Public slot to delete a file from the project directory. 2229 Public method to delete a file from the project directory.
2220 2230
2221 @param fn filename to be deleted from the project 2231 @param fn filename to be deleted from the project
2222 @return flag indicating success (boolean) 2232 @return flag indicating success (boolean)
2223 """ 2233 """
2224 try: 2234 try:
2258 self.removeFile(fn + '.h') 2268 self.removeFile(fn + '.h')
2259 return True 2269 return True
2260 2270
2261 def deleteDirectory(self, dn): 2271 def deleteDirectory(self, dn):
2262 """ 2272 """
2263 Public slot to delete a directory from the project directory. 2273 Public method to delete a directory from the project directory.
2264 2274
2265 @param dn directory name to be removed from the project 2275 @param dn directory name to be removed from the project
2266 @return flag indicating success (boolean) 2276 @return flag indicating success (boolean)
2267 """ 2277 """
2268 if not os.path.isabs(dn): 2278 if not os.path.isabs(dn):
2394 if not os.path.isabs(self.pdata["MAINSCRIPT"]): 2404 if not os.path.isabs(self.pdata["MAINSCRIPT"]):
2395 ms = os.path.join( 2405 ms = os.path.join(
2396 self.ppath, self.pdata["MAINSCRIPT"]) 2406 self.ppath, self.pdata["MAINSCRIPT"])
2397 else: 2407 else:
2398 ms = self.pdata["MAINSCRIPT"] 2408 ms = self.pdata["MAINSCRIPT"]
2399 os.makedirs(os.path.dirname(ms)) 2409 os.makedirs(os.path.dirname(ms), exist_ok=True)
2400 with open(ms, "w"): 2410 with open(ms, "w"):
2401 pass 2411 pass
2402 self.appendFile(ms, True) 2412 self.appendFile(ms, True)
2403 2413
2404 if self.pdata["MAKEPARAMS"]["MakeEnabled"]: 2414 if self.pdata["MAKEPARAMS"]["MakeEnabled"]:
2406 if mf: 2416 if mf:
2407 if not os.path.isabs(mf): 2417 if not os.path.isabs(mf):
2408 mf = os.path.join(self.ppath, mf) 2418 mf = os.path.join(self.ppath, mf)
2409 else: 2419 else:
2410 mf = os.path.join(self.ppath, Project.DefaultMakefile) 2420 mf = os.path.join(self.ppath, Project.DefaultMakefile)
2411 os.makedirs(os.path.dirname(mf)) 2421 os.makedirs(os.path.dirname(mf), exist_ok=True)
2412 with open(mf, "w"): 2422 with open(mf, "w"):
2413 pass 2423 pass
2414 self.appendFile(mf) 2424 self.appendFile(mf)
2415 2425
2416 tpd = os.path.join(self.ppath, self.translationsRoot) 2426 tpd = os.path.join(self.ppath, self.translationsRoot)
2417 if not self.translationsRoot.endswith(os.sep): 2427 if not self.translationsRoot.endswith(os.sep):
2418 tpd = os.path.dirname(tpd) 2428 tpd = os.path.dirname(tpd)
2419 if not os.path.isdir(tpd): 2429 if not os.path.isdir(tpd):
2420 os.makedirs(tpd) 2430 os.makedirs(tpd, exist_ok=True)
2421 if self.pdata["TRANSLATIONSBINPATH"]: 2431 if self.pdata["TRANSLATIONSBINPATH"]:
2422 tpd = os.path.join( 2432 tpd = os.path.join(
2423 self.ppath, self.pdata["TRANSLATIONSBINPATH"]) 2433 self.ppath, self.pdata["TRANSLATIONSBINPATH"])
2424 if not os.path.isdir(tpd): 2434 if not os.path.isdir(tpd):
2425 os.makedirs(tpd) 2435 os.makedirs(tpd, exist_ok=True)
2426 2436
2427 # create management directory if not present 2437 # create management directory if not present
2428 self.createProjectManagementDir() 2438 self.createProjectManagementDir()
2429 2439
2430 self.saveProject() 2440 self.saveProject()
2938 fn = E5FileDialog.getOpenFileName( 2948 fn = E5FileDialog.getOpenFileName(
2939 self.parent(), 2949 self.parent(),
2940 self.tr("Open project"), 2950 self.tr("Open project"),
2941 Preferences.getMultiProject("Workspace") or 2951 Preferences.getMultiProject("Workspace") or
2942 Utilities.getHomeDir(), 2952 Utilities.getHomeDir(),
2943 self.tr("Project Files (*.e4p)")) 2953 self.tr("Project Files (*.epj);;XML Project Files (*.e4p)"))
2944 2954
2945 QApplication.processEvents() 2955 QApplication.processEvents()
2946 2956
2947 if fn: 2957 if fn:
2948 if self.closeProject(): 2958 if self.closeProject():
3108 3118
3109 @return flag indicating success 3119 @return flag indicating success
3110 """ 3120 """
3111 if self.isDirty(): 3121 if self.isDirty():
3112 if len(self.pfile) > 0: 3122 if len(self.pfile) > 0:
3123 if self.pfile.endswith(".e4p"):
3124 self.pfile = self.pfile.replace(".e4p", ".epj")
3125 self.__syncRecent()
3113 ok = self.__writeProject() 3126 ok = self.__writeProject()
3114 else: 3127 else:
3115 ok = self.saveProjectAs() 3128 ok = self.saveProjectAs()
3116 else: 3129 else:
3117 ok = True 3130 ok = True
3123 """ 3136 """
3124 Public slot to save the current project to a different file. 3137 Public slot to save the current project to a different file.
3125 3138
3126 @return flag indicating success (boolean) 3139 @return flag indicating success (boolean)
3127 """ 3140 """
3128 defaultFilter = self.tr("Project Files (*.e4p)") 3141 defaultFilter = self.tr("Project Files (*.epj)")
3129 if self.ppath: 3142 if self.ppath:
3130 defaultPath = self.ppath 3143 defaultPath = self.ppath
3131 else: 3144 else:
3132 defaultPath = ( 3145 defaultPath = (
3133 Preferences.getMultiProject("Workspace") or 3146 Preferences.getMultiProject("Workspace") or
3135 ) 3148 )
3136 fn, selectedFilter = E5FileDialog.getSaveFileNameAndFilter( 3149 fn, selectedFilter = E5FileDialog.getSaveFileNameAndFilter(
3137 self.parent(), 3150 self.parent(),
3138 self.tr("Save project as"), 3151 self.tr("Save project as"),
3139 defaultPath, 3152 defaultPath,
3140 self.tr("Project Files (*.e4p)"), 3153 self.tr("Project Files (*.epj);;"
3154 "XML Project Files (*.e4p)"),
3141 defaultFilter, 3155 defaultFilter,
3142 E5FileDialog.Options(E5FileDialog.DontConfirmOverwrite)) 3156 E5FileDialog.Options(E5FileDialog.DontConfirmOverwrite))
3143 3157
3144 if fn: 3158 if fn:
3145 ext = QFileInfo(fn).suffix() 3159 ext = QFileInfo(fn).suffix()
4029 self.actions.append(self.userPropsAct) 4043 self.actions.append(self.userPropsAct)
4030 4044
4031 self.filetypesAct = E5Action( 4045 self.filetypesAct = E5Action(
4032 self.tr('Filetype Associations'), 4046 self.tr('Filetype Associations'),
4033 self.tr('Filetype Associations...'), 0, 0, 4047 self.tr('Filetype Associations...'), 0, 0,
4034 self, 'project_filetype_associatios') 4048 self, 'project_filetype_associations')
4035 self.filetypesAct.setStatusTip( 4049 self.filetypesAct.setStatusTip(
4036 self.tr('Show the project filetype associations')) 4050 self.tr('Show the project file type associations'))
4037 self.filetypesAct.setWhatsThis(self.tr( 4051 self.filetypesAct.setWhatsThis(self.tr(
4038 """<b>Filetype Associations...</b>""" 4052 """<b>Filetype Associations...</b>"""
4039 """<p>This shows a dialog to edit the file type associations of""" 4053 """<p>This shows a dialog to edit the file type associations of"""
4040 """ the project. These associations determine the type""" 4054 """ the project. These associations determine the type"""
4041 """ (source, form, interface, protocol or others) with a""" 4055 """ (source, form, interface, protocol or others) with a"""
4047 self.actions.append(self.filetypesAct) 4061 self.actions.append(self.filetypesAct)
4048 4062
4049 self.lexersAct = E5Action( 4063 self.lexersAct = E5Action(
4050 self.tr('Lexer Associations'), 4064 self.tr('Lexer Associations'),
4051 self.tr('Lexer Associations...'), 0, 0, 4065 self.tr('Lexer Associations...'), 0, 0,
4052 self, 'project_lexer_associatios') 4066 self, 'project_lexer_associations')
4053 self.lexersAct.setStatusTip(self.tr( 4067 self.lexersAct.setStatusTip(self.tr(
4054 'Show the project lexer associations (overriding defaults)')) 4068 'Show the project lexer associations (overriding defaults)'))
4055 self.lexersAct.setWhatsThis(self.tr( 4069 self.lexersAct.setWhatsThis(self.tr(
4056 """<b>Lexer Associations...</b>""" 4070 """<b>Lexer Associations...</b>"""
4057 """<p>This shows a dialog to edit the lexer associations of""" 4071 """<p>This shows a dialog to edit the lexer associations of"""

eric ide

mercurial