src/eric7/Project/Project.py

branch
server
changeset 10596
ea35c92a3c7c
parent 10593
b7ebfc2e47d4
child 10597
fbe93720ee9f
equal deleted inserted replaced
10594:6156d9675f62 10596:ea35c92a3c7c
21 21
22 from PyQt6.Qsci import QsciScintilla 22 from PyQt6.Qsci import QsciScintilla
23 from PyQt6.QtCore import ( 23 from PyQt6.QtCore import (
24 QByteArray, 24 QByteArray,
25 QCryptographicHash, 25 QCryptographicHash,
26 QFile,
27 QIODevice,
28 QObject, 26 QObject,
29 QProcess, 27 QProcess,
30 pyqtSignal, 28 pyqtSignal,
31 pyqtSlot, 29 pyqtSlot,
32 ) 30 )
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,
163 eols = [os.linesep, "\n", "\r", "\r\n"] 157 eols = [os.linesep, "\n", "\r", "\r\n"]
164 158
165 DefaultMake = "make" 159 DefaultMake = "make"
166 DefaultMakefile = "makefile" 160 DefaultMakefile = "makefile"
167 161
168 def __init__(self, parent=None, filename=None): 162 def __init__(self, parent=None, filename=None, remoteServer=None):
169 """ 163 """
170 Constructor 164 Constructor
171 165
172 @param parent parent widget (usually the ui object) 166 @param parent parent widget (usually the ui object)
173 @type QWidget 167 @type QWidget
174 @param filename optional filename of a project file to open 168 @param filename optional filename of a project file to open (defaults to None)
175 @type str 169 @type str (optional)
170 @param remoteServer reference to the 'eric-ide' server interface object
171 @type EricServerInterface
176 """ 172 """
177 super().__init__(parent) 173 super().__init__(parent)
178 174
179 self.ui = parent 175 self.ui = parent
176 self.__remotefsInterface = remoteServer.getServiceInterface("FileSystem")
180 177
181 self.__progLanguages = [ 178 self.__progLanguages = [
182 "Python3", 179 "Python3",
183 "MicroPython", 180 "MicroPython",
184 "Ruby", 181 "Ruby",
215 if filename is not None: 212 if filename is not None:
216 self.openProject(filename) 213 self.openProject(filename)
217 else: 214 else:
218 self.vcs = self.initVCS() 215 self.vcs = self.initVCS()
219 216
220 self.__model = ProjectBrowserModel(self) 217 self.__model = ProjectBrowserModel(self, fsInterface=self.__remotefsInterface)
221 218
222 self.codemetrics = None 219 self.codemetrics = None
223 self.codecoverage = None 220 self.codecoverage = None
224 self.profiledata = None 221 self.profiledata = None
225 self.applicationDiagram = None 222 self.applicationDiagram = None
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).
1372 self.tr("Save Project Session"), 1374 self.tr("Save Project Session"),
1373 self.tr("Please save the project first."), 1375 self.tr("Please save the project first."),
1374 ) 1376 )
1375 return 1377 return
1376 1378
1377 fn, ext = os.path.splitext(os.path.basename(self.pfile)) 1379 if FileSystemUtilities.isRemoteFileName(self.pfile):
1378 fn = os.path.join( 1380 fn1, _ext = self.__remotefsInterface.splitext(
1379 self.getProjectManagementDir(), "{0}{1}.esj".format(fn, indicator) 1381 self.__remotefsInterface.basename(self.pfile)
1380 ) 1382 )
1383 fn = self.__remotefsInterface.join(
1384 self.getProjectManagementDir(), f"{fn1}{indicator}.esj"
1385 )
1386 else:
1387 fn1, _ext = os.path.splitext(os.path.basename(self.pfile))
1388 fn = os.path.join(
1389 self.getProjectManagementDir(), f"{fn1}{indicator}.esj"
1390 )
1381 1391
1382 self.__sessionFile.writeFile(fn) 1392 self.__sessionFile.writeFile(fn)
1383 1393
1384 def __deleteSession(self): 1394 def __deleteSession(self):
1385 """ 1395 """
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).
1545 self.tr("Save Debugger Properties"), 1560 self.tr("Save Debugger Properties"),
1546 self.tr("Please save the project first."), 1561 self.tr("Please save the project first."),
1547 ) 1562 )
1548 return 1563 return
1549 1564
1550 fn, ext = os.path.splitext(os.path.basename(self.pfile)) 1565 if FileSystemUtilities.isRemoteFileName(self.pfile):
1551 fn = os.path.join(self.getProjectManagementDir(), "{0}.edj".format(fn)) 1566 fn1, _ext = self.__remotefsInterface.splitext(
1567 self.__remotefsInterface.basename(self.pfile)
1568 )
1569 fn = self.__remotefsInterface.join(
1570 self.getProjectManagementDir(), f"{fn1}.edj"
1571 )
1572 else:
1573 fn1, _ext = os.path.splitext(os.path.basename(self.pfile))
1574 fn = os.path.join(self.getProjectManagementDir(), f"{fn1}.edj")
1552 1575
1553 with EricOverrideCursor(): 1576 with EricOverrideCursor():
1554 self.__debuggerPropertiesFile.writeFile(fn) 1577 self.__debuggerPropertiesFile.writeFile(fn)
1555 1578
1556 def __deleteDebugProperties(self): 1579 def __deleteDebugProperties(self):
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):
1972 @param fileTypeFilter filter to be used by the add file dialog 2043 @param fileTypeFilter filter to be used by the add file dialog
1973 @type str 2044 @type str
1974 @param startdir start directory for the selection dialog 2045 @param startdir start directory for the selection dialog
1975 @type str 2046 @type str
1976 """ 2047 """
2048 # TODO: adapt to remote server
1977 from .AddFileDialog import AddFileDialog 2049 from .AddFileDialog import AddFileDialog
1978 2050
1979 if not startdir: 2051 if not startdir:
1980 startdir = self.ppath 2052 startdir = self.ppath
1981 2053
2036 @param target target directory 2108 @param target target directory
2037 @type str 2109 @type str
2038 @param quiet flag indicating quiet operations 2110 @param quiet flag indicating quiet operations
2039 @type bool 2111 @type bool
2040 """ 2112 """
2113 # TODO: adapt to remote server
2041 # get all relevant filename patterns 2114 # get all relevant filename patterns
2042 patterns = [] 2115 patterns = []
2043 ignorePatterns = [] 2116 ignorePatterns = []
2044 for pattern, patterntype in self.__pdata["FILETYPES"].items(): 2117 for pattern, patterntype in self.__pdata["FILETYPES"].items():
2045 if patterntype == filetype: 2118 if patterntype == filetype:
2119 @param source source directory 2192 @param source source directory
2120 @type str 2193 @type str
2121 @param target target directory 2194 @param target target directory
2122 @type str 2195 @type str
2123 """ 2196 """
2197 # TODO: adapt to remote server
2124 # first perform the addition of source 2198 # first perform the addition of source
2125 self.__addSingleDirectory(filetype, source, target, True) 2199 self.__addSingleDirectory(filetype, source, target, True)
2126 2200
2127 ignore_patterns = [ 2201 ignore_patterns = [
2128 ".svn", 2202 ".svn",
2157 @param fileTypeFilter filter to be used by the add directory dialog 2231 @param fileTypeFilter filter to be used by the add directory dialog
2158 @type str 2232 @type str
2159 @param startdir start directory for the selection dialog 2233 @param startdir start directory for the selection dialog
2160 @type str 2234 @type str
2161 """ 2235 """
2236 # TODO: adapt to remote server
2162 from .AddDirectoryDialog import AddDirectoryDialog 2237 from .AddDirectoryDialog import AddDirectoryDialog
2163 2238
2164 if not startdir: 2239 if not startdir:
2165 startdir = self.ppath 2240 startdir = self.ppath
2166 2241
2197 Public method to add a file/directory to the OTHERS project data. 2272 Public method to add a file/directory to the OTHERS project data.
2198 2273
2199 @param fn file name or directory name to add 2274 @param fn file name or directory name to add
2200 @type str 2275 @type str
2201 """ 2276 """
2277 # TODO: adapt to remote server
2202 if fn: 2278 if fn:
2203 # if it is below the project directory, make it relative to that 2279 # if it is below the project directory, make it relative to that
2204 fn = self.getRelativePath(fn) 2280 fn = self.getRelativePath(fn)
2205 2281
2206 # if it ends with the directory separator character, remove it 2282 # if it ends with the directory separator character, remove it
2242 @param newfn new filename of the file 2318 @param newfn new filename of the file
2243 @type str 2319 @type str
2244 @return flag indicating success 2320 @return flag indicating success
2245 @rtype bool 2321 @rtype bool
2246 """ 2322 """
2323 # TODO: adapt to remote server
2247 fn = self.getRelativePath(oldfn) 2324 fn = self.getRelativePath(oldfn)
2248 isSourceFile = fn in self.__pdata["SOURCES"] 2325 isSourceFile = fn in self.__pdata["SOURCES"]
2249 2326
2250 if newfn is None: 2327 if newfn is None:
2251 newfn = EricFileDialog.getSaveFileName( 2328 newfn = EricFileDialog.getSaveFileName(
2300 @type str 2377 @type str
2301 @param isSourceFile flag indicating that this is a source file 2378 @param isSourceFile flag indicating that this is a source file
2302 even if it doesn't have the source extension 2379 even if it doesn't have the source extension
2303 @type bool 2380 @type bool
2304 """ 2381 """
2382 # TODO: adapt to remote server
2305 fn = self.getRelativePath(oldname) 2383 fn = self.getRelativePath(oldname)
2306 if os.path.dirname(oldname) == os.path.dirname(newname): 2384 if os.path.dirname(oldname) == os.path.dirname(newname):
2307 if self.__isInPdata(oldname): 2385 if self.__isInPdata(oldname):
2308 self.removeFile(oldname, False) 2386 self.removeFile(oldname, False)
2309 self.appendFile(newname, isSourceFile, False) 2387 self.appendFile(newname, isSourceFile, False)
2322 @param start prefix 2400 @param start prefix
2323 @type str 2401 @type str
2324 @return list of files starting with a common prefix 2402 @return list of files starting with a common prefix
2325 @rtype list of str 2403 @rtype list of str
2326 """ 2404 """
2405 # TODO: adapt to remote server
2327 filelist = [] 2406 filelist = []
2328 start = self.getRelativePath(start) 2407 start = self.getRelativePath(start)
2329 for fileCategory in [ 2408 for fileCategory in [
2330 c for c in self.getFileCategories() if c != "TRANSLATIONS" 2409 c for c in self.getFileCategories() if c != "TRANSLATIONS"
2331 ]: 2410 ]:
3421 @return flag indicating success 3500 @return flag indicating success
3422 @rtype bool 3501 @rtype bool
3423 """ 3502 """
3424 if self.isDirty(): 3503 if self.isDirty():
3425 if len(self.pfile) > 0: 3504 if len(self.pfile) > 0:
3426 if self.pfile.endswith(".e4p"):
3427 self.pfile = self.pfile.replace(".e4p", ".epj")
3428 self.__syncRecent()
3429 ok = self.__writeProject() 3505 ok = self.__writeProject()
3430 else: 3506 else:
3431 ok = self.saveProjectAs() 3507 ok = self.saveProjectAs()
3432 else: 3508 else:
3433 ok = True 3509 ok = True
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
3974 """ 4054 """
3975 if path is None: 4055 if path is None:
3976 return "" 4056 return ""
3977 4057
3978 try: 4058 try:
3979 return str(pathlib.Path(path).relative_to(self.ppath)) 4059 if FileSystemUtilities.isRemoteFileName(self.ppath):
4060 if self.__remotefsInterface.separator() == "\\":
4061 return str(pathlib.PureWindowsPath(path).relative_to(self.ppath))
4062 else:
4063 return str(pathlib.PurePosixPath(path).relative_to(self.ppath))
4064 else:
4065 return str(pathlib.PurePath(path).relative_to(self.ppath))
3980 except ValueError: 4066 except ValueError:
3981 return path 4067 return path
3982 4068
3983 def getRelativeUniversalPath(self, path): 4069 def getRelativeUniversalPath(self, path):
3984 """ 4070 """
3989 @type str 4075 @type str
3990 @return project relative path or unchanged path, if path doesn't 4076 @return project relative path or unchanged path, if path doesn't
3991 belong to the project 4077 belong to the project
3992 @rtype str 4078 @rtype str
3993 """ 4079 """
3994 return FileSystemUtilities.fromNativeSeparators(self.getRelativePath(path)) 4080 if FileSystemUtilities.isRemoteFileName(self.ppath):
4081 return self.__remotefsInterface.fromNativeSeparators(
4082 self.getRelativePath(path)
4083 )
4084 else:
4085 return FileSystemUtilities.fromNativeSeparators(self.getRelativePath(path))
3995 4086
3996 def getAbsolutePath(self, fn): 4087 def getAbsolutePath(self, fn):
3997 """ 4088 """
3998 Public method to convert a project relative file path to an absolute 4089 Public method to convert a project relative file path to an absolute
3999 file path. 4090 file path.
4001 @param fn file or directory name to convert 4092 @param fn file or directory name to convert
4002 @type str 4093 @type str
4003 @return absolute path 4094 @return absolute path
4004 @rtype str 4095 @rtype str
4005 """ 4096 """
4006 if not os.path.isabs(fn): 4097 if not fn.startswith(self.ppath):
4007 fn = os.path.join(self.ppath, fn) 4098 if FileSystemUtilities.isRemoteFileName(self.ppath):
4099 fn = self.__remotefsInterface.join(self.ppath, fn)
4100 else:
4101 fn = os.path.join(self.ppath, fn)
4008 return fn 4102 return fn
4009 4103
4010 def getAbsoluteUniversalPath(self, fn): 4104 def getAbsoluteUniversalPath(self, fn):
4011 """ 4105 """
4012 Public method to convert a project relative file path with universal 4106 Public method to convert a project relative file path with universal
4015 @param fn file or directory name to convert 4109 @param fn file or directory name to convert
4016 @type str 4110 @type str
4017 @return absolute path 4111 @return absolute path
4018 @rtype str 4112 @rtype str
4019 """ 4113 """
4020 if not os.path.isabs(fn): 4114 if not fn.startswith(self.ppath):
4021 fn = os.path.join(self.ppath, FileSystemUtilities.toNativeSeparators(fn)) 4115 if FileSystemUtilities.isRemoteFileName(self.ppath):
4116 fn = self.__remotefsInterface.join(
4117 self.ppath, self.__remotefsInterface.fromNativeSeparators(fn)
4118 )
4119 else:
4120 fn = os.path.join(
4121 self.ppath, FileSystemUtilities.fromNativeSeparators(fn)
4122 )
4022 return fn 4123 return fn
4023 4124
4024 def getEolString(self): 4125 def getEolString(self):
4025 """ 4126 """
4026 Public method to get the EOL-string to be used by the project. 4127 Public method to get the EOL-string to be used by the project.
4239 @param group group to check 4340 @param group group to check
4240 @type str 4341 @type str
4241 @return flag indicating membership 4342 @return flag indicating membership
4242 @rtype bool 4343 @rtype bool
4243 """ 4344 """
4244 newfn = os.path.abspath(fn) 4345 newfn = (
4346 fn
4347 if FileSystemUtilities.isRemoteFileName(fn)
4348 else os.path.abspath(fn)
4349 )
4245 newfn = self.getRelativePath(newfn) 4350 newfn = self.getRelativePath(newfn)
4246 if newfn in self.__pdata[group] or ( 4351 if newfn in self.__pdata[group] or (
4247 group == "OTHERS" 4352 group == "OTHERS"
4248 and any(newfn.startswith(entry) for entry in self.__pdata[group]) 4353 and any(newfn.startswith(entry) for entry in self.__pdata[group])
4249 ): 4354 ):
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

eric ide

mercurial