43 from eric7.EricGui.EricOverrideCursor import EricOverrideCursor, EricOverridenCursor |
41 from eric7.EricGui.EricOverrideCursor import EricOverrideCursor, EricOverridenCursor |
44 from eric7.EricWidgets import EricFileDialog, EricMessageBox |
42 from eric7.EricWidgets import EricFileDialog, EricMessageBox |
45 from eric7.EricWidgets.EricApplication import ericApp |
43 from eric7.EricWidgets.EricApplication import ericApp |
46 from eric7.EricWidgets.EricListSelectionDialog import EricListSelectionDialog |
44 from eric7.EricWidgets.EricListSelectionDialog import EricListSelectionDialog |
47 from eric7.EricWidgets.EricProgressDialog import EricProgressDialog |
45 from eric7.EricWidgets.EricProgressDialog import EricProgressDialog |
48 from eric7.EricXML.DebuggerPropertiesReader import DebuggerPropertiesReader |
|
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 |
|
53 from eric7.Globals import recentNameProject |
46 from eric7.Globals import recentNameProject |
|
47 from eric7.RemoteServerInterface import EricServerFileDialog |
54 from eric7.Sessions.SessionFile import SessionFile |
48 from eric7.Sessions.SessionFile import SessionFile |
55 from eric7.SystemUtilities import ( |
49 from eric7.SystemUtilities import ( |
56 FileSystemUtilities, |
50 FileSystemUtilities, |
57 OSUtilities, |
51 OSUtilities, |
58 PythonUtilities, |
52 PythonUtilities, |
1104 @param index key of the list to be checked |
1101 @param index key of the list to be checked |
1105 @type str |
1102 @type str |
1106 """ |
1103 """ |
1107 removed = False |
1104 removed = False |
1108 removelist = [] |
1105 removelist = [] |
1109 for file in self.__pdata[index]: |
1106 if FileSystemUtilities.isRemoteFileName(self.ppath): |
1110 if not os.path.exists(os.path.join(self.ppath, file)): |
1107 for file in self.__pdata[index]: |
1111 removelist.append(file) |
1108 if not self.__remotefsInterface.exists( |
1112 removed = True |
1109 self.__remotefsInterface.join(self.ppath, file) |
|
1110 ): |
|
1111 removelist.append(file) |
|
1112 removed = True |
|
1113 else: |
|
1114 for file in self.__pdata[index]: |
|
1115 if not os.path.exists(os.path.join(self.ppath, file)): |
|
1116 removelist.append(file) |
|
1117 removed = True |
1113 |
1118 |
1114 if removed: |
1119 if removed: |
1115 for file in removelist: |
1120 for file in removelist: |
1116 self.__pdata[index].remove(file) |
1121 self.__pdata[index].remove(file) |
1117 self.setDirty(True) |
1122 self.setDirty(True) |
1118 |
1123 |
1119 def __readProject(self, fn): |
1124 def __readProject(self, fn): |
1120 """ |
1125 """ |
1121 Private method to read in a project (.epj or .e4p) file. |
1126 Private method to read in a project file (.epj). |
1122 |
1127 |
1123 @param fn filename of the project file to be read |
1128 @param fn filename of the project file to be read |
1124 @type str |
1129 @type str |
1125 @return flag indicating success |
1130 @return flag indicating success |
1126 @rtype bool |
1131 @rtype bool |
1127 """ |
1132 """ |
1128 if os.path.splitext(fn)[1] == ".epj": |
1133 with EricOverrideCursor(): |
1129 # new JSON based format |
1134 res = self.__projectFile.readFile(fn) |
1130 with EricOverrideCursor(): |
1135 |
1131 res = self.__projectFile.readFile(fn) |
1136 if res: |
1132 else: |
1137 if FileSystemUtilities.isRemoteFileName(fn): |
1133 # old XML based format |
1138 self.pfile = fn |
1134 f = QFile(fn) |
1139 self.ppath = self.__remotefsInterface.dirname(fn) |
1135 if f.open(QIODevice.OpenModeFlag.ReadOnly): |
1140 self.name = self.__remotefsInterface.splitext( |
1136 reader = ProjectReader(f, self) |
1141 self.__remotefsInterface.basename(fn) |
1137 reader.readXML() |
1142 )[0] |
1138 res = not reader.hasError() |
|
1139 f.close() |
|
1140 |
|
1141 # create hash value, if it doesn't have one |
|
1142 if reader.version.startswith("5.") and not self.__pdata["HASH"]: |
|
1143 hashStr = str( |
|
1144 QCryptographicHash.hash( |
|
1145 QByteArray(self.ppath.encode("utf-8")), |
|
1146 QCryptographicHash.Algorithm.Sha1, |
|
1147 ).toHex(), |
|
1148 encoding="utf-8", |
|
1149 ) |
|
1150 self.__pdata["HASH"] = hashStr |
|
1151 self.setDirty(True) |
|
1152 else: |
1143 else: |
1153 EricMessageBox.critical( |
1144 self.pfile = os.path.abspath(fn) |
1154 self.ui, |
1145 self.ppath = os.path.abspath(os.path.dirname(fn)) |
1155 self.tr("Read Project File"), |
1146 self.name = os.path.splitext(os.path.basename(fn))[0] |
1156 self.tr( |
|
1157 "<p>The project file <b>{0}</b> could not be read.</p>" |
|
1158 ).format(fn), |
|
1159 ) |
|
1160 res = False |
|
1161 |
|
1162 if res: |
|
1163 self.pfile = os.path.abspath(fn) |
|
1164 self.ppath = os.path.abspath(os.path.dirname(fn)) |
|
1165 |
1147 |
1166 # insert filename into list of recently opened projects |
1148 # insert filename into list of recently opened projects |
1167 self.__syncRecent() |
1149 self.__syncRecent() |
1168 |
1150 |
1169 if self.__pdata["TRANSLATIONPATTERN"]: |
1151 if self.__pdata["TRANSLATIONPATTERN"]: |
1170 self.translationsRoot = self.__pdata["TRANSLATIONPATTERN"].split( |
1152 self.translationsRoot = self.__pdata["TRANSLATIONPATTERN"].split( |
1171 "%language%" |
1153 "%language%" |
1172 )[0] |
1154 )[0] |
1173 elif self.__pdata["MAINSCRIPT"]: |
1155 elif self.__pdata["MAINSCRIPT"]: |
1174 self.translationsRoot = os.path.splitext(self.__pdata["MAINSCRIPT"])[0] |
1156 self.translationsRoot = os.path.splitext(self.__pdata["MAINSCRIPT"])[0] |
1175 if os.path.isdir(os.path.join(self.ppath, self.translationsRoot)): |
1157 |
1176 dn = self.translationsRoot |
1158 if FileSystemUtilities.isRemoteFileName(self.ppath): |
|
1159 if self.__remotefsInterface.isdir( |
|
1160 self.__remotefsInterface.join(self.ppath, self.translationsRoot) |
|
1161 ): |
|
1162 dn = self.translationsRoot |
|
1163 else: |
|
1164 dn = self.__remotefsInterface.dirname(self.translationsRoot) |
1177 else: |
1165 else: |
1178 dn = os.path.dirname(self.translationsRoot) |
1166 if os.path.isdir(os.path.join(self.ppath, self.translationsRoot)): |
1179 if dn not in self.subdirs: |
1167 dn = self.translationsRoot |
|
1168 else: |
|
1169 dn = os.path.dirname(self.translationsRoot) |
|
1170 if dn and dn not in self.subdirs: |
1180 self.subdirs.append(dn) |
1171 self.subdirs.append(dn) |
1181 |
|
1182 self.name = os.path.splitext(os.path.basename(fn))[0] |
|
1183 |
1172 |
1184 # check, if the files of the project still exist in the |
1173 # check, if the files of the project still exist in the |
1185 # project directory |
1174 # project directory |
1186 for fileCategory in self.getFileCategories(): |
1175 for fileCategory in self.getFileCategories(): |
1187 self.__checkFilesExist(fileCategory) |
1176 self.__checkFilesExist(fileCategory) |
1188 |
1177 |
1189 # get the names of subdirectories the files are stored in |
1178 # get the names of subdirectories the files are stored in |
1190 for fileCategory in [c for c in self.getFileCategories() if c != "OTHERS"]: |
1179 for fileCategory in [c for c in self.getFileCategories() if c != "OTHERS"]: |
1191 for fn in self.__pdata[fileCategory]: |
1180 for fn in self.__pdata[fileCategory]: |
1192 dn = os.path.dirname(fn) |
1181 dn = ( |
1193 if dn not in self.subdirs: |
1182 self.__remotefsInterface.dirname(fn) |
|
1183 if FileSystemUtilities.isRemoteFileName(fn) |
|
1184 else os.path.dirname(fn) |
|
1185 ) |
|
1186 if dn and dn not in self.subdirs: |
1194 self.subdirs.append(dn) |
1187 self.subdirs.append(dn) |
1195 |
1188 |
1196 # get the names of other subdirectories |
1189 # get the names of other subdirectories |
1197 for fn in self.__pdata["OTHERS"]: |
1190 for fn in self.__pdata["OTHERS"]: |
1198 dn = os.path.dirname(fn) |
1191 dn = ( |
1199 if dn not in self.otherssubdirs: |
1192 self.__remotefsInterface.dirname(fn) |
|
1193 if FileSystemUtilities.isRemoteFileName(fn) |
|
1194 else os.path.dirname(fn) |
|
1195 ) |
|
1196 if dn and dn not in self.otherssubdirs: |
1200 self.otherssubdirs.append(dn) |
1197 self.otherssubdirs.append(dn) |
1201 |
1198 |
1202 return res |
1199 return res |
1203 |
1200 |
1204 def __writeProject(self, fn=None): |
1201 def __writeProject(self, fn=None): |
1233 |
1230 |
1234 with EricOverrideCursor(): |
1231 with EricOverrideCursor(): |
1235 res = self.__projectFile.writeFile(fn) |
1232 res = self.__projectFile.writeFile(fn) |
1236 |
1233 |
1237 if res: |
1234 if res: |
1238 self.pfile = os.path.abspath(fn) |
1235 if FileSystemUtilities.isRemoteFileName(fn): |
1239 self.ppath = os.path.abspath(os.path.dirname(fn)) |
1236 self.pfile = fn |
1240 self.name = os.path.splitext(os.path.basename(fn))[0] |
1237 self.ppath = self.__remotefsInterface.dirname(fn) |
|
1238 self.name = self.__remotefsInterface.splitext( |
|
1239 self.__remotefsInterface.basename(fn) |
|
1240 )[0] |
|
1241 else: |
|
1242 self.pfile = os.path.abspath(fn) |
|
1243 self.ppath = os.path.abspath(os.path.dirname(fn)) |
|
1244 self.name = os.path.splitext(os.path.basename(fn))[0] |
1241 self.setDirty(False) |
1245 self.setDirty(False) |
1242 |
1246 |
1243 # insert filename into list of recently opened projects |
1247 # insert filename into list of recently opened projects |
1244 self.__syncRecent() |
1248 self.__syncRecent() |
1245 |
1249 |
1246 return res |
1250 return res |
1247 |
1251 |
1248 def __readUserProperties(self): |
1252 def __readUserProperties(self): |
1249 """ |
1253 """ |
1250 Private method to read in the user specific project file (.eqj or |
1254 Private method to read in the user specific project file (.eqj). |
1251 .e4q). |
|
1252 """ |
1255 """ |
1253 if self.pfile is None: |
1256 if self.pfile is None: |
1254 return |
1257 return |
1255 |
1258 |
1256 fn1, ext = os.path.splitext(os.path.basename(self.pfile)) |
1259 if FileSystemUtilities.isRemoteFileName(self.pfile): |
1257 fn = os.path.join(self.getProjectManagementDir(), "{0}.eqj".format(fn1)) |
1260 fn1, _ext = self.__remotefsInterface.splitext( |
1258 if os.path.exists(fn): |
1261 self.__remotefsInterface.basename(self.pfile) |
1259 # try the new JSON based format first |
1262 ) |
1260 self.__userProjectFile.readFile(fn) |
1263 fn = self.__remotefsInterface.join( |
|
1264 self.getProjectManagementDir(), f"{fn1}.eqj" |
|
1265 ) |
|
1266 if not self.__remotefsInterface.exists(fn): |
|
1267 return |
1261 else: |
1268 else: |
1262 # try the old XML based format second |
1269 fn1, _ext = os.path.splitext(os.path.basename(self.pfile)) |
1263 fn = os.path.join(self.getProjectManagementDir(), "{0}.e4q".format(fn1)) |
1270 fn = os.path.join(self.getProjectManagementDir(), f"{fn1}.eqj") |
1264 if os.path.exists(fn): |
1271 if not os.path.exists(fn): |
1265 f = QFile(fn) |
1272 return |
1266 if f.open(QIODevice.OpenModeFlag.ReadOnly): |
1273 |
1267 reader = UserProjectReader(f, self) |
1274 self.__userProjectFile.readFile(fn) |
1268 reader.readXML() |
|
1269 f.close() |
|
1270 else: |
|
1271 EricMessageBox.critical( |
|
1272 self.ui, |
|
1273 self.tr("Read User Project Properties"), |
|
1274 self.tr( |
|
1275 "<p>The user specific project properties file" |
|
1276 " <b>{0}</b> could not be read.</p>" |
|
1277 ).format(fn), |
|
1278 ) |
|
1279 |
1275 |
1280 def __writeUserProperties(self): |
1276 def __writeUserProperties(self): |
1281 """ |
1277 """ |
1282 Private method to write the user specific project data to a JSON file. |
1278 Private method to write the user specific project data to a JSON file. |
1283 """ |
1279 """ |
1284 if self.pfile is None: |
1280 if self.pfile is None: |
1285 return |
1281 return |
1286 |
1282 |
1287 fn, ext = os.path.splitext(os.path.basename(self.pfile)) |
1283 if FileSystemUtilities.isRemoteFileName(self.pfile): |
1288 fn = os.path.join(self.getProjectManagementDir(), "{0}.eqj".format(fn)) |
1284 fn1, _ext = self.__remotefsInterface.splitext( |
|
1285 self.__remotefsInterface.basename(self.pfile) |
|
1286 ) |
|
1287 fn = self.__remotefsInterface.join( |
|
1288 self.getProjectManagementDir(), f"{fn1}.eqj" |
|
1289 ) |
|
1290 else: |
|
1291 fn1, _ext = os.path.splitext(os.path.basename(self.pfile)) |
|
1292 fn = os.path.join(self.getProjectManagementDir(), f"{fn1}.eqj") |
1289 |
1293 |
1290 with EricOverrideCursor(): |
1294 with EricOverrideCursor(): |
1291 self.__userProjectFile.writeFile(fn) |
1295 self.__userProjectFile.writeFile(fn) |
1292 |
1296 |
1293 def __showContextMenuSession(self): |
1297 def __showContextMenuSession(self): |
1296 """ |
1300 """ |
1297 enable = True |
1301 enable = True |
1298 if self.pfile is None: |
1302 if self.pfile is None: |
1299 enable = False |
1303 enable = False |
1300 else: |
1304 else: |
1301 fn, ext = os.path.splitext(os.path.basename(self.pfile)) |
1305 if FileSystemUtilities.isRemoteFileName(self.pfile): |
1302 fn_new = os.path.join(self.getProjectManagementDir(), "{0}.esj".format(fn)) |
1306 fn, _ext = self.__remotefsInterface.splitext( |
1303 fn_old = os.path.join(self.getProjectManagementDir(), "{0}.e5s".format(fn)) |
1307 self.__remotefsInterface.basename(self.pfile) |
1304 enable = os.path.exists(fn_new) or os.path.exists(fn_old) |
1308 ) |
|
1309 fn_sess = self.__remotefsInterface.join( |
|
1310 self.getProjectManagementDir(), f"{fn}.esj" |
|
1311 ) |
|
1312 enable = self.__remotefsInterface.exists(fn) |
|
1313 else: |
|
1314 fn, _ext = os.path.splitext(os.path.basename(self.pfile)) |
|
1315 fn_sess = os.path.join(self.getProjectManagementDir(), f"{fn}.esj") |
|
1316 enable = os.path.exists(fn_sess) |
1305 self.sessActGrp.findChild(QAction, "project_load_session").setEnabled(enable) |
1317 self.sessActGrp.findChild(QAction, "project_load_session").setEnabled(enable) |
1306 self.sessActGrp.findChild(QAction, "project_delete_session").setEnabled(enable) |
1318 self.sessActGrp.findChild(QAction, "project_delete_session").setEnabled(enable) |
1307 |
1319 |
1308 @pyqtSlot() |
1320 @pyqtSlot() |
1309 def __readSession(self, quiet=False, indicator=""): |
1321 def __readSession(self, quiet=False, indicator=""): |
1310 """ |
1322 """ |
1311 Private method to read in the project session file (.esj or .e5s). |
1323 Private method to read in the project session file (.esj). |
1312 |
1324 |
1313 @param quiet flag indicating quiet operations. |
1325 @param quiet flag indicating quiet operations. |
1314 If this flag is true, no errors are reported. |
1326 If this flag is true, no errors are reported. |
1315 @type bool |
1327 @type bool |
1316 @param indicator indicator string |
1328 @param indicator indicator string |
1323 self.tr("Read Project Session"), |
1335 self.tr("Read Project Session"), |
1324 self.tr("Please save the project first."), |
1336 self.tr("Please save the project first."), |
1325 ) |
1337 ) |
1326 return |
1338 return |
1327 |
1339 |
1328 fn1, ext = os.path.splitext(os.path.basename(self.pfile)) |
1340 if FileSystemUtilities.isRemoteFileName(self.pfile): |
1329 fn = os.path.join( |
1341 fn1, _ext = self.__remotefsInterface.splitext( |
1330 self.getProjectManagementDir(), "{0}{1}.esj".format(fn1, indicator) |
1342 self.__remotefsInterface.basename(self.pfile) |
1331 ) |
1343 ) |
1332 if os.path.exists(fn): |
1344 fn = self.__remotefsInterface.join( |
1333 # try the new JSON based format first |
1345 self.getProjectManagementDir(), f"{fn1}{indicator}.esj" |
1334 self.__sessionFile.readFile(fn) |
1346 ) |
|
1347 if not self.__remotefsInterface.exists(fn): |
|
1348 return |
1335 else: |
1349 else: |
1336 # try the old XML based format second |
1350 fn1, _ext = os.path.splitext(os.path.basename(self.pfile)) |
1337 fn = os.path.join( |
1351 fn = os.path.join( |
1338 self.getProjectManagementDir(), "{0}{1}.e5s".format(fn1, indicator) |
1352 self.getProjectManagementDir(), f"{fn1}{indicator}.esj" |
1339 ) |
1353 ) |
1340 if os.path.exists(fn): |
1354 if not os.path.exists(fn): |
1341 f = QFile(fn) |
1355 return |
1342 if f.open(QIODevice.OpenModeFlag.ReadOnly): |
1356 |
1343 reader = SessionReader(f, False) |
1357 self.__sessionFile.readFile(fn) |
1344 reader.readXML(quiet=quiet) |
|
1345 f.close() |
|
1346 else: |
|
1347 if not quiet: |
|
1348 EricMessageBox.critical( |
|
1349 self.ui, |
|
1350 self.tr("Read project session"), |
|
1351 self.tr( |
|
1352 "<p>The project session file <b>{0}</b> could" |
|
1353 " not be read.</p>" |
|
1354 ).format(fn), |
|
1355 ) |
|
1356 |
1358 |
1357 @pyqtSlot() |
1359 @pyqtSlot() |
1358 def __writeSession(self, quiet=False, indicator=""): |
1360 def __writeSession(self, quiet=False, indicator=""): |
1359 """ |
1361 """ |
1360 Private method to write the session data to an XML file (.esj). |
1362 Private method to write the session data to an XML file (.esj). |
1391 self.tr("Delete Project Session"), |
1401 self.tr("Delete Project Session"), |
1392 self.tr("Please save the project first."), |
1402 self.tr("Please save the project first."), |
1393 ) |
1403 ) |
1394 return |
1404 return |
1395 |
1405 |
1396 fname, ext = os.path.splitext(os.path.basename(self.pfile)) |
1406 try: |
1397 |
1407 if FileSystemUtilities.isRemoteFileName(self.pfile): |
1398 for ext in (".esj", ".e5s", ".e4s"): |
1408 title = self.tr("Delete Remote Project Session") |
1399 fn = os.path.join( |
1409 fname, _ext = self.__remotefsInterface.splitext( |
1400 self.getProjectManagementDir(), "{0}{1}".format(fname, ext) |
1410 self.__remotefsInterface.basename(self.pfile) |
1401 ) |
1411 ) |
1402 if os.path.exists(fn): |
1412 fn = self.__remotefsInterface.join( |
1403 try: |
1413 self.getProjectManagementDir(), f"{fname}.esj" |
|
1414 ) |
|
1415 if self.__remotefsInterface.exists(fn): |
|
1416 self.__remotefsInterface.remove(fn) |
|
1417 else: |
|
1418 title = self.tr("Delete Project Session") |
|
1419 fname, _ext = os.path.splitext(os.path.basename(self.pfile)) |
|
1420 fn = os.path.join(self.getProjectManagementDir(), f"{fname}.esj") |
|
1421 if os.path.exists(fn): |
1404 os.remove(fn) |
1422 os.remove(fn) |
1405 except OSError: |
1423 except OSError: |
1406 EricMessageBox.critical( |
1424 EricMessageBox.critical( |
1407 self.ui, |
1425 self.ui, |
1408 self.tr("Delete Project Session"), |
1426 title, |
1409 self.tr( |
1427 self.tr( |
1410 "<p>The project session file <b>{0}</b> could" |
1428 "<p>The project session file <b>{0}</b> could" |
1411 " not be deleted.</p>" |
1429 " not be deleted.</p>" |
1412 ).format(fn), |
1430 ).format(fn), |
1413 ) |
1431 ) |
1414 |
1432 |
1415 def __readTasks(self): |
1433 def __readTasks(self): |
1416 """ |
1434 """ |
1417 Private method to read in the project tasks file (.etj or .e6t). |
1435 Private method to read in the project tasks file (.etj). |
1418 """ |
1436 """ |
1419 if self.pfile is None: |
1437 if self.pfile is None: |
1420 EricMessageBox.critical( |
1438 EricMessageBox.critical( |
1421 self.ui, |
1439 self.ui, |
1422 self.tr("Read Tasks"), |
1440 self.tr("Read Tasks"), |
1423 self.tr("Please save the project first."), |
1441 self.tr("Please save the project first."), |
1424 ) |
1442 ) |
1425 return |
1443 return |
1426 |
1444 |
1427 base, ext = os.path.splitext(os.path.basename(self.pfile)) |
1445 if FileSystemUtilities.isRemoteFileName(self.pfile): |
1428 fn = os.path.join(self.getProjectManagementDir(), "{0}.etj".format(base)) |
1446 base, _ext = self.__remotefsInterface.splitext( |
1429 if os.path.exists(fn): |
1447 self.__remotefsInterface.basename(self.pfile) |
1430 # try new style JSON file first |
1448 ) |
1431 self.__tasksFile.readFile(fn) |
1449 fn = self.__remotefsInterface.join( |
|
1450 self.getProjectManagementDir(), f"{base}.etj" |
|
1451 ) |
|
1452 if not self.__remotefsInterface.exists(fn): |
|
1453 return |
1432 else: |
1454 else: |
1433 # try old style XML file second |
1455 base, ext = os.path.splitext(os.path.basename(self.pfile)) |
1434 fn = os.path.join(self.getProjectManagementDir(), "{0}.e6t".format(base)) |
1456 fn = os.path.join(self.getProjectManagementDir(), f"{base}.etj") |
1435 if os.path.exists(fn): |
1457 if not os.path.exists(fn): |
1436 f = QFile(fn) |
1458 return |
1437 if f.open(QIODevice.OpenModeFlag.ReadOnly): |
1459 |
1438 reader = TasksReader(f, True) |
1460 self.__tasksFile.readFile(fn) |
1439 reader.readXML() |
|
1440 f.close() |
|
1441 else: |
|
1442 EricMessageBox.critical( |
|
1443 self.ui, |
|
1444 self.tr("Read Tasks"), |
|
1445 self.tr( |
|
1446 "<p>The tasks file <b>{0}</b> could not be read.</p>" |
|
1447 ).format(fn), |
|
1448 ) |
|
1449 |
1461 |
1450 def writeTasks(self): |
1462 def writeTasks(self): |
1451 """ |
1463 """ |
1452 Public method to write the tasks data to a JSON file (.etj). |
1464 Public method to write the tasks data to a JSON file (.etj). |
1453 """ |
1465 """ |
1454 if self.pfile is None: |
1466 if self.pfile is None: |
1455 return |
1467 return |
1456 |
1468 |
1457 fn, ext = os.path.splitext(os.path.basename(self.pfile)) |
1469 if FileSystemUtilities.isRemoteFileName(self.pfile): |
1458 |
1470 base, _ext = self.__remotefsInterface.splitext( |
1459 fn = os.path.join(self.getProjectManagementDir(), "{0}.etj".format(fn)) |
1471 self.__remotefsInterface.basename(self.pfile) |
|
1472 ) |
|
1473 fn = self.__remotefsInterface.join( |
|
1474 self.getProjectManagementDir(), f"{base}.etj" |
|
1475 ) |
|
1476 else: |
|
1477 base, ext = os.path.splitext(os.path.basename(self.pfile)) |
|
1478 fn = os.path.join(self.getProjectManagementDir(), f"{base}.etj") |
|
1479 |
1460 self.__tasksFile.writeFile(fn) |
1480 self.__tasksFile.writeFile(fn) |
1461 |
1481 |
1462 def __showContextMenuDebugger(self): |
1482 def __showContextMenuDebugger(self): |
1463 """ |
1483 """ |
1464 Private slot called before the Debugger menu is shown. |
1484 Private slot called before the Debugger menu is shown. |
1465 """ |
1485 """ |
1466 enable = True |
1486 enable = True |
1467 if self.pfile is None: |
1487 if self.pfile is None: |
1468 enable = False |
1488 enable = False |
1469 else: |
1489 else: |
1470 fn, ext = os.path.splitext(os.path.basename(self.pfile)) |
1490 if FileSystemUtilities.isRemoteFileName(self.pfile): |
1471 # try new style file first |
1491 fn1, _ext = self.__remotefsInterface.splitext( |
1472 fn = os.path.join(self.getProjectManagementDir(), "{0}.edj".format(fn)) |
1492 self.__remotefsInterface.basename(self.pfile) |
1473 if not os.path.exists(fn): |
1493 ) |
1474 # try old style file second |
1494 fn = self.__remotefsInterface.join( |
1475 fn = os.path.join(self.getProjectManagementDir(), "{0}.e4d".format(fn)) |
1495 self.getProjectManagementDir(), f"{fn1}.edj" |
1476 enable = os.path.exists(fn) |
1496 ) |
|
1497 enable = self.__remotefsInterface.exists(fn) |
|
1498 else: |
|
1499 fn1, _ext = os.path.splitext(os.path.basename(self.pfile)) |
|
1500 fn = os.path.join(self.getProjectManagementDir(), f"{fn1}.edj") |
|
1501 enable = os.path.exists(fn) |
1477 self.dbgActGrp.findChild( |
1502 self.dbgActGrp.findChild( |
1478 QAction, "project_debugger_properties_load" |
1503 QAction, "project_debugger_properties_load" |
1479 ).setEnabled(enable) |
1504 ).setEnabled(enable) |
1480 self.dbgActGrp.findChild( |
1505 self.dbgActGrp.findChild( |
1481 QAction, "project_debugger_properties_delete" |
1506 QAction, "project_debugger_properties_delete" |
1498 self.tr("Read Debugger Properties"), |
1523 self.tr("Read Debugger Properties"), |
1499 self.tr("Please save the project first."), |
1524 self.tr("Please save the project first."), |
1500 ) |
1525 ) |
1501 return |
1526 return |
1502 |
1527 |
1503 fn1, ext = os.path.splitext(os.path.basename(self.pfile)) |
1528 if FileSystemUtilities.isRemoteFileName(self.pfile): |
1504 fn = os.path.join(self.getProjectManagementDir(), "{0}.edj".format(fn1)) |
1529 fn1, _ext = self.__remotefsInterface.splitext( |
1505 if os.path.exists(fn): |
1530 self.__remotefsInterface.basename(self.pfile) |
1506 # try the new JSON based format first |
1531 ) |
1507 if self.__debuggerPropertiesFile.readFile(fn): |
1532 fn = self.__remotefsInterface.join( |
1508 self.debugPropertiesLoaded = True |
1533 self.getProjectManagementDir(), f"{fn1}.edj" |
1509 self.debugPropertiesChanged = False |
1534 ) |
|
1535 if not self.__remotefsInterface.exists(fn): |
|
1536 return |
1510 else: |
1537 else: |
1511 # try the old XML based format second |
1538 fn1, _ext = os.path.splitext(os.path.basename(self.pfile)) |
1512 fn = os.path.join(self.getProjectManagementDir(), "{0}.e4d".format(fn1)) |
1539 fn = os.path.join(self.getProjectManagementDir(), f"{fn1}.edj") |
1513 |
1540 if not os.path.exists(fn): |
1514 f = QFile(fn) |
1541 return |
1515 if f.open(QIODevice.OpenModeFlag.ReadOnly): |
1542 |
1516 reader = DebuggerPropertiesReader(f, self) |
1543 if self.__debuggerPropertiesFile.readFile(fn): |
1517 reader.readXML(quiet=quiet) |
1544 self.debugPropertiesLoaded = True |
1518 f.close() |
1545 self.debugPropertiesChanged = False |
1519 self.debugPropertiesLoaded = True |
|
1520 self.debugPropertiesChanged = False |
|
1521 else: |
|
1522 if not quiet: |
|
1523 EricMessageBox.critical( |
|
1524 self.ui, |
|
1525 self.tr("Read Debugger Properties"), |
|
1526 self.tr( |
|
1527 "<p>The project debugger properties file" |
|
1528 " <b>{0}</b> could not be read.</p>" |
|
1529 ).format(fn), |
|
1530 ) |
|
1531 |
1546 |
1532 @pyqtSlot() |
1547 @pyqtSlot() |
1533 def __writeDebugProperties(self, quiet=False): |
1548 def __writeDebugProperties(self, quiet=False): |
1534 """ |
1549 """ |
1535 Private method to write the project debugger properties file (.edj). |
1550 Private method to write the project debugger properties file (.edj). |
1564 self.tr("Delete Debugger Properties"), |
1587 self.tr("Delete Debugger Properties"), |
1565 self.tr("Please save the project first."), |
1588 self.tr("Please save the project first."), |
1566 ) |
1589 ) |
1567 return |
1590 return |
1568 |
1591 |
1569 fname, ext = os.path.splitext(os.path.basename(self.pfile)) |
1592 try: |
1570 |
1593 if FileSystemUtilities.isRemoteFileName(self.pfile): |
1571 for ext in (".edj", ".e4d"): |
1594 title = self.tr("Delete Remote Debugger Properties") |
1572 fn = os.path.join( |
1595 fname, _ext = self.__remotefsInterface.splitext( |
1573 self.getProjectManagementDir(), "{0}{1}".format(fname, ext) |
1596 self.__remotefsInterface.basename(self.pfile) |
1574 ) |
1597 ) |
1575 if os.path.exists(fn): |
1598 fn = self.__remotefsInterface.join( |
1576 try: |
1599 self.getProjectManagementDir(), f"{fname}.edj" |
|
1600 ) |
|
1601 if self.__remotefsInterface.exists(fn): |
|
1602 self.__remotefsInterface.remove(fn) |
|
1603 else: |
|
1604 title = self.tr("Delete Debugger Properties") |
|
1605 fname, _ext = os.path.splitext(os.path.basename(self.pfile)) |
|
1606 fn = os.path.join(self.getProjectManagementDir(), f"{fname}.edj") |
|
1607 if os.path.exists(fn): |
1577 os.remove(fn) |
1608 os.remove(fn) |
1578 except OSError: |
1609 except OSError: |
1579 EricMessageBox.critical( |
1610 EricMessageBox.critical( |
1580 self.ui, |
1611 self.ui, |
1581 self.tr("Delete Debugger Properties"), |
1612 title, |
1582 self.tr( |
1613 self.tr( |
1583 "<p>The project debugger properties file" |
1614 "<p>The project debugger properties file" |
1584 " <b>{0}</b> could not be deleted.</p>" |
1615 " <b>{0}</b> could not be deleted.</p>" |
1585 ).format(fn), |
1616 ).format(fn), |
1586 ) |
1617 ) |
1587 |
1618 |
1588 def __initDebugProperties(self): |
1619 def __initDebugProperties(self): |
1589 """ |
1620 """ |
1590 Private method to initialize the debug properties. |
1621 Private method to initialize the debug properties. |
1591 """ |
1622 """ |
1802 """ |
1833 """ |
1803 tbPath = self.__pdata["TRANSLATIONSBINPATH"] |
1834 tbPath = self.__pdata["TRANSLATIONSBINPATH"] |
1804 for langFile in self.__pdata["TRANSLATIONS"][:]: |
1835 for langFile in self.__pdata["TRANSLATIONS"][:]: |
1805 qmFile = self.__binaryTranslationFile(langFile) |
1836 qmFile = self.__binaryTranslationFile(langFile) |
1806 if qmFile: |
1837 if qmFile: |
1807 if qmFile not in self.__pdata["TRANSLATIONS"] and os.path.exists( |
1838 if FileSystemUtilities.isRemoteFileName(self.ppath): |
1808 os.path.join(self.ppath, qmFile) |
1839 if ( |
1809 ): |
1840 qmFile not in self.__pdata["TRANSLATIONS"] |
1810 self.appendFile(qmFile) |
1841 and self.__remotefsInterface.exists( |
1811 if tbPath: |
1842 self.__remotefsInterface.join(self.ppath, qmFile) |
1812 qmFile = os.path.join(tbPath, os.path.basename(qmFile)) |
1843 ) |
|
1844 ): |
|
1845 self.appendFile(qmFile) |
|
1846 if tbPath: |
|
1847 qmFile = self.__remotefsInterface.join( |
|
1848 tbPath, self.__remotefsInterface.basename(qmFile) |
|
1849 ) |
|
1850 if ( |
|
1851 qmFile not in self.__pdata["TRANSLATIONS"] |
|
1852 and self.__remotefsInterface.exists( |
|
1853 self.__remotefsInterface.join(self.ppath, qmFile) |
|
1854 ) |
|
1855 ): |
|
1856 self.appendFile(qmFile) |
|
1857 else: |
1813 if qmFile not in self.__pdata["TRANSLATIONS"] and os.path.exists( |
1858 if qmFile not in self.__pdata["TRANSLATIONS"] and os.path.exists( |
1814 os.path.join(self.ppath, qmFile) |
1859 os.path.join(self.ppath, qmFile) |
1815 ): |
1860 ): |
1816 self.appendFile(qmFile) |
1861 self.appendFile(qmFile) |
|
1862 if tbPath: |
|
1863 qmFile = os.path.join(tbPath, os.path.basename(qmFile)) |
|
1864 if ( |
|
1865 qmFile not in self.__pdata["TRANSLATIONS"] |
|
1866 and os.path.exists(os.path.join(self.ppath, qmFile)) |
|
1867 ): |
|
1868 self.appendFile(qmFile) |
1817 |
1869 |
1818 def removeLanguageFile(self, langFile): |
1870 def removeLanguageFile(self, langFile): |
1819 """ |
1871 """ |
1820 Public slot to remove a translation from the project. |
1872 Public slot to remove a translation from the project. |
1821 |
1873 |
1830 self.__model.removeItem(langFile) |
1882 self.__model.removeItem(langFile) |
1831 self.__pdata["TRANSLATIONS"].remove(langFile) |
1883 self.__pdata["TRANSLATIONS"].remove(langFile) |
1832 if qmFile: |
1884 if qmFile: |
1833 with contextlib.suppress(ValueError): |
1885 with contextlib.suppress(ValueError): |
1834 if self.__pdata["TRANSLATIONSBINPATH"]: |
1886 if self.__pdata["TRANSLATIONSBINPATH"]: |
1835 qmFile = self.getRelativePath( |
1887 if FileSystemUtilities.isRemoteFileName(self.ppath): |
1836 os.path.join( |
1888 qmFile = self.__remotefsInterface.join( |
1837 self.__pdata["TRANSLATIONSBINPATH"], |
1889 self.__pdata["TRANSLATIONSBINPATH"], |
1838 os.path.basename(qmFile), |
1890 self.__remotefsInterface.basename(qmFile), |
1839 ) |
1891 ) |
1840 ) |
1892 else: |
|
1893 qmFile = self.getRelativePath( |
|
1894 os.path.join( |
|
1895 self.__pdata["TRANSLATIONSBINPATH"], |
|
1896 os.path.basename(qmFile), |
|
1897 ) |
|
1898 ) |
1841 self.__model.removeItem(qmFile) |
1899 self.__model.removeItem(qmFile) |
1842 self.__pdata["TRANSLATIONS"].remove(qmFile) |
1900 self.__pdata["TRANSLATIONS"].remove(qmFile) |
1843 self.setDirty(True) |
1901 self.setDirty(True) |
1844 |
1902 |
1845 def deleteLanguageFile(self, langFile): |
1903 def deleteLanguageFile(self, langFile): |
1851 """ |
1909 """ |
1852 langFile = self.getRelativePath(langFile) |
1910 langFile = self.getRelativePath(langFile) |
1853 qmFile = self.__binaryTranslationFile(langFile) |
1911 qmFile = self.__binaryTranslationFile(langFile) |
1854 |
1912 |
1855 try: |
1913 try: |
1856 fn = os.path.join(self.ppath, langFile) |
1914 if FileSystemUtilities.isRemoteFileName(self.ppath): |
1857 if os.path.exists(fn): |
1915 fn = self.__remotefsInterface.join(self.ppath, langFile) |
1858 os.remove(fn) |
1916 if self.__remotefsInterface.exists(fn): |
|
1917 self.__remotefsInterface.remove(fn) |
|
1918 else: |
|
1919 fn = os.path.join(self.ppath, langFile) |
|
1920 if os.path.exists(fn): |
|
1921 os.remove(fn) |
1859 except OSError as err: |
1922 except OSError as err: |
1860 EricMessageBox.critical( |
1923 EricMessageBox.critical( |
1861 self.ui, |
1924 self.ui, |
1862 self.tr("Delete translation"), |
1925 self.tr("Delete Translation"), |
1863 self.tr( |
1926 self.tr( |
1864 "<p>The selected translation file <b>{0}</b> could not be" |
1927 "<p>The selected translation file <b>{0}</b> could not be" |
1865 " deleted.</p><p>Reason: {1}</p>" |
1928 " deleted.</p><p>Reason: {1}</p>" |
1866 ).format(langFile, str(err)), |
1929 ).format(langFile, str(err)), |
1867 ) |
1930 ) |
1908 """ |
1971 """ |
1909 dirty = False |
1972 dirty = False |
1910 |
1973 |
1911 # make it relative to the project root, if it starts with that path |
1974 # make it relative to the project root, if it starts with that path |
1912 # assume relative paths are relative to the project root |
1975 # assume relative paths are relative to the project root |
1913 newfn = self.getRelativePath(fn) if os.path.isabs(fn) else fn |
1976 if FileSystemUtilities.isRemoteFileName(self.ppath): |
1914 newdir = os.path.dirname(newfn) |
1977 newfn = self.getRelativePath(fn) if fn.startswith(self.ppath) else fn |
|
1978 newdir = self.__remotefsInterface.dirname(newfn) |
|
1979 else: |
|
1980 newfn = self.getRelativePath(fn) if os.path.isabs(fn) else fn |
|
1981 newdir = os.path.dirname(newfn) |
1915 |
1982 |
1916 if isSourceFile: |
1983 if isSourceFile: |
1917 filetype = "SOURCES" |
1984 filetype = "SOURCES" |
1918 else: |
1985 else: |
1919 filetype = "OTHERS" |
1986 filetype = "OTHERS" |
1920 bfn = os.path.basename(newfn) |
1987 bfn = ( |
|
1988 self.__remotefsInterface.basename(newfn) |
|
1989 if FileSystemUtilities.isRemoteFileName(self.ppath) |
|
1990 else os.path.basename(newfn) |
|
1991 ) |
1921 if fnmatch.fnmatch(bfn, "*.ts") or fnmatch.fnmatch(bfn, "*.qm"): |
1992 if fnmatch.fnmatch(bfn, "*.ts") or fnmatch.fnmatch(bfn, "*.qm"): |
1922 filetype = "TRANSLATIONS" |
1993 filetype = "TRANSLATIONS" |
1923 else: |
1994 else: |
1924 for pattern in sorted(self.__pdata["FILETYPES"], reverse=True): |
1995 for pattern in sorted(self.__pdata["FILETYPES"], reverse=True): |
1925 if fnmatch.fnmatch(bfn, pattern): |
1996 if fnmatch.fnmatch(bfn, pattern): |
3925 |
4001 |
3926 @return name of the project |
4002 @return name of the project |
3927 @rtype str |
4003 @rtype str |
3928 """ |
4004 """ |
3929 if self.pfile: |
4005 if self.pfile: |
3930 name = os.path.splitext(self.pfile)[0] |
4006 return self.name |
3931 return os.path.basename(name) |
|
3932 else: |
4007 else: |
3933 return "" |
4008 return "" |
3934 |
4009 |
3935 def getProjectManagementDir(self): |
4010 def getProjectManagementDir(self): |
3936 """ |
4011 """ |
3937 Public method to get the path of the management directory. |
4012 Public method to get the path of the management directory. |
3938 |
4013 |
3939 @return path of the management directory |
4014 @return path of the management directory |
3940 @rtype str |
4015 @rtype str |
3941 """ |
4016 """ |
3942 return os.path.join(self.ppath, ".eric7project") |
4017 if FileSystemUtilities.isRemoteFileName(self.ppath): |
|
4018 return self.__remotefsInterface.join(self.ppath, ".eric7project") |
|
4019 else: |
|
4020 return os.path.join(self.ppath, ".eric7project") |
3943 |
4021 |
3944 def createProjectManagementDir(self): |
4022 def createProjectManagementDir(self): |
3945 """ |
4023 """ |
3946 Public method to create the project management directory. |
4024 Public method to create the project management directory. |
3947 |
4025 |
3948 It does nothing, if it already exists. |
4026 It does nothing, if it already exists. |
3949 """ |
4027 """ |
3950 # create management directory if not present |
4028 # create management directory if not present |
3951 mgmtDir = self.getProjectManagementDir() |
4029 mgmtDir = self.getProjectManagementDir() |
3952 if not os.path.exists(mgmtDir): |
4030 if FileSystemUtilities.isRemoteFileName(mgmtDir): |
3953 os.makedirs(mgmtDir) |
4031 self.__remotefsInterface.makedirs(mgmtDir, exist_ok=True) |
|
4032 else: |
|
4033 os.makedirs(mgmtDir, exist_ok=True) |
3954 |
4034 |
3955 def getHash(self): |
4035 def getHash(self): |
3956 """ |
4036 """ |
3957 Public method to get the project hash. |
4037 Public method to get the project hash. |
3958 |
4038 |
4324 act.setWhatsThis( |
4429 act.setWhatsThis( |
4325 self.tr("""<b>Open...</b><p>This opens an existing project.</p>""") |
4430 self.tr("""<b>Open...</b><p>This opens an existing project.</p>""") |
4326 ) |
4431 ) |
4327 act.triggered.connect(self.openProject) |
4432 act.triggered.connect(self.openProject) |
4328 self.actions.append(act) |
4433 self.actions.append(act) |
|
4434 |
|
4435 self.openRemoteAct = EricAction( |
|
4436 self.tr("Open remote project"), |
|
4437 EricPixmapCache.getIcon("projectOpen-remote"), |
|
4438 self.tr("Open (Remote)..."), |
|
4439 0, |
|
4440 0, |
|
4441 self.actGrp1, |
|
4442 "project_open_remote", |
|
4443 ) |
|
4444 self.openRemoteAct.setStatusTip(self.tr("Open an existing remote project")) |
|
4445 self.openRemoteAct.setWhatsThis( |
|
4446 self.tr( |
|
4447 "<b>Open (Remote)...</b><p>This opens an existing remote project.</p>" |
|
4448 ) |
|
4449 ) |
|
4450 self.openRemoteAct.triggered.connect(self.__openRemoteProject) |
|
4451 self.actions.append(self.openRemoteAct) |
|
4452 self.openRemoteAct.setEnabled(False) # server is not connected initially |
4329 |
4453 |
4330 self.reloadAct = EricAction( |
4454 self.reloadAct = EricAction( |
4331 self.tr("Reload project"), |
4455 self.tr("Reload project"), |
4332 EricPixmapCache.getIcon("projectReload"), |
4456 EricPixmapCache.getIcon("projectReload"), |
4333 self.tr("Re&load"), |
4457 self.tr("Re&load"), |
7292 self.__createEmbeddedEnvironment(upgrade=True) |
7416 self.__createEmbeddedEnvironment(upgrade=True) |
7293 except (OSError, json.JSONDecodeError): |
7417 except (OSError, json.JSONDecodeError): |
7294 # the configuration file does not exist or is invalid JSON |
7418 # the configuration file does not exist or is invalid JSON |
7295 self.__initVenvConfiguration() |
7419 self.__initVenvConfiguration() |
7296 |
7420 |
|
7421 ############################################################################# |
|
7422 ## Below are methods implementing the support for 'eric-ide server projects |
|
7423 ############################################################################# |
|
7424 |
|
7425 @pyqtSlot(bool) |
|
7426 def remoteConnectionChanged(self, connected): |
|
7427 """ |
|
7428 Public slot to handle a change of the 'eric-ide' server connection state. |
|
7429 |
|
7430 @param connected flag indicating the connection state |
|
7431 @type bool |
|
7432 """ |
|
7433 self.openRemoteAct.setEnabled(connected) |
|
7434 |
|
7435 @pyqtSlot() |
|
7436 def __openRemoteProject(self): |
|
7437 """ |
|
7438 Private slot to open a project of an 'eric-ide' server. |
|
7439 """ |
|
7440 # TODO: not implemented yet |
|
7441 fn = EricServerFileDialog.getOpenFileName( |
|
7442 self.parent(), |
|
7443 self.tr("Open project"), |
|
7444 "", |
|
7445 self.tr("Project Files (*.epj)"), |
|
7446 ) |
|
7447 if fn: |
|
7448 self.openProject(fn=fn) |
7297 |
7449 |
7298 # |
7450 # |
7299 # eflag: noqa = M601 |
7451 # eflag: noqa = M601 |