src/eric7/Project/Project.py

branch
eric7
changeset 9221
bf71ee032bb4
parent 9214
bd28e56047d7
child 9235
b5fe898e171f
equal deleted inserted replaced
9220:e9e7eca7efee 9221:bf71ee032bb4
16 import zipfile 16 import zipfile
17 import contextlib 17 import contextlib
18 import pathlib 18 import pathlib
19 19
20 from PyQt6.QtCore import ( 20 from PyQt6.QtCore import (
21 pyqtSlot, QFile, pyqtSignal, QCryptographicHash, QIODevice, QByteArray, 21 pyqtSlot,
22 QObject, QProcess 22 QFile,
23 pyqtSignal,
24 QCryptographicHash,
25 QIODevice,
26 QByteArray,
27 QObject,
28 QProcess,
23 ) 29 )
24 from PyQt6.QtGui import QKeySequence, QAction 30 from PyQt6.QtGui import QKeySequence, QAction
25 from PyQt6.QtWidgets import ( 31 from PyQt6.QtWidgets import QLineEdit, QToolBar, QDialog, QInputDialog, QMenu
26 QLineEdit, QToolBar, QDialog, QInputDialog, QMenu
27 )
28 from PyQt6.Qsci import QsciScintilla 32 from PyQt6.Qsci import QsciScintilla
29 33
30 from EricWidgets.EricApplication import ericApp 34 from EricWidgets.EricApplication import ericApp
31 from EricWidgets import EricFileDialog, EricMessageBox 35 from EricWidgets import EricFileDialog, EricMessageBox
32 from EricWidgets.EricListSelectionDialog import EricListSelectionDialog 36 from EricWidgets.EricListSelectionDialog import EricListSelectionDialog
56 60
57 61
58 class Project(QObject): 62 class Project(QObject):
59 """ 63 """
60 Class implementing the project management functionality. 64 Class implementing the project management functionality.
61 65
62 @signal dirty(bool) emitted when the dirty state changes 66 @signal dirty(bool) emitted when the dirty state changes
63 @signal projectLanguageAdded(str) emitted after a new language was added 67 @signal projectLanguageAdded(str) emitted after a new language was added
64 @signal projectLanguageAddedByCode(str) emitted after a new language was 68 @signal projectLanguageAddedByCode(str) emitted after a new language was
65 added. The language code is sent by this signal. 69 added. The language code is sent by this signal.
66 @signal projectLanguageRemoved(str) emitted after a language was removed 70 @signal projectLanguageRemoved(str) emitted after a language was removed
123 @signal appendStdout(str) emitted after something was received from 127 @signal appendStdout(str) emitted after something was received from
124 a QProcess on stdout 128 a QProcess on stdout
125 @signal appendStderr(str) emitted after something was received from 129 @signal appendStderr(str) emitted after something was received from
126 a QProcess on stderr 130 a QProcess on stderr
127 """ 131 """
132
128 dirty = pyqtSignal(bool) 133 dirty = pyqtSignal(bool)
129 projectLanguageAdded = pyqtSignal(str) 134 projectLanguageAdded = pyqtSignal(str)
130 projectLanguageAddedByCode = pyqtSignal(str) 135 projectLanguageAddedByCode = pyqtSignal(str)
131 projectLanguageRemoved = pyqtSignal(str) 136 projectLanguageRemoved = pyqtSignal(str)
132 projectFormAdded = pyqtSignal(str) 137 projectFormAdded = pyqtSignal(str)
166 showMenu = pyqtSignal(str, QMenu) 171 showMenu = pyqtSignal(str, QMenu)
167 lexerAssociationsChanged = pyqtSignal() 172 lexerAssociationsChanged = pyqtSignal()
168 projectChanged = pyqtSignal() 173 projectChanged = pyqtSignal()
169 appendStdout = pyqtSignal(str) 174 appendStdout = pyqtSignal(str)
170 appendStderr = pyqtSignal(str) 175 appendStderr = pyqtSignal(str)
171 176
172 eols = [os.linesep, "\n", "\r", "\r\n"] 177 eols = [os.linesep, "\n", "\r", "\r\n"]
173 178
174 DefaultMake = "make" 179 DefaultMake = "make"
175 DefaultMakefile = "makefile" 180 DefaultMakefile = "makefile"
176 181
177 def __init__(self, parent=None, filename=None): 182 def __init__(self, parent=None, filename=None):
178 """ 183 """
179 Constructor 184 Constructor
180 185
181 @param parent parent widget (usually the ui object) (QWidget) 186 @param parent parent widget (usually the ui object) (QWidget)
182 @param filename optional filename of a project file to open (string) 187 @param filename optional filename of a project file to open (string)
183 """ 188 """
184 super().__init__(parent) 189 super().__init__(parent)
185 190
186 self.ui = parent 191 self.ui = parent
187 192
188 self.__progLanguages = [ 193 self.__progLanguages = [
189 "Python3", 194 "Python3",
190 "MicroPython", 195 "MicroPython",
191 "Ruby", 196 "Ruby",
192 "JavaScript", 197 "JavaScript",
193 ] 198 ]
194 199
195 self.__dbgFilters = { 200 self.__dbgFilters = {
196 "Python3": self.tr( 201 "Python3": self.tr(
197 "Python3 Files (*.py *.py3);;" 202 "Python3 Files (*.py *.py3);;" "Python3 GUI Files (*.pyw *.pyw3);;"
198 "Python3 GUI Files (*.pyw *.pyw3);;"), 203 ),
199 } 204 }
200 205
201 self.vcsMenu = None 206 self.vcsMenu = None
202 self.__makeProcess = None 207 self.__makeProcess = None
203 208
204 self.__initProjectTypes() 209 self.__initProjectTypes()
205 210
206 self.__initData() 211 self.__initData()
207 212
208 self.__projectFile = ProjectFile(self) 213 self.__projectFile = ProjectFile(self)
209 self.__userProjectFile = UserProjectFile(self) 214 self.__userProjectFile = UserProjectFile(self)
210 self.__debuggerPropertiesFile = DebuggerPropertiesFile(self) 215 self.__debuggerPropertiesFile = DebuggerPropertiesFile(self)
211 self.__sessionFile = SessionFile(False) 216 self.__sessionFile = SessionFile(False)
212 self.__tasksFile = TasksFile(False) 217 self.__tasksFile = TasksFile(False)
213 218
214 self.recent = [] 219 self.recent = []
215 self.__loadRecent() 220 self.__loadRecent()
216 221
217 if filename is not None: 222 if filename is not None:
218 self.openProject(filename) 223 self.openProject(filename)
219 else: 224 else:
220 self.vcs = self.initVCS() 225 self.vcs = self.initVCS()
221 226
222 from .ProjectBrowserModel import ProjectBrowserModel 227 from .ProjectBrowserModel import ProjectBrowserModel
228
223 self.__model = ProjectBrowserModel(self) 229 self.__model = ProjectBrowserModel(self)
224 230
225 self.codemetrics = None 231 self.codemetrics = None
226 self.codecoverage = None 232 self.codecoverage = None
227 self.profiledata = None 233 self.profiledata = None
228 self.applicationDiagram = None 234 self.applicationDiagram = None
229 self.loadedDiagram = None 235 self.loadedDiagram = None
230 self.__findProjectFileDialog = None 236 self.__findProjectFileDialog = None
231 237
232 def __sourceExtensions(self, language): 238 def __sourceExtensions(self, language):
233 """ 239 """
234 Private method to get the source extensions of a programming language. 240 Private method to get the source extensions of a programming language.
235 241
236 @param language programming language (string) 242 @param language programming language (string)
237 @return source extensions (list of string) 243 @return source extensions (list of string)
238 """ 244 """
239 if language == "Python3": 245 if language == "Python3":
240 extensions = Preferences.getPython("Python3Extensions") 246 extensions = Preferences.getPython("Python3Extensions")
252 return extensions 258 return extensions
253 else: 259 else:
254 return { 260 return {
255 "Ruby": [".rb"], 261 "Ruby": [".rb"],
256 "JavaScript": [".js"], 262 "JavaScript": [".js"],
257 "Mixed": ( 263 "Mixed": (Preferences.getPython("Python3Extensions") + [".rb", ".js"]),
258 Preferences.getPython("Python3Extensions") +
259 ['.rb', '.js']),
260 }.get(language, "") 264 }.get(language, "")
261 265
262 def getProgrammingLanguages(self): 266 def getProgrammingLanguages(self):
263 """ 267 """
264 Public method to get the programming languages supported by project. 268 Public method to get the programming languages supported by project.
265 269
266 @return list of supported programming languages (list of string) 270 @return list of supported programming languages (list of string)
267 """ 271 """
268 return self.__progLanguages[:] 272 return self.__progLanguages[:]
269 273
270 def getDebuggerFilters(self, language): 274 def getDebuggerFilters(self, language):
271 """ 275 """
272 Public method to get the debugger filters for a programming language. 276 Public method to get the debugger filters for a programming language.
273 277
274 @param language programming language 278 @param language programming language
275 @type str 279 @type str
276 @return filter string 280 @return filter string
277 @rtype str 281 @rtype str
278 """ 282 """
279 try: 283 try:
280 return self.__dbgFilters[language] 284 return self.__dbgFilters[language]
281 except KeyError: 285 except KeyError:
282 return "" 286 return ""
283 287
284 def __initProjectTypes(self): 288 def __initProjectTypes(self):
285 """ 289 """
286 Private method to initialize the list of supported project types. 290 Private method to initialize the list of supported project types.
287 """ 291 """
288 self.__fileTypeCallbacks = {} 292 self.__fileTypeCallbacks = {}
289 self.__lexerAssociationCallbacks = {} 293 self.__lexerAssociationCallbacks = {}
290 self.__binaryTranslationsCallbacks = {} 294 self.__binaryTranslationsCallbacks = {}
291 295
292 self.__projectTypes = { 296 self.__projectTypes = {
293 "PyQt5": self.tr("PyQt5 GUI"), 297 "PyQt5": self.tr("PyQt5 GUI"),
294 "PyQt5C": self.tr("PyQt5 Console"), 298 "PyQt5C": self.tr("PyQt5 Console"),
295 "PyQt6": self.tr("PyQt6 GUI"), 299 "PyQt6": self.tr("PyQt6 GUI"),
296 "PyQt6C": self.tr("PyQt6 Console"), 300 "PyQt6C": self.tr("PyQt6 Console"),
297 "E7Plugin": self.tr("Eric7 Plugin"), 301 "E7Plugin": self.tr("Eric7 Plugin"),
298 "Console": self.tr("Console"), 302 "Console": self.tr("Console"),
299 "Other": self.tr("Other"), 303 "Other": self.tr("Other"),
300 } 304 }
301 305
302 self.__projectProgLanguages = { 306 self.__projectProgLanguages = {
303 "Python3": ["PyQt5", "PyQt5C", "PyQt6", "PyQt6C", "E7Plugin", 307 "Python3": [
304 "Console", "Other"], 308 "PyQt5",
309 "PyQt5C",
310 "PyQt6",
311 "PyQt6C",
312 "E7Plugin",
313 "Console",
314 "Other",
315 ],
305 "MicroPython": ["Console", "Other"], 316 "MicroPython": ["Console", "Other"],
306 "Ruby": ["Console", "Other"], 317 "Ruby": ["Console", "Other"],
307 "JavaScript": ["Other"], 318 "JavaScript": ["Other"],
308 } 319 }
309 320
310 if Utilities.checkPyside(variant=2): 321 if Utilities.checkPyside(variant=2):
311 self.__projectTypes["PySide2"] = self.tr("PySide2 GUI") 322 self.__projectTypes["PySide2"] = self.tr("PySide2 GUI")
312 self.__projectTypes["PySide2C"] = self.tr("PySide2 Console") 323 self.__projectTypes["PySide2C"] = self.tr("PySide2 Console")
313 self.__projectProgLanguages["Python3"].extend( 324 self.__projectProgLanguages["Python3"].extend(["PySide2", "PySide2C"])
314 ["PySide2", "PySide2C"]) 325
315
316 if Utilities.checkPyside(variant=6): 326 if Utilities.checkPyside(variant=6):
317 self.__projectTypes["PySide6"] = self.tr("PySide6 GUI") 327 self.__projectTypes["PySide6"] = self.tr("PySide6 GUI")
318 self.__projectTypes["PySide6C"] = self.tr("PySide6 Console") 328 self.__projectTypes["PySide6C"] = self.tr("PySide6 Console")
319 self.__projectProgLanguages["Python3"].extend( 329 self.__projectProgLanguages["Python3"].extend(["PySide6", "PySide6C"])
320 ["PySide6", "PySide6C"]) 330
321
322 def getProjectTypes(self, progLanguage=""): 331 def getProjectTypes(self, progLanguage=""):
323 """ 332 """
324 Public method to get the list of supported project types. 333 Public method to get the list of supported project types.
325 334
326 @param progLanguage programming language to get project types for 335 @param progLanguage programming language to get project types for
327 (string) 336 (string)
328 @return reference to the dictionary of project types. 337 @return reference to the dictionary of project types.
329 """ 338 """
330 if progLanguage and progLanguage in self.__projectProgLanguages: 339 if progLanguage and progLanguage in self.__projectProgLanguages:
332 for ptype in self.__projectProgLanguages[progLanguage]: 341 for ptype in self.__projectProgLanguages[progLanguage]:
333 ptypes[ptype] = self.__projectTypes[ptype] 342 ptypes[ptype] = self.__projectTypes[ptype]
334 return ptypes 343 return ptypes
335 else: 344 else:
336 return self.__projectTypes 345 return self.__projectTypes
337 346
338 def hasProjectType(self, type_, progLanguage=""): 347 def hasProjectType(self, type_, progLanguage=""):
339 """ 348 """
340 Public method to check, if a project type is already registered. 349 Public method to check, if a project type is already registered.
341 350
342 @param type_ internal type designator (string) 351 @param type_ internal type designator (string)
343 @param progLanguage programming language of the project type (string) 352 @param progLanguage programming language of the project type (string)
344 @return flag indicating presence of the project type (boolean) 353 @return flag indicating presence of the project type (boolean)
345 """ 354 """
346 if progLanguage: 355 if progLanguage:
347 return ( 356 return (
348 progLanguage in self.__projectProgLanguages and 357 progLanguage in self.__projectProgLanguages
349 type_ in self.__projectProgLanguages[progLanguage] 358 and type_ in self.__projectProgLanguages[progLanguage]
350 ) 359 )
351 else: 360 else:
352 return type_ in self.__projectTypes 361 return type_ in self.__projectTypes
353 362
354 def registerProjectType(self, type_, description, fileTypeCallback=None, 363 def registerProjectType(
355 binaryTranslationsCallback=None, 364 self,
356 lexerAssociationCallback=None, progLanguages=None): 365 type_,
366 description,
367 fileTypeCallback=None,
368 binaryTranslationsCallback=None,
369 lexerAssociationCallback=None,
370 progLanguages=None,
371 ):
357 """ 372 """
358 Public method to register a project type. 373 Public method to register a project type.
359 374
360 @param type_ internal type designator to be registered (string) 375 @param type_ internal type designator to be registered (string)
361 @param description more verbose type name (display string) (string) 376 @param description more verbose type name (display string) (string)
362 @param fileTypeCallback reference to a method returning a dictionary 377 @param fileTypeCallback reference to a method returning a dictionary
363 of filetype associations. 378 of filetype associations.
364 @param binaryTranslationsCallback reference to a method returning 379 @param binaryTranslationsCallback reference to a method returning
376 EricMessageBox.critical( 391 EricMessageBox.critical(
377 self.ui, 392 self.ui,
378 self.tr("Registering Project Type"), 393 self.tr("Registering Project Type"),
379 self.tr( 394 self.tr(
380 """<p>The Programming Language <b>{0}</b> is not""" 395 """<p>The Programming Language <b>{0}</b> is not"""
381 """ supported (project type: {1}).</p>""") 396 """ supported (project type: {1}).</p>"""
382 .format(progLanguage, type_) 397 ).format(progLanguage, type_),
383 ) 398 )
384 return 399 return
385 400
386 if type_ in self.__projectProgLanguages[progLanguage]: 401 if type_ in self.__projectProgLanguages[progLanguage]:
387 EricMessageBox.critical( 402 EricMessageBox.critical(
388 self.ui, 403 self.ui,
389 self.tr("Registering Project Type"), 404 self.tr("Registering Project Type"),
390 self.tr( 405 self.tr(
391 """<p>The Project type <b>{0}</b> is already""" 406 """<p>The Project type <b>{0}</b> is already"""
392 """ registered with Programming Language""" 407 """ registered with Programming Language"""
393 """ <b>{1}</b>.</p>""") 408 """ <b>{1}</b>.</p>"""
394 .format(type_, progLanguage) 409 ).format(type_, progLanguage),
395 ) 410 )
396 return 411 return
397 412
398 if type_ in self.__projectTypes: 413 if type_ in self.__projectTypes:
399 EricMessageBox.critical( 414 EricMessageBox.critical(
400 self.ui, 415 self.ui,
401 self.tr("Registering Project Type"), 416 self.tr("Registering Project Type"),
402 self.tr("""<p>The Project type <b>{0}</b> is already""" 417 self.tr(
403 """ registered.</p>""").format(type_) 418 """<p>The Project type <b>{0}</b> is already"""
419 """ registered.</p>"""
420 ).format(type_),
404 ) 421 )
405 else: 422 else:
406 self.__projectTypes[type_] = description 423 self.__projectTypes[type_] = description
407 self.__fileTypeCallbacks[type_] = fileTypeCallback 424 self.__fileTypeCallbacks[type_] = fileTypeCallback
408 self.__lexerAssociationCallbacks[type_] = lexerAssociationCallback 425 self.__lexerAssociationCallbacks[type_] = lexerAssociationCallback
409 self.__binaryTranslationsCallbacks[type_] = ( 426 self.__binaryTranslationsCallbacks[type_] = binaryTranslationsCallback
410 binaryTranslationsCallback
411 )
412 if progLanguages: 427 if progLanguages:
413 for progLanguage in progLanguages: 428 for progLanguage in progLanguages:
414 self.__projectProgLanguages[progLanguage].append(type_) 429 self.__projectProgLanguages[progLanguage].append(type_)
415 else: 430 else:
416 # no specific programming languages given -> add to all 431 # no specific programming languages given -> add to all
417 for progLanguage in self.__projectProgLanguages: 432 for progLanguage in self.__projectProgLanguages:
418 self.__projectProgLanguages[progLanguage].append(type_) 433 self.__projectProgLanguages[progLanguage].append(type_)
419 434
420 def unregisterProjectType(self, type_): 435 def unregisterProjectType(self, type_):
421 """ 436 """
422 Public method to unregister a project type. 437 Public method to unregister a project type.
423 438
424 @param type_ internal type designator to be unregistered (string) 439 @param type_ internal type designator to be unregistered (string)
425 """ 440 """
426 for progLanguage in self.__projectProgLanguages: 441 for progLanguage in self.__projectProgLanguages:
427 if type_ in self.__projectProgLanguages[progLanguage]: 442 if type_ in self.__projectProgLanguages[progLanguage]:
428 self.__projectProgLanguages[progLanguage].remove(type_) 443 self.__projectProgLanguages[progLanguage].remove(type_)
432 del self.__fileTypeCallbacks[type_] 447 del self.__fileTypeCallbacks[type_]
433 if type_ in self.__lexerAssociationCallbacks: 448 if type_ in self.__lexerAssociationCallbacks:
434 del self.__lexerAssociationCallbacks[type_] 449 del self.__lexerAssociationCallbacks[type_]
435 if type_ in self.__binaryTranslationsCallbacks: 450 if type_ in self.__binaryTranslationsCallbacks:
436 del self.__binaryTranslationsCallbacks[type_] 451 del self.__binaryTranslationsCallbacks[type_]
437 452
438 def __initData(self): 453 def __initData(self):
439 """ 454 """
440 Private method to initialize the project data part. 455 Private method to initialize the project data part.
441 """ 456 """
442 self.loaded = False # flag for the loaded status 457 self.loaded = False # flag for the loaded status
443 self.__dirty = False # dirty flag 458 self.__dirty = False # dirty flag
444 self.pfile = "" # name of the project file 459 self.pfile = "" # name of the project file
445 self.ppath = "" # name of the project directory 460 self.ppath = "" # name of the project directory
446 self.translationsRoot = "" # the translations prefix 461 self.translationsRoot = "" # the translations prefix
447 self.name = "" 462 self.name = ""
448 self.opened = False 463 self.opened = False
449 self.subdirs = [] 464 self.subdirs = []
450 # record the project dir as a relative path (i.e. empty path) 465 # record the project dir as a relative path (i.e. empty path)
451 self.otherssubdirs = [] 466 self.otherssubdirs = []
452 self.vcs = None 467 self.vcs = None
453 self.vcsRequested = False 468 self.vcsRequested = False
454 self.dbgVirtualEnv = '' 469 self.dbgVirtualEnv = ""
455 self.dbgCmdline = '' 470 self.dbgCmdline = ""
456 self.dbgWd = '' 471 self.dbgWd = ""
457 self.dbgEnv = '' 472 self.dbgEnv = ""
458 self.dbgReportExceptions = True 473 self.dbgReportExceptions = True
459 self.dbgExcList = [] 474 self.dbgExcList = []
460 self.dbgExcIgnoreList = [] 475 self.dbgExcIgnoreList = []
461 self.dbgAutoClearShell = True 476 self.dbgAutoClearShell = True
462 self.dbgTracePython = False 477 self.dbgTracePython = False
465 self.dbgMultiprocessNoDebug = "" 480 self.dbgMultiprocessNoDebug = ""
466 self.dbgGlobalConfigOverride = { 481 self.dbgGlobalConfigOverride = {
467 "enable": False, 482 "enable": False,
468 "redirect": True, 483 "redirect": True,
469 } 484 }
470 485
471 self.pdata = { 486 self.pdata = {
472 "DESCRIPTION": "", 487 "DESCRIPTION": "",
473 "VERSION": "", 488 "VERSION": "",
474 "SOURCES": [], 489 "SOURCES": [],
475 "FORMS": [], 490 "FORMS": [],
483 "TRANSLATIONSBINPATH": "", 498 "TRANSLATIONSBINPATH": "",
484 "MAINSCRIPT": "", 499 "MAINSCRIPT": "",
485 "VCS": "None", 500 "VCS": "None",
486 "VCSOPTIONS": {}, 501 "VCSOPTIONS": {},
487 "VCSOTHERDATA": {}, 502 "VCSOTHERDATA": {},
488 "AUTHOR": '', 503 "AUTHOR": "",
489 "EMAIL": '', 504 "EMAIL": "",
490 "HASH": '', 505 "HASH": "",
491 "PROGLANGUAGE": "Python3", 506 "PROGLANGUAGE": "Python3",
492 "MIXEDLANGUAGE": False, 507 "MIXEDLANGUAGE": False,
493 "PROJECTTYPE": "PyQt5", 508 "PROJECTTYPE": "PyQt5",
494 "SPELLLANGUAGE": 509 "SPELLLANGUAGE": Preferences.getEditor("SpellCheckingDefaultLanguage"),
495 Preferences.getEditor("SpellCheckingDefaultLanguage"), 510 "SPELLWORDS": "",
496 "SPELLWORDS": '', 511 "SPELLEXCLUDES": "",
497 "SPELLEXCLUDES": '',
498 "FILETYPES": {}, 512 "FILETYPES": {},
499 "LEXERASSOCS": {}, 513 "LEXERASSOCS": {},
500 "PROJECTTYPESPECIFICDATA": {}, 514 "PROJECTTYPESPECIFICDATA": {},
501 "CHECKERSPARMS": {}, 515 "CHECKERSPARMS": {},
502 "PACKAGERSPARMS": {}, 516 "PACKAGERSPARMS": {},
519 "Package": "", 533 "Package": "",
520 "RcSuffix": "", 534 "RcSuffix": "",
521 "PackagesRoot": "", 535 "PackagesRoot": "",
522 }, 536 },
523 "RCCPARAMS": { 537 "RCCPARAMS": {
524 "CompressionThreshold": 70, # default value 538 "CompressionThreshold": 70, # default value
525 "CompressLevel": 0, # use zlib default 539 "CompressLevel": 0, # use zlib default
526 "CompressionDisable": False, 540 "CompressionDisable": False,
527 "PathPrefix": "", 541 "PathPrefix": "",
528 }, 542 },
529 "EOL": -1, 543 "EOL": -1,
530 "DOCSTRING": "", 544 "DOCSTRING": "",
531 "TESTING_FRAMEWORK": "", 545 "TESTING_FRAMEWORK": "",
532 "LICENSE": "", 546 "LICENSE": "",
533 } 547 }
534 548
535 self.__initDebugProperties() 549 self.__initDebugProperties()
536 550
537 self.pudata = { 551 self.pudata = {
538 "VCSOVERRIDE": "", 552 "VCSOVERRIDE": "",
539 "VCSSTATUSMONITORINTERVAL": 0, 553 "VCSSTATUSMONITORINTERVAL": 0,
540 } 554 }
541 555
542 self.vcs = self.initVCS() 556 self.vcs = self.initVCS()
543 557
544 def getData(self, category, key): 558 def getData(self, category, key):
545 """ 559 """
546 Public method to get data out of the project data store. 560 Public method to get data out of the project data store.
547 561
548 @param category category of the data to get (string, one of 562 @param category category of the data to get (string, one of
549 PROJECTTYPESPECIFICDATA, CHECKERSPARMS, PACKAGERSPARMS, 563 PROJECTTYPESPECIFICDATA, CHECKERSPARMS, PACKAGERSPARMS,
550 DOCUMENTATIONPARMS or OTHERTOOLSPARMS) 564 DOCUMENTATIONPARMS or OTHERTOOLSPARMS)
551 @param key key of the data entry to get (string). 565 @param key key of the data entry to get (string).
552 @return a copy of the requested data or None 566 @return a copy of the requested data or None
553 """ 567 """
554 # __IGNORE_WARNING_D202__ 568 # __IGNORE_WARNING_D202__
555 if ( 569 if (
556 category in ["PROJECTTYPESPECIFICDATA", "CHECKERSPARMS", 570 category
557 "PACKAGERSPARMS", "DOCUMENTATIONPARMS", 571 in [
558 "OTHERTOOLSPARMS"] and 572 "PROJECTTYPESPECIFICDATA",
559 key in self.pdata[category] 573 "CHECKERSPARMS",
574 "PACKAGERSPARMS",
575 "DOCUMENTATIONPARMS",
576 "OTHERTOOLSPARMS",
577 ]
578 and key in self.pdata[category]
560 ): 579 ):
561 return copy.deepcopy(self.pdata[category][key]) 580 return copy.deepcopy(self.pdata[category][key])
562 else: 581 else:
563 return None 582 return None
564 583
565 def setData(self, category, key, data): 584 def setData(self, category, key, data):
566 """ 585 """
567 Public method to store data in the project data store. 586 Public method to store data in the project data store.
568 587
569 @param category category of the data to get (string, one of 588 @param category category of the data to get (string, one of
570 PROJECTTYPESPECIFICDATA, CHECKERSPARMS, PACKAGERSPARMS, 589 PROJECTTYPESPECIFICDATA, CHECKERSPARMS, PACKAGERSPARMS,
571 DOCUMENTATIONPARMS or OTHERTOOLSPARMS) 590 DOCUMENTATIONPARMS or OTHERTOOLSPARMS)
572 @param key key of the data entry to get (string). 591 @param key key of the data entry to get (string).
573 @param data data to be stored 592 @param data data to be stored
574 @return flag indicating success (boolean) 593 @return flag indicating success (boolean)
575 """ 594 """
576 # __IGNORE_WARNING_D202__ 595 # __IGNORE_WARNING_D202__
577 if category not in ["PROJECTTYPESPECIFICDATA", "CHECKERSPARMS", 596 if category not in [
578 "PACKAGERSPARMS", "DOCUMENTATIONPARMS", 597 "PROJECTTYPESPECIFICDATA",
579 "OTHERTOOLSPARMS"]: 598 "CHECKERSPARMS",
599 "PACKAGERSPARMS",
600 "DOCUMENTATIONPARMS",
601 "OTHERTOOLSPARMS",
602 ]:
580 return False 603 return False
581 604
582 # test for changes of data and save them in the project 605 # test for changes of data and save them in the project
583 # 1. there were none, now there are 606 # 1. there were none, now there are
584 if key not in self.pdata[category] and len(data) > 0: 607 if key not in self.pdata[category] and len(data) > 0:
585 self.pdata[category][key] = copy.deepcopy(data) 608 self.pdata[category][key] = copy.deepcopy(data)
586 self.setDirty(True) 609 self.setDirty(True)
595 self.setDirty(True) 618 self.setDirty(True)
596 # 4. there were none and none are given 619 # 4. there were none and none are given
597 else: 620 else:
598 return False 621 return False
599 return True 622 return True
600 623
601 def initFileTypes(self): 624 def initFileTypes(self):
602 """ 625 """
603 Public method to initialize the filetype associations with default 626 Public method to initialize the filetype associations with default
604 values. 627 values.
605 """ 628 """
613 "*.epj": "OTHERS", 636 "*.epj": "OTHERS",
614 "GNUmakefile": "OTHERS", 637 "GNUmakefile": "OTHERS",
615 "makefile": "OTHERS", 638 "makefile": "OTHERS",
616 "Makefile": "OTHERS", 639 "Makefile": "OTHERS",
617 } 640 }
618 641
619 # Sources 642 # Sources
620 sourceKey = ( 643 sourceKey = (
621 "Mixed" 644 "Mixed" if self.pdata["MIXEDLANGUAGE"] else self.pdata["PROGLANGUAGE"]
622 if self.pdata["MIXEDLANGUAGE"] else
623 self.pdata["PROGLANGUAGE"]
624 ) 645 )
625 for ext in self.__sourceExtensions(sourceKey): 646 for ext in self.__sourceExtensions(sourceKey):
626 self.pdata["FILETYPES"]["*{0}".format(ext)] = "SOURCES" 647 self.pdata["FILETYPES"]["*{0}".format(ext)] = "SOURCES"
627 648
628 # IDL interfaces 649 # IDL interfaces
629 self.pdata["FILETYPES"]["*.idl"] = "INTERFACES" 650 self.pdata["FILETYPES"]["*.idl"] = "INTERFACES"
630 651
631 # Protobuf Files 652 # Protobuf Files
632 self.pdata["FILETYPES"]["*.proto"] = "PROTOCOLS" 653 self.pdata["FILETYPES"]["*.proto"] = "PROTOCOLS"
633 654
634 # Forms 655 # Forms
635 if self.pdata["PROJECTTYPE"] in ["E7Plugin", 656 if self.pdata["PROJECTTYPE"] in [
636 "PyQt5", 657 "E7Plugin",
637 "PyQt6", 658 "PyQt5",
638 "PySide2", 659 "PyQt6",
639 "PySide6"]: 660 "PySide2",
661 "PySide6",
662 ]:
640 self.pdata["FILETYPES"]["*.ui"] = "FORMS" 663 self.pdata["FILETYPES"]["*.ui"] = "FORMS"
641 664
642 # Resources 665 # Resources
643 if self.pdata["PROJECTTYPE"] in ["PyQt5", "PyQt5C", 666 if self.pdata["PROJECTTYPE"] in [
644 "PySide2", "PySide2C", 667 "PyQt5",
645 "PySide6", "PySide6C"]: 668 "PyQt5C",
669 "PySide2",
670 "PySide2C",
671 "PySide6",
672 "PySide6C",
673 ]:
646 self.pdata["FILETYPES"]["*.qrc"] = "RESOURCES" 674 self.pdata["FILETYPES"]["*.qrc"] = "RESOURCES"
647 675
648 # Translations 676 # Translations
649 if self.pdata["PROJECTTYPE"] in ["E7Plugin", 677 if self.pdata["PROJECTTYPE"] in [
650 "PyQt5", "PyQt5C", 678 "E7Plugin",
651 "PyQt6", "PyQt6C", 679 "PyQt5",
652 "PySide2", "PySide2C", 680 "PyQt5C",
653 "PySide6", "PySide6C"]: 681 "PyQt6",
682 "PyQt6C",
683 "PySide2",
684 "PySide2C",
685 "PySide6",
686 "PySide6C",
687 ]:
654 self.pdata["FILETYPES"]["*.ts"] = "TRANSLATIONS" 688 self.pdata["FILETYPES"]["*.ts"] = "TRANSLATIONS"
655 self.pdata["FILETYPES"]["*.qm"] = "TRANSLATIONS" 689 self.pdata["FILETYPES"]["*.qm"] = "TRANSLATIONS"
656 690
657 # Project type specific ones 691 # Project type specific ones
658 with contextlib.suppress(KeyError): 692 with contextlib.suppress(KeyError):
659 if self.__fileTypeCallbacks[ 693 if self.__fileTypeCallbacks[self.pdata["PROJECTTYPE"]] is not None:
660 self.pdata["PROJECTTYPE"]] is not None:
661 ftypes = self.__fileTypeCallbacks[self.pdata["PROJECTTYPE"]]() 694 ftypes = self.__fileTypeCallbacks[self.pdata["PROJECTTYPE"]]()
662 self.pdata["FILETYPES"].update(ftypes) 695 self.pdata["FILETYPES"].update(ftypes)
663 696
664 self.setDirty(True) 697 self.setDirty(True)
665 698
666 def updateFileTypes(self): 699 def updateFileTypes(self):
667 """ 700 """
668 Public method to update the filetype associations with new default 701 Public method to update the filetype associations with new default
669 values. 702 values.
670 """ 703 """
671 if self.pdata["PROJECTTYPE"] in ["E7Plugin", 704 if self.pdata["PROJECTTYPE"] in [
672 "PyQt5", "PyQt5C", 705 "E7Plugin",
673 "PyQt6", "PyQt6C", 706 "PyQt5",
674 "PySide2", "PySide2C", 707 "PyQt5C",
675 "PySide6", "PySide6C"]: 708 "PyQt6",
709 "PyQt6C",
710 "PySide2",
711 "PySide2C",
712 "PySide6",
713 "PySide6C",
714 ]:
676 if "*.ts" not in self.pdata["FILETYPES"]: 715 if "*.ts" not in self.pdata["FILETYPES"]:
677 self.pdata["FILETYPES"]["*.ts"] = "TRANSLATIONS" 716 self.pdata["FILETYPES"]["*.ts"] = "TRANSLATIONS"
678 if "*.qm" not in self.pdata["FILETYPES"]: 717 if "*.qm" not in self.pdata["FILETYPES"]:
679 self.pdata["FILETYPES"]["*.qm"] = "TRANSLATIONS" 718 self.pdata["FILETYPES"]["*.qm"] = "TRANSLATIONS"
680 with contextlib.suppress(KeyError): 719 with contextlib.suppress(KeyError):
681 if self.__fileTypeCallbacks[ 720 if self.__fileTypeCallbacks[self.pdata["PROJECTTYPE"]] is not None:
682 self.pdata["PROJECTTYPE"]] is not None:
683 ftypes = self.__fileTypeCallbacks[self.pdata["PROJECTTYPE"]]() 721 ftypes = self.__fileTypeCallbacks[self.pdata["PROJECTTYPE"]]()
684 for pattern, ftype in list(ftypes.items()): 722 for pattern, ftype in list(ftypes.items()):
685 if pattern not in self.pdata["FILETYPES"]: 723 if pattern not in self.pdata["FILETYPES"]:
686 self.pdata["FILETYPES"][pattern] = ftype 724 self.pdata["FILETYPES"][pattern] = ftype
687 self.setDirty(True) 725 self.setDirty(True)
688 726
689 def __loadRecent(self): 727 def __loadRecent(self):
690 """ 728 """
691 Private method to load the recently opened project filenames. 729 Private method to load the recently opened project filenames.
692 """ 730 """
693 self.recent = [] 731 self.recent = []
695 rp = Preferences.Prefs.rsettings.value(recentNameProject) 733 rp = Preferences.Prefs.rsettings.value(recentNameProject)
696 if rp is not None: 734 if rp is not None:
697 for f in rp: 735 for f in rp:
698 if pathlib.Path(f).exists(): 736 if pathlib.Path(f).exists():
699 self.recent.append(f) 737 self.recent.append(f)
700 738
701 def __saveRecent(self): 739 def __saveRecent(self):
702 """ 740 """
703 Private method to save the list of recently opened filenames. 741 Private method to save the list of recently opened filenames.
704 """ 742 """
705 Preferences.Prefs.rsettings.setValue(recentNameProject, self.recent) 743 Preferences.Prefs.rsettings.setValue(recentNameProject, self.recent)
706 Preferences.Prefs.rsettings.sync() 744 Preferences.Prefs.rsettings.sync()
707 745
708 def getMostRecent(self): 746 def getMostRecent(self):
709 """ 747 """
710 Public method to get the most recently opened project. 748 Public method to get the most recently opened project.
711 749
712 @return path of the most recently opened project (string) 750 @return path of the most recently opened project (string)
713 """ 751 """
714 if len(self.recent): 752 if len(self.recent):
715 return self.recent[0] 753 return self.recent[0]
716 else: 754 else:
717 return None 755 return None
718 756
719 def getModel(self): 757 def getModel(self):
720 """ 758 """
721 Public method to get a reference to the project browser model. 759 Public method to get a reference to the project browser model.
722 760
723 @return reference to the project browser model (ProjectBrowserModel) 761 @return reference to the project browser model (ProjectBrowserModel)
724 """ 762 """
725 return self.__model 763 return self.__model
726 764
727 def startFileSystemMonitoring(self): 765 def startFileSystemMonitoring(self):
728 """ 766 """
729 Public method to (re)start monitoring the project file system. 767 Public method to (re)start monitoring the project file system.
730 """ 768 """
731 self.__model.startFileSystemMonitoring() 769 self.__model.startFileSystemMonitoring()
732 770
733 def stopFileSystemMonitoring(self): 771 def stopFileSystemMonitoring(self):
734 """ 772 """
735 Public method to stop monitoring the project file system. 773 Public method to stop monitoring the project file system.
736 """ 774 """
737 self.__model.stopFileSystemMonitoring() 775 self.__model.stopFileSystemMonitoring()
738 776
739 def getVcs(self): 777 def getVcs(self):
740 """ 778 """
741 Public method to get a reference to the VCS object. 779 Public method to get a reference to the VCS object.
742 780
743 @return reference to the VCS object 781 @return reference to the VCS object
744 """ 782 """
745 return self.vcs 783 return self.vcs
746 784
747 def handlePreferencesChanged(self): 785 def handlePreferencesChanged(self):
748 """ 786 """
749 Public slot used to handle the preferencesChanged signal. 787 Public slot used to handle the preferencesChanged signal.
750 """ 788 """
751 if self.pudata["VCSSTATUSMONITORINTERVAL"]: 789 if self.pudata["VCSSTATUSMONITORINTERVAL"]:
752 self.setStatusMonitorInterval( 790 self.setStatusMonitorInterval(self.pudata["VCSSTATUSMONITORINTERVAL"])
753 self.pudata["VCSSTATUSMONITORINTERVAL"])
754 else: 791 else:
755 self.setStatusMonitorInterval( 792 self.setStatusMonitorInterval(Preferences.getVCS("StatusMonitorInterval"))
756 Preferences.getVCS("StatusMonitorInterval")) 793
757
758 self.__model.preferencesChanged() 794 self.__model.preferencesChanged()
759 795
760 def setDirty(self, dirty): 796 def setDirty(self, dirty):
761 """ 797 """
762 Public method to set the dirty state. 798 Public method to set the dirty state.
763 799
764 It emits the signal dirty(bool). 800 It emits the signal dirty(bool).
765 801
766 @param dirty dirty state 802 @param dirty dirty state
767 @type bool 803 @type bool
768 """ 804 """
769 self.__dirty = dirty 805 self.__dirty = dirty
770 self.saveAct.setEnabled(dirty) 806 self.saveAct.setEnabled(dirty)
771 self.dirty.emit(dirty) 807 self.dirty.emit(dirty)
772 if self.__dirty: 808 if self.__dirty:
773 self.projectChanged.emit() 809 self.projectChanged.emit()
774 810
775 def isDirty(self): 811 def isDirty(self):
776 """ 812 """
777 Public method to return the dirty state. 813 Public method to return the dirty state.
778 814
779 @return dirty state (boolean) 815 @return dirty state (boolean)
780 """ 816 """
781 return self.__dirty 817 return self.__dirty
782 818
783 def isOpen(self): 819 def isOpen(self):
784 """ 820 """
785 Public method to return the opened state. 821 Public method to return the opened state.
786 822
787 @return open state (boolean) 823 @return open state (boolean)
788 """ 824 """
789 return self.opened 825 return self.opened
790 826
791 def __checkFilesExist(self, index): 827 def __checkFilesExist(self, index):
792 """ 828 """
793 Private method to check, if the files in a list exist. 829 Private method to check, if the files in a list exist.
794 830
795 The files in the indicated list are checked for existance in the 831 The files in the indicated list are checked for existance in the
796 filesystem. Non existant files are removed from the list and the 832 filesystem. Non existant files are removed from the list and the
797 dirty state of the project is changed accordingly. 833 dirty state of the project is changed accordingly.
798 834
799 @param index key of the list to be checked (string) 835 @param index key of the list to be checked (string)
800 """ 836 """
801 removed = False 837 removed = False
802 removelist = [] 838 removelist = []
803 for file in self.pdata[index]: 839 for file in self.pdata[index]:
804 if not os.path.exists(os.path.join(self.ppath, file)): 840 if not os.path.exists(os.path.join(self.ppath, file)):
805 removelist.append(file) 841 removelist.append(file)
806 removed = True 842 removed = True
807 843
808 if removed: 844 if removed:
809 for file in removelist: 845 for file in removelist:
810 self.pdata[index].remove(file) 846 self.pdata[index].remove(file)
811 self.setDirty(True) 847 self.setDirty(True)
812 848
813 def __readProject(self, fn): 849 def __readProject(self, fn):
814 """ 850 """
815 Private method to read in a project (.epj or .e4p) file. 851 Private method to read in a project (.epj or .e4p) file.
816 852
817 @param fn filename of the project file to be read (string) 853 @param fn filename of the project file to be read (string)
818 @return flag indicating success 854 @return flag indicating success
819 """ 855 """
820 if os.path.splitext(fn)[1] == ".epj": 856 if os.path.splitext(fn)[1] == ".epj":
821 # new JSON based format 857 # new JSON based format
824 else: 860 else:
825 # old XML based format 861 # old XML based format
826 f = QFile(fn) 862 f = QFile(fn)
827 if f.open(QIODevice.OpenModeFlag.ReadOnly): 863 if f.open(QIODevice.OpenModeFlag.ReadOnly):
828 from EricXML.ProjectReader import ProjectReader 864 from EricXML.ProjectReader import ProjectReader
865
829 reader = ProjectReader(f, self) 866 reader = ProjectReader(f, self)
830 reader.readXML() 867 reader.readXML()
831 res = not reader.hasError() 868 res = not reader.hasError()
832 f.close() 869 f.close()
833 870
834 # create hash value, if it doesn't have one 871 # create hash value, if it doesn't have one
835 if reader.version.startswith("5.") and not self.pdata["HASH"]: 872 if reader.version.startswith("5.") and not self.pdata["HASH"]:
836 hashStr = str(QCryptographicHash.hash( 873 hashStr = str(
837 QByteArray(self.ppath.encode("utf-8")), 874 QCryptographicHash.hash(
838 QCryptographicHash.Algorithm.Sha1).toHex(), 875 QByteArray(self.ppath.encode("utf-8")),
839 encoding="utf-8") 876 QCryptographicHash.Algorithm.Sha1,
877 ).toHex(),
878 encoding="utf-8",
879 )
840 self.pdata["HASH"] = hashStr 880 self.pdata["HASH"] = hashStr
841 self.setDirty(True) 881 self.setDirty(True)
842 else: 882 else:
843 EricMessageBox.critical( 883 EricMessageBox.critical(
844 self.ui, 884 self.ui,
845 self.tr("Read Project File"), 885 self.tr("Read Project File"),
846 self.tr( 886 self.tr(
847 "<p>The project file <b>{0}</b> could not be read." 887 "<p>The project file <b>{0}</b> could not be read." "</p>"
848 "</p>") 888 ).format(fn),
849 .format(fn)) 889 )
850 res = False 890 res = False
851 891
852 if res: 892 if res:
853 self.pfile = os.path.abspath(fn) 893 self.pfile = os.path.abspath(fn)
854 self.ppath = os.path.abspath(os.path.dirname(fn)) 894 self.ppath = os.path.abspath(os.path.dirname(fn))
855 895
856 # insert filename into list of recently opened projects 896 # insert filename into list of recently opened projects
857 self.__syncRecent() 897 self.__syncRecent()
858 898
859 if self.pdata["TRANSLATIONPATTERN"]: 899 if self.pdata["TRANSLATIONPATTERN"]:
860 self.translationsRoot = self.pdata["TRANSLATIONPATTERN"].split( 900 self.translationsRoot = self.pdata["TRANSLATIONPATTERN"].split(
861 "%language%")[0] 901 "%language%"
902 )[0]
862 elif self.pdata["MAINSCRIPT"]: 903 elif self.pdata["MAINSCRIPT"]:
863 self.translationsRoot = os.path.splitext( 904 self.translationsRoot = os.path.splitext(self.pdata["MAINSCRIPT"])[0]
864 self.pdata["MAINSCRIPT"])[0]
865 if os.path.isdir(os.path.join(self.ppath, self.translationsRoot)): 905 if os.path.isdir(os.path.join(self.ppath, self.translationsRoot)):
866 dn = self.translationsRoot 906 dn = self.translationsRoot
867 else: 907 else:
868 dn = os.path.dirname(self.translationsRoot) 908 dn = os.path.dirname(self.translationsRoot)
869 if dn not in self.subdirs: 909 if dn not in self.subdirs:
870 self.subdirs.append(dn) 910 self.subdirs.append(dn)
871 911
872 self.name = os.path.splitext(os.path.basename(fn))[0] 912 self.name = os.path.splitext(os.path.basename(fn))[0]
873 913
874 # check, if the files of the project still exist in the 914 # check, if the files of the project still exist in the
875 # project directory 915 # project directory
876 self.__checkFilesExist("SOURCES") 916 self.__checkFilesExist("SOURCES")
877 self.__checkFilesExist("FORMS") 917 self.__checkFilesExist("FORMS")
878 self.__checkFilesExist("INTERFACES") 918 self.__checkFilesExist("INTERFACES")
879 self.__checkFilesExist("PROTOCOLS") 919 self.__checkFilesExist("PROTOCOLS")
880 self.__checkFilesExist("TRANSLATIONS") 920 self.__checkFilesExist("TRANSLATIONS")
881 self.__checkFilesExist("RESOURCES") 921 self.__checkFilesExist("RESOURCES")
882 self.__checkFilesExist("OTHERS") 922 self.__checkFilesExist("OTHERS")
883 923
884 # get the names of subdirectories the files are stored in 924 # get the names of subdirectories the files are stored in
885 for fn in ( 925 for fn in (
886 self.pdata["SOURCES"] + 926 self.pdata["SOURCES"]
887 self.pdata["FORMS"] + 927 + self.pdata["FORMS"]
888 self.pdata["INTERFACES"] + 928 + self.pdata["INTERFACES"]
889 self.pdata["PROTOCOLS"] + 929 + self.pdata["PROTOCOLS"]
890 self.pdata["RESOURCES"] + 930 + self.pdata["RESOURCES"]
891 self.pdata["TRANSLATIONS"] 931 + self.pdata["TRANSLATIONS"]
892 ): 932 ):
893 dn = os.path.dirname(fn) 933 dn = os.path.dirname(fn)
894 if dn not in self.subdirs: 934 if dn not in self.subdirs:
895 self.subdirs.append(dn) 935 self.subdirs.append(dn)
896 936
897 # get the names of other subdirectories 937 # get the names of other subdirectories
898 for fn in self.pdata["OTHERS"]: 938 for fn in self.pdata["OTHERS"]:
899 dn = os.path.dirname(fn) 939 dn = os.path.dirname(fn)
900 if dn not in self.otherssubdirs: 940 if dn not in self.otherssubdirs:
901 self.otherssubdirs.append(dn) 941 self.otherssubdirs.append(dn)
902 942
903 return res 943 return res
904 944
905 def __writeProject(self, fn=None): 945 def __writeProject(self, fn=None):
906 """ 946 """
907 Private method to save the project infos to a project file. 947 Private method to save the project infos to a project file.
908 948
909 @param fn optional filename of the project file to be written (string). 949 @param fn optional filename of the project file to be written (string).
910 If fn is None, the filename stored in the project object 950 If fn is None, the filename stored in the project object
911 is used. This is the 'save' action. If fn is given, this filename 951 is used. This is the 'save' action. If fn is given, this filename
912 is used instead of the one in the project object. This is the 952 is used instead of the one in the project object. This is the
913 'save as' action. 953 'save as' action.
914 @return flag indicating success 954 @return flag indicating success
915 """ 955 """
916 if self.vcs is not None: 956 if self.vcs is not None:
917 self.pdata["VCSOPTIONS"] = copy.deepcopy(self.vcs.vcsGetOptions()) 957 self.pdata["VCSOPTIONS"] = copy.deepcopy(self.vcs.vcsGetOptions())
918 self.pdata["VCSOTHERDATA"] = copy.deepcopy( 958 self.pdata["VCSOTHERDATA"] = copy.deepcopy(self.vcs.vcsGetOtherData())
919 self.vcs.vcsGetOtherData()) 959
920
921 if not self.pdata["HASH"]: 960 if not self.pdata["HASH"]:
922 hashStr = str(QCryptographicHash.hash( 961 hashStr = str(
923 QByteArray(self.ppath.encode("utf-8")), 962 QCryptographicHash.hash(
924 QCryptographicHash.Algorithm.Sha1).toHex(), 963 QByteArray(self.ppath.encode("utf-8")),
925 encoding="utf-8") 964 QCryptographicHash.Algorithm.Sha1,
965 ).toHex(),
966 encoding="utf-8",
967 )
926 self.pdata["HASH"] = hashStr 968 self.pdata["HASH"] = hashStr
927 969
928 if fn is None: 970 if fn is None:
929 fn = self.pfile 971 fn = self.pfile
930 972
931 with EricOverrideCursor(): 973 with EricOverrideCursor():
932 res = self.__projectFile.writeFile(fn) 974 res = self.__projectFile.writeFile(fn)
933 975
934 if res: 976 if res:
935 self.pfile = os.path.abspath(fn) 977 self.pfile = os.path.abspath(fn)
936 self.ppath = os.path.abspath(os.path.dirname(fn)) 978 self.ppath = os.path.abspath(os.path.dirname(fn))
937 self.name = os.path.splitext(os.path.basename(fn))[0] 979 self.name = os.path.splitext(os.path.basename(fn))[0]
938 self.setDirty(False) 980 self.setDirty(False)
939 981
940 # insert filename into list of recently opened projects 982 # insert filename into list of recently opened projects
941 self.__syncRecent() 983 self.__syncRecent()
942 984
943 return res 985 return res
944 986
945 def __readUserProperties(self): 987 def __readUserProperties(self):
946 """ 988 """
947 Private method to read in the user specific project file (.eqj or 989 Private method to read in the user specific project file (.eqj or
948 .e4q). 990 .e4q).
949 """ 991 """
950 if self.pfile is None: 992 if self.pfile is None:
951 return 993 return
952 994
953 fn1, ext = os.path.splitext(os.path.basename(self.pfile)) 995 fn1, ext = os.path.splitext(os.path.basename(self.pfile))
954 fn = os.path.join(self.getProjectManagementDir(), 996 fn = os.path.join(self.getProjectManagementDir(), "{0}.eqj".format(fn1))
955 '{0}.eqj'.format(fn1))
956 if os.path.exists(fn): 997 if os.path.exists(fn):
957 # try the new JSON based format first 998 # try the new JSON based format first
958 self.__userProjectFile.readFile(fn) 999 self.__userProjectFile.readFile(fn)
959 else: 1000 else:
960 # try the old XML based format second 1001 # try the old XML based format second
961 fn = os.path.join(self.getProjectManagementDir(), 1002 fn = os.path.join(self.getProjectManagementDir(), "{0}.e4q".format(fn1))
962 '{0}.e4q'.format(fn1))
963 if os.path.exists(fn): 1003 if os.path.exists(fn):
964 f = QFile(fn) 1004 f = QFile(fn)
965 if f.open(QIODevice.OpenModeFlag.ReadOnly): 1005 if f.open(QIODevice.OpenModeFlag.ReadOnly):
966 from EricXML.UserProjectReader import UserProjectReader 1006 from EricXML.UserProjectReader import UserProjectReader
1007
967 reader = UserProjectReader(f, self) 1008 reader = UserProjectReader(f, self)
968 reader.readXML() 1009 reader.readXML()
969 f.close() 1010 f.close()
970 else: 1011 else:
971 EricMessageBox.critical( 1012 EricMessageBox.critical(
972 self.ui, 1013 self.ui,
973 self.tr("Read User Project Properties"), 1014 self.tr("Read User Project Properties"),
974 self.tr( 1015 self.tr(
975 "<p>The user specific project properties file" 1016 "<p>The user specific project properties file"
976 " <b>{0}</b> could not be read.</p>").format(fn)) 1017 " <b>{0}</b> could not be read.</p>"
977 1018 ).format(fn),
1019 )
1020
978 def __writeUserProperties(self): 1021 def __writeUserProperties(self):
979 """ 1022 """
980 Private method to write the user specific project data to a JSON file. 1023 Private method to write the user specific project data to a JSON file.
981 """ 1024 """
982 if self.pfile is None: 1025 if self.pfile is None:
983 return 1026 return
984 1027
985 fn, ext = os.path.splitext(os.path.basename(self.pfile)) 1028 fn, ext = os.path.splitext(os.path.basename(self.pfile))
986 fn = os.path.join(self.getProjectManagementDir(), '{0}.eqj'.format(fn)) 1029 fn = os.path.join(self.getProjectManagementDir(), "{0}.eqj".format(fn))
987 1030
988 with EricOverrideCursor(): 1031 with EricOverrideCursor():
989 self.__userProjectFile.writeFile(fn) 1032 self.__userProjectFile.writeFile(fn)
990 1033
991 def __showContextMenuSession(self): 1034 def __showContextMenuSession(self):
992 """ 1035 """
993 Private slot called before the Session menu is shown. 1036 Private slot called before the Session menu is shown.
994 """ 1037 """
995 enable = True 1038 enable = True
996 if self.pfile is None: 1039 if self.pfile is None:
997 enable = False 1040 enable = False
998 else: 1041 else:
999 fn, ext = os.path.splitext(os.path.basename(self.pfile)) 1042 fn, ext = os.path.splitext(os.path.basename(self.pfile))
1000 fn_new = os.path.join(self.getProjectManagementDir(), 1043 fn_new = os.path.join(self.getProjectManagementDir(), "{0}.esj".format(fn))
1001 '{0}.esj'.format(fn)) 1044 fn_old = os.path.join(self.getProjectManagementDir(), "{0}.e5s".format(fn))
1002 fn_old = os.path.join(self.getProjectManagementDir(),
1003 '{0}.e5s'.format(fn))
1004 enable = os.path.exists(fn_new) or os.path.exists(fn_old) 1045 enable = os.path.exists(fn_new) or os.path.exists(fn_old)
1005 self.sessActGrp.findChild( 1046 self.sessActGrp.findChild(QAction, "project_load_session").setEnabled(enable)
1006 QAction, "project_load_session").setEnabled(enable) 1047 self.sessActGrp.findChild(QAction, "project_delete_session").setEnabled(enable)
1007 self.sessActGrp.findChild( 1048
1008 QAction, "project_delete_session").setEnabled(enable)
1009
1010 @pyqtSlot() 1049 @pyqtSlot()
1011 def __readSession(self, quiet=False, indicator=""): 1050 def __readSession(self, quiet=False, indicator=""):
1012 """ 1051 """
1013 Private method to read in the project session file (.esj or .e5s). 1052 Private method to read in the project session file (.esj or .e5s).
1014 1053
1015 @param quiet flag indicating quiet operations. 1054 @param quiet flag indicating quiet operations.
1016 If this flag is true, no errors are reported. 1055 If this flag is true, no errors are reported.
1017 @param indicator indicator string (string) 1056 @param indicator indicator string (string)
1018 """ 1057 """
1019 if self.pfile is None: 1058 if self.pfile is None:
1020 if not quiet: 1059 if not quiet:
1021 EricMessageBox.critical( 1060 EricMessageBox.critical(
1022 self.ui, 1061 self.ui,
1023 self.tr("Read Project Session"), 1062 self.tr("Read Project Session"),
1024 self.tr("Please save the project first.")) 1063 self.tr("Please save the project first."),
1064 )
1025 return 1065 return
1026 1066
1027 fn1, ext = os.path.splitext(os.path.basename(self.pfile)) 1067 fn1, ext = os.path.splitext(os.path.basename(self.pfile))
1028 fn = os.path.join(self.getProjectManagementDir(), 1068 fn = os.path.join(
1029 '{0}{1}.esj'.format(fn1, indicator)) 1069 self.getProjectManagementDir(), "{0}{1}.esj".format(fn1, indicator)
1070 )
1030 if os.path.exists(fn): 1071 if os.path.exists(fn):
1031 # try the new JSON based format first 1072 # try the new JSON based format first
1032 self.__sessionFile.readFile(fn) 1073 self.__sessionFile.readFile(fn)
1033 else: 1074 else:
1034 # try the old XML based format second 1075 # try the old XML based format second
1035 fn = os.path.join(self.getProjectManagementDir(), 1076 fn = os.path.join(
1036 '{0}{1}.e5s'.format(fn1, indicator)) 1077 self.getProjectManagementDir(), "{0}{1}.e5s".format(fn1, indicator)
1078 )
1037 if os.path.exists(fn): 1079 if os.path.exists(fn):
1038 f = QFile(fn) 1080 f = QFile(fn)
1039 if f.open(QIODevice.OpenModeFlag.ReadOnly): 1081 if f.open(QIODevice.OpenModeFlag.ReadOnly):
1040 from EricXML.SessionReader import SessionReader 1082 from EricXML.SessionReader import SessionReader
1083
1041 reader = SessionReader(f, False) 1084 reader = SessionReader(f, False)
1042 reader.readXML(quiet=quiet) 1085 reader.readXML(quiet=quiet)
1043 f.close() 1086 f.close()
1044 else: 1087 else:
1045 if not quiet: 1088 if not quiet:
1046 EricMessageBox.critical( 1089 EricMessageBox.critical(
1047 self.ui, 1090 self.ui,
1048 self.tr("Read project session"), 1091 self.tr("Read project session"),
1049 self.tr( 1092 self.tr(
1050 "<p>The project session file <b>{0}</b> could" 1093 "<p>The project session file <b>{0}</b> could"
1051 " not be read.</p>").format(fn)) 1094 " not be read.</p>"
1052 1095 ).format(fn),
1096 )
1097
1053 @pyqtSlot() 1098 @pyqtSlot()
1054 def __writeSession(self, quiet=False, indicator=""): 1099 def __writeSession(self, quiet=False, indicator=""):
1055 """ 1100 """
1056 Private method to write the session data to an XML file (.esj). 1101 Private method to write the session data to an XML file (.esj).
1057 1102
1058 @param quiet flag indicating quiet operations. 1103 @param quiet flag indicating quiet operations.
1059 If this flag is true, no errors are reported. 1104 If this flag is true, no errors are reported.
1060 @param indicator indicator string (string) 1105 @param indicator indicator string (string)
1061 """ 1106 """
1062 if self.pfile is None: 1107 if self.pfile is None:
1063 if not quiet: 1108 if not quiet:
1064 EricMessageBox.critical( 1109 EricMessageBox.critical(
1065 self.ui, 1110 self.ui,
1066 self.tr("Save Project Session"), 1111 self.tr("Save Project Session"),
1067 self.tr("Please save the project first.")) 1112 self.tr("Please save the project first."),
1113 )
1068 return 1114 return
1069 1115
1070 fn, ext = os.path.splitext(os.path.basename(self.pfile)) 1116 fn, ext = os.path.splitext(os.path.basename(self.pfile))
1071 fn = os.path.join(self.getProjectManagementDir(), 1117 fn = os.path.join(
1072 '{0}{1}.esj'.format(fn, indicator)) 1118 self.getProjectManagementDir(), "{0}{1}.esj".format(fn, indicator)
1073 1119 )
1120
1074 self.__sessionFile.writeFile(fn) 1121 self.__sessionFile.writeFile(fn)
1075 1122
1076 def __deleteSession(self): 1123 def __deleteSession(self):
1077 """ 1124 """
1078 Private method to delete the session file. 1125 Private method to delete the session file.
1079 """ 1126 """
1080 if self.pfile is None: 1127 if self.pfile is None:
1081 EricMessageBox.critical( 1128 EricMessageBox.critical(
1082 self.ui, 1129 self.ui,
1083 self.tr("Delete Project Session"), 1130 self.tr("Delete Project Session"),
1084 self.tr("Please save the project first.")) 1131 self.tr("Please save the project first."),
1132 )
1085 return 1133 return
1086 1134
1087 fname, ext = os.path.splitext(os.path.basename(self.pfile)) 1135 fname, ext = os.path.splitext(os.path.basename(self.pfile))
1088 1136
1089 for ext in (".esj", ".e5s", ".e4s"): 1137 for ext in (".esj", ".e5s", ".e4s"):
1090 fn = os.path.join( 1138 fn = os.path.join(
1091 self.getProjectManagementDir(), "{0}{1}".format(fname, ext)) 1139 self.getProjectManagementDir(), "{0}{1}".format(fname, ext)
1140 )
1092 if os.path.exists(fn): 1141 if os.path.exists(fn):
1093 try: 1142 try:
1094 os.remove(fn) 1143 os.remove(fn)
1095 except OSError: 1144 except OSError:
1096 EricMessageBox.critical( 1145 EricMessageBox.critical(
1097 self.ui, 1146 self.ui,
1098 self.tr("Delete Project Session"), 1147 self.tr("Delete Project Session"),
1099 self.tr( 1148 self.tr(
1100 "<p>The project session file <b>{0}</b> could" 1149 "<p>The project session file <b>{0}</b> could"
1101 " not be deleted.</p>").format(fn)) 1150 " not be deleted.</p>"
1102 1151 ).format(fn),
1152 )
1153
1103 def __readTasks(self): 1154 def __readTasks(self):
1104 """ 1155 """
1105 Private method to read in the project tasks file (.etj or .e6t). 1156 Private method to read in the project tasks file (.etj or .e6t).
1106 """ 1157 """
1107 if self.pfile is None: 1158 if self.pfile is None:
1108 EricMessageBox.critical( 1159 EricMessageBox.critical(
1109 self.ui, 1160 self.ui,
1110 self.tr("Read Tasks"), 1161 self.tr("Read Tasks"),
1111 self.tr("Please save the project first.")) 1162 self.tr("Please save the project first."),
1163 )
1112 return 1164 return
1113 1165
1114 base, ext = os.path.splitext(os.path.basename(self.pfile)) 1166 base, ext = os.path.splitext(os.path.basename(self.pfile))
1115 fn = os.path.join(self.getProjectManagementDir(), 1167 fn = os.path.join(self.getProjectManagementDir(), "{0}.etj".format(base))
1116 '{0}.etj'.format(base))
1117 if os.path.exists(fn): 1168 if os.path.exists(fn):
1118 # try new style JSON file first 1169 # try new style JSON file first
1119 self.__tasksFile.readFile(fn) 1170 self.__tasksFile.readFile(fn)
1120 else: 1171 else:
1121 # try old style XML file second 1172 # try old style XML file second
1122 fn = os.path.join(self.getProjectManagementDir(), 1173 fn = os.path.join(self.getProjectManagementDir(), "{0}.e6t".format(base))
1123 '{0}.e6t'.format(base))
1124 if os.path.exists(fn): 1174 if os.path.exists(fn):
1125 f = QFile(fn) 1175 f = QFile(fn)
1126 if f.open(QIODevice.OpenModeFlag.ReadOnly): 1176 if f.open(QIODevice.OpenModeFlag.ReadOnly):
1127 from EricXML.TasksReader import TasksReader 1177 from EricXML.TasksReader import TasksReader
1178
1128 reader = TasksReader(f, True) 1179 reader = TasksReader(f, True)
1129 reader.readXML() 1180 reader.readXML()
1130 f.close() 1181 f.close()
1131 else: 1182 else:
1132 EricMessageBox.critical( 1183 EricMessageBox.critical(
1133 self.ui, 1184 self.ui,
1134 self.tr("Read Tasks"), 1185 self.tr("Read Tasks"),
1135 self.tr( 1186 self.tr(
1136 "<p>The tasks file <b>{0}</b> could not be read." 1187 "<p>The tasks file <b>{0}</b> could not be read." "</p>"
1137 "</p>") 1188 ).format(fn),
1138 .format(fn)) 1189 )
1139 1190
1140 def writeTasks(self): 1191 def writeTasks(self):
1141 """ 1192 """
1142 Public method to write the tasks data to a JSON file (.etj). 1193 Public method to write the tasks data to a JSON file (.etj).
1143 """ 1194 """
1144 if self.pfile is None: 1195 if self.pfile is None:
1145 return 1196 return
1146 1197
1147 fn, ext = os.path.splitext(os.path.basename(self.pfile)) 1198 fn, ext = os.path.splitext(os.path.basename(self.pfile))
1148 1199
1149 fn = os.path.join(self.getProjectManagementDir(), 1200 fn = os.path.join(self.getProjectManagementDir(), "{0}.etj".format(fn))
1150 '{0}.etj'.format(fn))
1151 self.__tasksFile.writeFile(fn) 1201 self.__tasksFile.writeFile(fn)
1152 1202
1153 def __showContextMenuDebugger(self): 1203 def __showContextMenuDebugger(self):
1154 """ 1204 """
1155 Private slot called before the Debugger menu is shown. 1205 Private slot called before the Debugger menu is shown.
1156 """ 1206 """
1157 enable = True 1207 enable = True
1158 if self.pfile is None: 1208 if self.pfile is None:
1159 enable = False 1209 enable = False
1160 else: 1210 else:
1161 fn, ext = os.path.splitext(os.path.basename(self.pfile)) 1211 fn, ext = os.path.splitext(os.path.basename(self.pfile))
1162 # try new style file first 1212 # try new style file first
1163 fn = os.path.join(self.getProjectManagementDir(), 1213 fn = os.path.join(self.getProjectManagementDir(), "{0}.edj".format(fn))
1164 '{0}.edj'.format(fn))
1165 if not os.path.exists(fn): 1214 if not os.path.exists(fn):
1166 # try old style file second 1215 # try old style file second
1167 fn = os.path.join(self.getProjectManagementDir(), 1216 fn = os.path.join(self.getProjectManagementDir(), "{0}.e4d".format(fn))
1168 '{0}.e4d'.format(fn))
1169 enable = os.path.exists(fn) 1217 enable = os.path.exists(fn)
1170 self.dbgActGrp.findChild( 1218 self.dbgActGrp.findChild(
1171 QAction, "project_debugger_properties_load").setEnabled(enable) 1219 QAction, "project_debugger_properties_load"
1220 ).setEnabled(enable)
1172 self.dbgActGrp.findChild( 1221 self.dbgActGrp.findChild(
1173 QAction, "project_debugger_properties_delete").setEnabled(enable) 1222 QAction, "project_debugger_properties_delete"
1174 1223 ).setEnabled(enable)
1224
1175 @pyqtSlot() 1225 @pyqtSlot()
1176 def __readDebugProperties(self, quiet=False): 1226 def __readDebugProperties(self, quiet=False):
1177 """ 1227 """
1178 Private method to read in the project debugger properties file 1228 Private method to read in the project debugger properties file
1179 (.edj or .e4d). 1229 (.edj or .e4d).
1180 1230
1181 @param quiet flag indicating quiet operations. 1231 @param quiet flag indicating quiet operations.
1182 If this flag is true, no errors are reported. 1232 If this flag is true, no errors are reported.
1183 """ 1233 """
1184 if self.pfile is None: 1234 if self.pfile is None:
1185 if not quiet: 1235 if not quiet:
1186 EricMessageBox.critical( 1236 EricMessageBox.critical(
1187 self.ui, 1237 self.ui,
1188 self.tr("Read Debugger Properties"), 1238 self.tr("Read Debugger Properties"),
1189 self.tr("Please save the project first.")) 1239 self.tr("Please save the project first."),
1240 )
1190 return 1241 return
1191 1242
1192 fn1, ext = os.path.splitext(os.path.basename(self.pfile)) 1243 fn1, ext = os.path.splitext(os.path.basename(self.pfile))
1193 fn = os.path.join(self.getProjectManagementDir(), 1244 fn = os.path.join(self.getProjectManagementDir(), "{0}.edj".format(fn1))
1194 '{0}.edj'.format(fn1))
1195 if os.path.exists(fn): 1245 if os.path.exists(fn):
1196 # try the new JSON based format first 1246 # try the new JSON based format first
1197 if self.__debuggerPropertiesFile.readFile(fn): 1247 if self.__debuggerPropertiesFile.readFile(fn):
1198 self.debugPropertiesLoaded = True 1248 self.debugPropertiesLoaded = True
1199 self.debugPropertiesChanged = False 1249 self.debugPropertiesChanged = False
1200 else: 1250 else:
1201 # try the old XML based format second 1251 # try the old XML based format second
1202 fn = os.path.join(self.getProjectManagementDir(), 1252 fn = os.path.join(self.getProjectManagementDir(), "{0}.e4d".format(fn1))
1203 '{0}.e4d'.format(fn1)) 1253
1204
1205 f = QFile(fn) 1254 f = QFile(fn)
1206 if f.open(QIODevice.OpenModeFlag.ReadOnly): 1255 if f.open(QIODevice.OpenModeFlag.ReadOnly):
1207 from EricXML.DebuggerPropertiesReader import ( 1256 from EricXML.DebuggerPropertiesReader import DebuggerPropertiesReader
1208 DebuggerPropertiesReader 1257
1209 )
1210 reader = DebuggerPropertiesReader(f, self) 1258 reader = DebuggerPropertiesReader(f, self)
1211 reader.readXML(quiet=quiet) 1259 reader.readXML(quiet=quiet)
1212 f.close() 1260 f.close()
1213 self.debugPropertiesLoaded = True 1261 self.debugPropertiesLoaded = True
1214 self.debugPropertiesChanged = False 1262 self.debugPropertiesChanged = False
1217 EricMessageBox.critical( 1265 EricMessageBox.critical(
1218 self.ui, 1266 self.ui,
1219 self.tr("Read Debugger Properties"), 1267 self.tr("Read Debugger Properties"),
1220 self.tr( 1268 self.tr(
1221 "<p>The project debugger properties file" 1269 "<p>The project debugger properties file"
1222 " <b>{0}</b> could not be read.</p>").format(fn)) 1270 " <b>{0}</b> could not be read.</p>"
1223 1271 ).format(fn),
1272 )
1273
1224 @pyqtSlot() 1274 @pyqtSlot()
1225 def __writeDebugProperties(self, quiet=False): 1275 def __writeDebugProperties(self, quiet=False):
1226 """ 1276 """
1227 Private method to write the project debugger properties file (.edj). 1277 Private method to write the project debugger properties file (.edj).
1228 1278
1229 @param quiet flag indicating quiet operations. 1279 @param quiet flag indicating quiet operations.
1230 If this flag is true, no errors are reported. 1280 If this flag is true, no errors are reported.
1231 """ 1281 """
1232 if self.pfile is None: 1282 if self.pfile is None:
1233 if not quiet: 1283 if not quiet:
1234 EricMessageBox.critical( 1284 EricMessageBox.critical(
1235 self.ui, 1285 self.ui,
1236 self.tr("Save Debugger Properties"), 1286 self.tr("Save Debugger Properties"),
1237 self.tr("Please save the project first.")) 1287 self.tr("Please save the project first."),
1288 )
1238 return 1289 return
1239 1290
1240 fn, ext = os.path.splitext(os.path.basename(self.pfile)) 1291 fn, ext = os.path.splitext(os.path.basename(self.pfile))
1241 fn = os.path.join(self.getProjectManagementDir(), '{0}.edj'.format(fn)) 1292 fn = os.path.join(self.getProjectManagementDir(), "{0}.edj".format(fn))
1242 1293
1243 with EricOverrideCursor(): 1294 with EricOverrideCursor():
1244 self.__debuggerPropertiesFile.writeFile(fn) 1295 self.__debuggerPropertiesFile.writeFile(fn)
1245 1296
1246 def __deleteDebugProperties(self): 1297 def __deleteDebugProperties(self):
1247 """ 1298 """
1248 Private method to delete the project debugger properties file 1299 Private method to delete the project debugger properties file
1249 (.edj or .e4d). 1300 (.edj or .e4d).
1250 """ 1301 """
1251 if self.pfile is None: 1302 if self.pfile is None:
1252 EricMessageBox.critical( 1303 EricMessageBox.critical(
1253 self.ui, 1304 self.ui,
1254 self.tr("Delete Debugger Properties"), 1305 self.tr("Delete Debugger Properties"),
1255 self.tr("Please save the project first.")) 1306 self.tr("Please save the project first."),
1307 )
1256 return 1308 return
1257 1309
1258 fname, ext = os.path.splitext(os.path.basename(self.pfile)) 1310 fname, ext = os.path.splitext(os.path.basename(self.pfile))
1259 1311
1260 for ext in (".edj", ".e4d"): 1312 for ext in (".edj", ".e4d"):
1261 fn = os.path.join(self.getProjectManagementDir(), 1313 fn = os.path.join(
1262 "{0}{1}".format(fname, ext)) 1314 self.getProjectManagementDir(), "{0}{1}".format(fname, ext)
1315 )
1263 if os.path.exists(fn): 1316 if os.path.exists(fn):
1264 try: 1317 try:
1265 os.remove(fn) 1318 os.remove(fn)
1266 except OSError: 1319 except OSError:
1267 EricMessageBox.critical( 1320 EricMessageBox.critical(
1268 self.ui, 1321 self.ui,
1269 self.tr("Delete Debugger Properties"), 1322 self.tr("Delete Debugger Properties"),
1270 self.tr( 1323 self.tr(
1271 "<p>The project debugger properties file" 1324 "<p>The project debugger properties file"
1272 " <b>{0}</b> could not be deleted.</p>") 1325 " <b>{0}</b> could not be deleted.</p>"
1273 .format(fn)) 1326 ).format(fn),
1274 1327 )
1328
1275 def __initDebugProperties(self): 1329 def __initDebugProperties(self):
1276 """ 1330 """
1277 Private method to initialize the debug properties. 1331 Private method to initialize the debug properties.
1278 """ 1332 """
1279 self.debugPropertiesLoaded = False 1333 self.debugPropertiesLoaded = False
1292 "CONSOLEDEBUGGER": False, 1346 "CONSOLEDEBUGGER": False,
1293 "CONSOLECOMMAND": "", 1347 "CONSOLECOMMAND": "",
1294 "REDIRECT": False, 1348 "REDIRECT": False,
1295 "NOENCODING": False, 1349 "NOENCODING": False,
1296 } 1350 }
1297 1351
1298 def isDebugPropertiesLoaded(self): 1352 def isDebugPropertiesLoaded(self):
1299 """ 1353 """
1300 Public method to return the status of the debug properties. 1354 Public method to return the status of the debug properties.
1301 1355
1302 @return load status of debug properties (boolean) 1356 @return load status of debug properties (boolean)
1303 """ 1357 """
1304 return self.debugPropertiesLoaded 1358 return self.debugPropertiesLoaded
1305 1359
1306 def __showDebugProperties(self): 1360 def __showDebugProperties(self):
1307 """ 1361 """
1308 Private slot to display the debugger properties dialog. 1362 Private slot to display the debugger properties dialog.
1309 """ 1363 """
1310 from .DebuggerPropertiesDialog import DebuggerPropertiesDialog 1364 from .DebuggerPropertiesDialog import DebuggerPropertiesDialog
1365
1311 dlg = DebuggerPropertiesDialog(self) 1366 dlg = DebuggerPropertiesDialog(self)
1312 if dlg.exec() == QDialog.DialogCode.Accepted: 1367 if dlg.exec() == QDialog.DialogCode.Accepted:
1313 dlg.storeData() 1368 dlg.storeData()
1314 1369
1315 def getDebugProperty(self, key): 1370 def getDebugProperty(self, key):
1316 """ 1371 """
1317 Public method to retrieve a debugger property. 1372 Public method to retrieve a debugger property.
1318 1373
1319 @param key key of the property (string) 1374 @param key key of the property (string)
1320 @return value of the property 1375 @return value of the property
1321 """ 1376 """
1322 if key == "INTERPRETER": 1377 if key == "INTERPRETER":
1323 return ( 1378 return (
1324 ericApp().getObject("VirtualEnvManager") 1379 ericApp()
1380 .getObject("VirtualEnvManager")
1325 .getVirtualenvInterpreter(self.debugProperties["VIRTUALENV"]) 1381 .getVirtualenvInterpreter(self.debugProperties["VIRTUALENV"])
1326 ) 1382 )
1327 else: 1383 else:
1328 return self.debugProperties[key] 1384 return self.debugProperties[key]
1329 1385
1330 def setDbgInfo(self, venvName, argv, wd, env, excReporting, excList, 1386 def setDbgInfo(
1331 excIgnoreList, autoClearShell, tracePython=None, 1387 self,
1332 autoContinue=None, enableMultiprocess=None, 1388 venvName,
1333 multiprocessNoDebug=None, configOverride=None): 1389 argv,
1390 wd,
1391 env,
1392 excReporting,
1393 excList,
1394 excIgnoreList,
1395 autoClearShell,
1396 tracePython=None,
1397 autoContinue=None,
1398 enableMultiprocess=None,
1399 multiprocessNoDebug=None,
1400 configOverride=None,
1401 ):
1334 """ 1402 """
1335 Public method to set the debugging information. 1403 Public method to set the debugging information.
1336 1404
1337 @param venvName name of the virtual environment used 1405 @param venvName name of the virtual environment used
1338 @type str 1406 @type str
1339 @param argv command line arguments to be used 1407 @param argv command line arguments to be used
1340 @type str 1408 @type str
1341 @param wd working directory 1409 @param wd working directory
1370 self.dbgVirtualEnv = venvName 1438 self.dbgVirtualEnv = venvName
1371 self.dbgCmdline = argv 1439 self.dbgCmdline = argv
1372 self.dbgWd = wd 1440 self.dbgWd = wd
1373 self.dbgEnv = env 1441 self.dbgEnv = env
1374 self.dbgReportExceptions = excReporting 1442 self.dbgReportExceptions = excReporting
1375 self.dbgExcList = excList[:] # keep a copy of the list 1443 self.dbgExcList = excList[:] # keep a copy of the list
1376 self.dbgExcIgnoreList = excIgnoreList[:] # keep a copy of the list 1444 self.dbgExcIgnoreList = excIgnoreList[:] # keep a copy of the list
1377 self.dbgAutoClearShell = autoClearShell 1445 self.dbgAutoClearShell = autoClearShell
1378 if tracePython is not None: 1446 if tracePython is not None:
1379 self.dbgTracePython = tracePython 1447 self.dbgTracePython = tracePython
1380 if autoContinue is not None: 1448 if autoContinue is not None:
1381 self.dbgAutoContinue = autoContinue 1449 self.dbgAutoContinue = autoContinue
1383 self.dbgEnableMultiprocess = enableMultiprocess 1451 self.dbgEnableMultiprocess = enableMultiprocess
1384 if multiprocessNoDebug is not None: 1452 if multiprocessNoDebug is not None:
1385 self.dbgMultiprocessNoDebug = multiprocessNoDebug 1453 self.dbgMultiprocessNoDebug = multiprocessNoDebug
1386 if configOverride is not None: 1454 if configOverride is not None:
1387 self.dbgGlobalConfigOverride = copy.deepcopy(configOverride) 1455 self.dbgGlobalConfigOverride = copy.deepcopy(configOverride)
1388 1456
1389 def getTranslationPattern(self): 1457 def getTranslationPattern(self):
1390 """ 1458 """
1391 Public method to get the translation pattern. 1459 Public method to get the translation pattern.
1392 1460
1393 @return translation pattern (string) 1461 @return translation pattern (string)
1394 """ 1462 """
1395 return self.pdata["TRANSLATIONPATTERN"] 1463 return self.pdata["TRANSLATIONPATTERN"]
1396 1464
1397 def setTranslationPattern(self, pattern): 1465 def setTranslationPattern(self, pattern):
1398 """ 1466 """
1399 Public method to set the translation pattern. 1467 Public method to set the translation pattern.
1400 1468
1401 @param pattern translation pattern 1469 @param pattern translation pattern
1402 @type str 1470 @type str
1403 """ 1471 """
1404 self.pdata["TRANSLATIONPATTERN"] = pattern 1472 self.pdata["TRANSLATIONPATTERN"] = pattern
1405 1473
1406 def addLanguage(self): 1474 def addLanguage(self):
1407 """ 1475 """
1408 Public slot used to add a language to the project. 1476 Public slot used to add a language to the project.
1409 """ 1477 """
1410 if not self.pdata["TRANSLATIONPATTERN"]: 1478 if not self.pdata["TRANSLATIONPATTERN"]:
1411 EricMessageBox.critical( 1479 EricMessageBox.critical(
1412 self.ui, 1480 self.ui,
1413 self.tr("Add Language"), 1481 self.tr("Add Language"),
1414 self.tr( 1482 self.tr("You have to specify a translation pattern first."),
1415 "You have to specify a translation pattern first.")) 1483 )
1416 return 1484 return
1417 1485
1418 from .AddLanguageDialog import AddLanguageDialog 1486 from .AddLanguageDialog import AddLanguageDialog
1487
1419 dlg = AddLanguageDialog(self.parent()) 1488 dlg = AddLanguageDialog(self.parent())
1420 if dlg.exec() == QDialog.DialogCode.Accepted: 1489 if dlg.exec() == QDialog.DialogCode.Accepted:
1421 lang = dlg.getSelectedLanguage() 1490 lang = dlg.getSelectedLanguage()
1422 if self.pdata["PROJECTTYPE"] in [ 1491 if self.pdata["PROJECTTYPE"] in [
1423 "PyQt5", "PyQt5C", "PyQt6", "PyQt6C", "E7Plugin", 1492 "PyQt5",
1424 "PySide2", "PySide2C", "PySide6", "PySide6C" 1493 "PyQt5C",
1494 "PyQt6",
1495 "PyQt6C",
1496 "E7Plugin",
1497 "PySide2",
1498 "PySide2C",
1499 "PySide6",
1500 "PySide6C",
1425 ]: 1501 ]:
1426 langFile = self.pdata["TRANSLATIONPATTERN"].replace( 1502 langFile = self.pdata["TRANSLATIONPATTERN"].replace("%language%", lang)
1427 "%language%", lang)
1428 self.appendFile(langFile) 1503 self.appendFile(langFile)
1429 self.projectLanguageAddedByCode.emit(lang) 1504 self.projectLanguageAddedByCode.emit(lang)
1430 1505
1431 def __binaryTranslationFile(self, langFile): 1506 def __binaryTranslationFile(self, langFile):
1432 """ 1507 """
1433 Private method to calculate the filename of the binary translations 1508 Private method to calculate the filename of the binary translations
1434 file given the name of the raw translations file. 1509 file given the name of the raw translations file.
1435 1510
1436 @param langFile name of the raw translations file (string) 1511 @param langFile name of the raw translations file (string)
1437 @return name of the binary translations file (string) 1512 @return name of the binary translations file (string)
1438 """ 1513 """
1439 qmFile = "" 1514 qmFile = ""
1440 try: 1515 try:
1441 if self.__binaryTranslationsCallbacks[ 1516 if (
1442 self.pdata["PROJECTTYPE"]] is not None: 1517 self.__binaryTranslationsCallbacks[self.pdata["PROJECTTYPE"]]
1443 qmFile = self.__binaryTranslationsCallbacks[ 1518 is not None
1444 self.pdata["PROJECTTYPE"]](langFile) 1519 ):
1520 qmFile = self.__binaryTranslationsCallbacks[self.pdata["PROJECTTYPE"]](
1521 langFile
1522 )
1445 except KeyError: 1523 except KeyError:
1446 qmFile = langFile.replace('.ts', '.qm') 1524 qmFile = langFile.replace(".ts", ".qm")
1447 if qmFile == langFile: 1525 if qmFile == langFile:
1448 qmFile = "" 1526 qmFile = ""
1449 return qmFile 1527 return qmFile
1450 1528
1451 def checkLanguageFiles(self): 1529 def checkLanguageFiles(self):
1452 """ 1530 """
1453 Public slot to check the language files after a release process. 1531 Public slot to check the language files after a release process.
1454 """ 1532 """
1455 tbPath = self.pdata["TRANSLATIONSBINPATH"] 1533 tbPath = self.pdata["TRANSLATIONSBINPATH"]
1456 for langFile in self.pdata["TRANSLATIONS"][:]: 1534 for langFile in self.pdata["TRANSLATIONS"][:]:
1457 qmFile = self.__binaryTranslationFile(langFile) 1535 qmFile = self.__binaryTranslationFile(langFile)
1458 if qmFile: 1536 if qmFile:
1459 if ( 1537 if qmFile not in self.pdata["TRANSLATIONS"] and os.path.exists(
1460 qmFile not in self.pdata["TRANSLATIONS"] and 1538 os.path.join(self.ppath, qmFile)
1461 os.path.exists(os.path.join(self.ppath, qmFile))
1462 ): 1539 ):
1463 self.appendFile(qmFile) 1540 self.appendFile(qmFile)
1464 if tbPath: 1541 if tbPath:
1465 qmFile = os.path.join(tbPath, os.path.basename(qmFile)) 1542 qmFile = os.path.join(tbPath, os.path.basename(qmFile))
1466 if ( 1543 if qmFile not in self.pdata["TRANSLATIONS"] and os.path.exists(
1467 qmFile not in self.pdata["TRANSLATIONS"] and 1544 os.path.join(self.ppath, qmFile)
1468 os.path.exists(os.path.join(self.ppath, qmFile))
1469 ): 1545 ):
1470 self.appendFile(qmFile) 1546 self.appendFile(qmFile)
1471 1547
1472 def removeLanguageFile(self, langFile): 1548 def removeLanguageFile(self, langFile):
1473 """ 1549 """
1474 Public slot to remove a translation from the project. 1550 Public slot to remove a translation from the project.
1475 1551
1476 The translation file is not deleted from the project directory. 1552 The translation file is not deleted from the project directory.
1477 1553
1478 @param langFile the translation file to be removed (string) 1554 @param langFile the translation file to be removed (string)
1479 """ 1555 """
1480 langFile = self.getRelativePath(langFile) 1556 langFile = self.getRelativePath(langFile)
1481 qmFile = self.__binaryTranslationFile(langFile) 1557 qmFile = self.__binaryTranslationFile(langFile)
1482 self.pdata["TRANSLATIONS"].remove(langFile) 1558 self.pdata["TRANSLATIONS"].remove(langFile)
1483 self.__model.removeItem(langFile) 1559 self.__model.removeItem(langFile)
1484 if qmFile: 1560 if qmFile:
1485 with contextlib.suppress(ValueError): 1561 with contextlib.suppress(ValueError):
1486 if self.pdata["TRANSLATIONSBINPATH"]: 1562 if self.pdata["TRANSLATIONSBINPATH"]:
1487 qmFile = self.getRelativePath( 1563 qmFile = self.getRelativePath(
1488 os.path.join(self.pdata["TRANSLATIONSBINPATH"], 1564 os.path.join(
1489 os.path.basename(qmFile))) 1565 self.pdata["TRANSLATIONSBINPATH"], os.path.basename(qmFile)
1566 )
1567 )
1490 self.pdata["TRANSLATIONS"].remove(qmFile) 1568 self.pdata["TRANSLATIONS"].remove(qmFile)
1491 self.__model.removeItem(qmFile) 1569 self.__model.removeItem(qmFile)
1492 self.setDirty(True) 1570 self.setDirty(True)
1493 1571
1494 def deleteLanguageFile(self, langFile): 1572 def deleteLanguageFile(self, langFile):
1495 """ 1573 """
1496 Public slot to delete a translation from the project directory. 1574 Public slot to delete a translation from the project directory.
1497 1575
1498 @param langFile the translation file to be removed (string) 1576 @param langFile the translation file to be removed (string)
1499 """ 1577 """
1500 try: 1578 try:
1501 from send2trash import send2trash as s2t 1579 from send2trash import send2trash as s2t
1502 except ImportError: 1580 except ImportError:
1503 s2t = os.remove 1581 s2t = os.remove
1504 1582
1505 langFile = self.getRelativePath(langFile) 1583 langFile = self.getRelativePath(langFile)
1506 qmFile = self.__binaryTranslationFile(langFile) 1584 qmFile = self.__binaryTranslationFile(langFile)
1507 1585
1508 try: 1586 try:
1509 fn = os.path.join(self.ppath, langFile) 1587 fn = os.path.join(self.ppath, langFile)
1510 if os.path.exists(fn): 1588 if os.path.exists(fn):
1511 s2t(fn) 1589 s2t(fn)
1512 except OSError as err: 1590 except OSError as err:
1513 EricMessageBox.critical( 1591 EricMessageBox.critical(
1514 self.ui, 1592 self.ui,
1515 self.tr("Delete translation"), 1593 self.tr("Delete translation"),
1516 self.tr( 1594 self.tr(
1517 "<p>The selected translation file <b>{0}</b> could not be" 1595 "<p>The selected translation file <b>{0}</b> could not be"
1518 " deleted.</p><p>Reason: {1}</p>").format( 1596 " deleted.</p><p>Reason: {1}</p>"
1519 langFile, str(err))) 1597 ).format(langFile, str(err)),
1598 )
1520 return 1599 return
1521 1600
1522 self.removeLanguageFile(langFile) 1601 self.removeLanguageFile(langFile)
1523 1602
1524 # now get rid of the .qm file 1603 # now get rid of the .qm file
1525 if qmFile: 1604 if qmFile:
1526 try: 1605 try:
1527 if self.pdata["TRANSLATIONSBINPATH"]: 1606 if self.pdata["TRANSLATIONSBINPATH"]:
1528 qmFile = self.getRelativePath( 1607 qmFile = self.getRelativePath(
1529 os.path.join(self.pdata["TRANSLATIONSBINPATH"], 1608 os.path.join(
1530 os.path.basename(qmFile))) 1609 self.pdata["TRANSLATIONSBINPATH"], os.path.basename(qmFile)
1610 )
1611 )
1531 fn = os.path.join(self.ppath, qmFile) 1612 fn = os.path.join(self.ppath, qmFile)
1532 if os.path.exists(fn): 1613 if os.path.exists(fn):
1533 s2t(fn) 1614 s2t(fn)
1534 except OSError as err: 1615 except OSError as err:
1535 EricMessageBox.critical( 1616 EricMessageBox.critical(
1536 self.ui, 1617 self.ui,
1537 self.tr("Delete translation"), 1618 self.tr("Delete translation"),
1538 self.tr( 1619 self.tr(
1539 "<p>The selected translation file <b>{0}</b> could" 1620 "<p>The selected translation file <b>{0}</b> could"
1540 " not be deleted.</p><p>Reason: {1}</p>").format( 1621 " not be deleted.</p><p>Reason: {1}</p>"
1541 qmFile, str(err))) 1622 ).format(qmFile, str(err)),
1623 )
1542 return 1624 return
1543 1625
1544 def appendFile(self, fn, isSourceFile=False, updateModel=True): 1626 def appendFile(self, fn, isSourceFile=False, updateModel=True):
1545 """ 1627 """
1546 Public method to append a file to the project. 1628 Public method to append a file to the project.
1547 1629
1548 @param fn filename to be added to the project (string) 1630 @param fn filename to be added to the project (string)
1549 @param isSourceFile flag indicating that this is a source file 1631 @param isSourceFile flag indicating that this is a source file
1550 even if it doesn't have the source extension (boolean) 1632 even if it doesn't have the source extension (boolean)
1551 @param updateModel flag indicating an update of the model is 1633 @param updateModel flag indicating an update of the model is
1552 requested (boolean) 1634 requested (boolean)
1553 """ 1635 """
1554 dirty = False 1636 dirty = False
1555 1637
1556 # make it relative to the project root, if it starts with that path 1638 # make it relative to the project root, if it starts with that path
1557 # assume relative paths are relative to the project root 1639 # assume relative paths are relative to the project root
1558 newfn = self.getRelativePath(fn) if os.path.isabs(fn) else fn 1640 newfn = self.getRelativePath(fn) if os.path.isabs(fn) else fn
1559 newdir = os.path.dirname(newfn) 1641 newdir = os.path.dirname(newfn)
1560 1642
1561 if isSourceFile: 1643 if isSourceFile:
1562 filetype = "SOURCES" 1644 filetype = "SOURCES"
1563 else: 1645 else:
1564 filetype = "OTHERS" 1646 filetype = "OTHERS"
1565 bfn = os.path.basename(newfn) 1647 bfn = os.path.basename(newfn)
1566 if fnmatch.fnmatch(bfn, '*.ts') or fnmatch.fnmatch(bfn, '*.qm'): 1648 if fnmatch.fnmatch(bfn, "*.ts") or fnmatch.fnmatch(bfn, "*.qm"):
1567 filetype = "TRANSLATIONS" 1649 filetype = "TRANSLATIONS"
1568 else: 1650 else:
1569 for pattern in sorted(self.pdata["FILETYPES"].keys(), 1651 for pattern in sorted(self.pdata["FILETYPES"].keys(), reverse=True):
1570 reverse=True):
1571 if fnmatch.fnmatch(bfn, pattern): 1652 if fnmatch.fnmatch(bfn, pattern):
1572 filetype = self.pdata["FILETYPES"][pattern] 1653 filetype = self.pdata["FILETYPES"][pattern]
1573 break 1654 break
1574 1655
1575 if filetype == "__IGNORE__": 1656 if filetype == "__IGNORE__":
1576 return 1657 return
1577 1658
1578 if filetype in ["SOURCES", "FORMS", "INTERFACES", "PROTOCOLS", 1659 if filetype in ["SOURCES", "FORMS", "INTERFACES", "PROTOCOLS", "RESOURCES"]:
1579 "RESOURCES"]:
1580 if filetype == "SOURCES": 1660 if filetype == "SOURCES":
1581 if newfn not in self.pdata["SOURCES"]: 1661 if newfn not in self.pdata["SOURCES"]:
1582 self.pdata["SOURCES"].append(newfn) 1662 self.pdata["SOURCES"].append(newfn)
1583 self.projectSourceAdded.emit(newfn) 1663 self.projectSourceAdded.emit(newfn)
1584 updateModel and self.__model.addNewItem("SOURCES", newfn) 1664 updateModel and self.__model.addNewItem("SOURCES", newfn)
1595 updateModel and self.repopulateItem(newfn) 1675 updateModel and self.repopulateItem(newfn)
1596 elif filetype == "INTERFACES": 1676 elif filetype == "INTERFACES":
1597 if newfn not in self.pdata["INTERFACES"]: 1677 if newfn not in self.pdata["INTERFACES"]:
1598 self.pdata["INTERFACES"].append(newfn) 1678 self.pdata["INTERFACES"].append(newfn)
1599 self.projectInterfaceAdded.emit(newfn) 1679 self.projectInterfaceAdded.emit(newfn)
1600 (updateModel and 1680 (updateModel and self.__model.addNewItem("INTERFACES", newfn))
1601 self.__model.addNewItem("INTERFACES", newfn))
1602 dirty = True 1681 dirty = True
1603 else: 1682 else:
1604 updateModel and self.repopulateItem(newfn) 1683 updateModel and self.repopulateItem(newfn)
1605 elif filetype == "PROTOCOLS": 1684 elif filetype == "PROTOCOLS":
1606 if newfn not in self.pdata["PROTOCOLS"]: 1685 if newfn not in self.pdata["PROTOCOLS"]:
1607 self.pdata["PROTOCOLS"].append(newfn) 1686 self.pdata["PROTOCOLS"].append(newfn)
1608 self.projectProtocolAdded.emit(newfn) 1687 self.projectProtocolAdded.emit(newfn)
1609 (updateModel and 1688 (updateModel and self.__model.addNewItem("PROTOCOLS", newfn))
1610 self.__model.addNewItem("PROTOCOLS", newfn))
1611 dirty = True 1689 dirty = True
1612 else: 1690 else:
1613 updateModel and self.repopulateItem(newfn) 1691 updateModel and self.repopulateItem(newfn)
1614 elif filetype == "RESOURCES": 1692 elif filetype == "RESOURCES":
1615 if newfn not in self.pdata["RESOURCES"]: 1693 if newfn not in self.pdata["RESOURCES"]:
1627 updateModel and self.__model.addNewItem("TRANSLATIONS", newfn) 1705 updateModel and self.__model.addNewItem("TRANSLATIONS", newfn)
1628 self.projectLanguageAdded.emit(newfn) 1706 self.projectLanguageAdded.emit(newfn)
1629 dirty = True 1707 dirty = True
1630 else: 1708 else:
1631 updateModel and self.repopulateItem(newfn) 1709 updateModel and self.repopulateItem(newfn)
1632 else: # filetype == "OTHERS" 1710 else: # filetype == "OTHERS"
1633 if newfn not in self.pdata["OTHERS"]: 1711 if newfn not in self.pdata["OTHERS"]:
1634 self.pdata['OTHERS'].append(newfn) 1712 self.pdata["OTHERS"].append(newfn)
1635 self.othersAdded(newfn, updateModel) 1713 self.othersAdded(newfn, updateModel)
1636 dirty = True 1714 dirty = True
1637 else: 1715 else:
1638 updateModel and self.repopulateItem(newfn) 1716 updateModel and self.repopulateItem(newfn)
1639 if newdir not in self.otherssubdirs: 1717 if newdir not in self.otherssubdirs:
1640 self.otherssubdirs.append(newdir) 1718 self.otherssubdirs.append(newdir)
1641 1719
1642 if dirty: 1720 if dirty:
1643 self.setDirty(True) 1721 self.setDirty(True)
1644 1722
1645 @pyqtSlot() 1723 @pyqtSlot()
1646 def addFiles(self, fileTypeFilter=None, startdir=None): 1724 def addFiles(self, fileTypeFilter=None, startdir=None):
1647 """ 1725 """
1648 Public slot used to add files to the project. 1726 Public slot used to add files to the project.
1649 1727
1650 @param fileTypeFilter filter to be used by the add file dialog 1728 @param fileTypeFilter filter to be used by the add file dialog
1651 @type str out of source, form, resource, interface, protocol, others 1729 @type str out of source, form, resource, interface, protocol, others
1652 @param startdir start directory for the selection dialog 1730 @param startdir start directory for the selection dialog
1653 @type str 1731 @type str
1654 """ 1732 """
1655 if startdir is None: 1733 if startdir is None:
1656 startdir = self.ppath 1734 startdir = self.ppath
1657 from .AddFileDialog import AddFileDialog 1735 from .AddFileDialog import AddFileDialog
1658 dlg = AddFileDialog(self, self.parent(), fileTypeFilter, 1736
1659 startdir=startdir) 1737 dlg = AddFileDialog(self, self.parent(), fileTypeFilter, startdir=startdir)
1660 if dlg.exec() == QDialog.DialogCode.Accepted: 1738 if dlg.exec() == QDialog.DialogCode.Accepted:
1661 fnames, target, isSource = dlg.getData() 1739 fnames, target, isSource = dlg.getData()
1662 if target != '': 1740 if target != "":
1663 for fn in fnames: 1741 for fn in fnames:
1664 targetfile = os.path.join(target, os.path.basename(fn)) 1742 targetfile = os.path.join(target, os.path.basename(fn))
1665 if not Utilities.samepath(os.path.dirname(fn), target): 1743 if not Utilities.samepath(os.path.dirname(fn), target):
1666 try: 1744 try:
1667 if not os.path.isdir(target): 1745 if not os.path.isdir(target):
1668 os.makedirs(target) 1746 os.makedirs(target)
1669 1747
1670 if os.path.exists(targetfile): 1748 if os.path.exists(targetfile):
1671 res = EricMessageBox.yesNo( 1749 res = EricMessageBox.yesNo(
1672 self.ui, 1750 self.ui,
1673 self.tr("Add file"), 1751 self.tr("Add file"),
1674 self.tr( 1752 self.tr(
1675 "<p>The file <b>{0}</b> already" 1753 "<p>The file <b>{0}</b> already"
1676 " exists.</p><p>Overwrite it?</p>") 1754 " exists.</p><p>Overwrite it?</p>"
1677 .format(targetfile), 1755 ).format(targetfile),
1678 icon=EricMessageBox.Warning) 1756 icon=EricMessageBox.Warning,
1757 )
1679 if not res: 1758 if not res:
1680 return # don't overwrite 1759 return # don't overwrite
1681 1760
1682 shutil.copy(fn, target) 1761 shutil.copy(fn, target)
1683 except OSError as why: 1762 except OSError as why:
1684 EricMessageBox.critical( 1763 EricMessageBox.critical(
1685 self.ui, 1764 self.ui,
1686 self.tr("Add file"), 1765 self.tr("Add file"),
1687 self.tr( 1766 self.tr(
1688 "<p>The selected file <b>{0}</b> could" 1767 "<p>The selected file <b>{0}</b> could"
1689 " not be added to <b>{1}</b>.</p>" 1768 " not be added to <b>{1}</b>.</p>"
1690 "<p>Reason: {2}</p>") 1769 "<p>Reason: {2}</p>"
1691 .format(fn, target, str(why))) 1770 ).format(fn, target, str(why)),
1771 )
1692 continue 1772 continue
1693 1773
1694 self.appendFile(targetfile, 1774 self.appendFile(targetfile, isSource or fileTypeFilter == "source")
1695 isSource or fileTypeFilter == 'source')
1696 else: 1775 else:
1697 EricMessageBox.critical( 1776 EricMessageBox.critical(
1698 self.ui, 1777 self.ui,
1699 self.tr("Add file"), 1778 self.tr("Add file"),
1700 self.tr("The target directory must not be empty.")) 1779 self.tr("The target directory must not be empty."),
1701 1780 )
1781
1702 def __addSingleDirectory(self, filetype, source, target, quiet=False): 1782 def __addSingleDirectory(self, filetype, source, target, quiet=False):
1703 """ 1783 """
1704 Private method used to add all files of a single directory to the 1784 Private method used to add all files of a single directory to the
1705 project. 1785 project.
1706 1786
1707 @param filetype type of files to add (string) 1787 @param filetype type of files to add (string)
1708 @param source source directory (string) 1788 @param source source directory (string)
1709 @param target target directory (string) 1789 @param target target directory (string)
1710 @param quiet flag indicating quiet operations (boolean) 1790 @param quiet flag indicating quiet operations (boolean)
1711 """ 1791 """
1715 for pattern, patterntype in list(self.pdata["FILETYPES"].items()): 1795 for pattern, patterntype in list(self.pdata["FILETYPES"].items()):
1716 if patterntype == filetype: 1796 if patterntype == filetype:
1717 patterns.append(pattern) 1797 patterns.append(pattern)
1718 elif patterntype == "__IGNORE__": 1798 elif patterntype == "__IGNORE__":
1719 ignorePatterns.append(pattern) 1799 ignorePatterns.append(pattern)
1720 1800
1721 files = [] 1801 files = []
1722 for pattern in patterns: 1802 for pattern in patterns:
1723 sstring = "{0}{1}{2}".format(source, os.sep, pattern) 1803 sstring = "{0}{1}{2}".format(source, os.sep, pattern)
1724 files.extend(glob.glob(sstring)) 1804 files.extend(glob.glob(sstring))
1725 1805
1726 if len(files) == 0: 1806 if len(files) == 0:
1727 if not quiet: 1807 if not quiet:
1728 EricMessageBox.information( 1808 EricMessageBox.information(
1729 self.ui, 1809 self.ui,
1730 self.tr("Add directory"), 1810 self.tr("Add directory"),
1731 self.tr( 1811 self.tr(
1732 "<p>The source directory doesn't contain" 1812 "<p>The source directory doesn't contain"
1733 " any files belonging to the selected category.</p>")) 1813 " any files belonging to the selected category.</p>"
1814 ),
1815 )
1734 return 1816 return
1735 1817
1736 if ( 1818 if not Utilities.samepath(target, source) and not os.path.isdir(target):
1737 not Utilities.samepath(target, source) and
1738 not os.path.isdir(target)
1739 ):
1740 try: 1819 try:
1741 os.makedirs(target) 1820 os.makedirs(target)
1742 except OSError as why: 1821 except OSError as why:
1743 EricMessageBox.critical( 1822 EricMessageBox.critical(
1744 self.ui, 1823 self.ui,
1745 self.tr("Add directory"), 1824 self.tr("Add directory"),
1746 self.tr( 1825 self.tr(
1747 "<p>The target directory <b>{0}</b> could not be" 1826 "<p>The target directory <b>{0}</b> could not be"
1748 " created.</p><p>Reason: {1}</p>") 1827 " created.</p><p>Reason: {1}</p>"
1749 .format(target, str(why))) 1828 ).format(target, str(why)),
1829 )
1750 return 1830 return
1751 1831
1752 for file in files: 1832 for file in files:
1753 for pattern in ignorePatterns: 1833 for pattern in ignorePatterns:
1754 if fnmatch.fnmatch(file, pattern): 1834 if fnmatch.fnmatch(file, pattern):
1755 continue 1835 continue
1756 1836
1757 targetfile = os.path.join(target, os.path.basename(file)) 1837 targetfile = os.path.join(target, os.path.basename(file))
1758 if not Utilities.samepath(target, source): 1838 if not Utilities.samepath(target, source):
1759 try: 1839 try:
1760 if os.path.exists(targetfile): 1840 if os.path.exists(targetfile):
1761 res = EricMessageBox.yesNo( 1841 res = EricMessageBox.yesNo(
1762 self.ui, 1842 self.ui,
1763 self.tr("Add directory"), 1843 self.tr("Add directory"),
1764 self.tr( 1844 self.tr(
1765 "<p>The file <b>{0}</b> already exists.</p>" 1845 "<p>The file <b>{0}</b> already exists.</p>"
1766 "<p>Overwrite it?</p>") 1846 "<p>Overwrite it?</p>"
1767 .format(targetfile), 1847 ).format(targetfile),
1768 icon=EricMessageBox.Warning) 1848 icon=EricMessageBox.Warning,
1849 )
1769 if not res: 1850 if not res:
1770 continue 1851 continue
1771 # don't overwrite, carry on with next file 1852 # don't overwrite, carry on with next file
1772 1853
1773 shutil.copy(file, target) 1854 shutil.copy(file, target)
1774 except OSError: 1855 except OSError:
1775 continue 1856 continue
1776 self.appendFile(targetfile) 1857 self.appendFile(targetfile)
1777 1858
1778 def __addRecursiveDirectory(self, filetype, source, target): 1859 def __addRecursiveDirectory(self, filetype, source, target):
1779 """ 1860 """
1780 Private method used to add all files of a directory tree. 1861 Private method used to add all files of a directory tree.
1781 1862
1782 The tree is rooted at source to another one rooted at target. This 1863 The tree is rooted at source to another one rooted at target. This
1783 method decents down to the lowest subdirectory. 1864 method decents down to the lowest subdirectory.
1784 1865
1785 @param filetype type of files to add (string) 1866 @param filetype type of files to add (string)
1786 @param source source directory (string) 1867 @param source source directory (string)
1787 @param target target directory (string) 1868 @param target target directory (string)
1788 """ 1869 """
1789 # first perform the addition of source 1870 # first perform the addition of source
1790 self.__addSingleDirectory(filetype, source, target, True) 1871 self.__addSingleDirectory(filetype, source, target, True)
1791 1872
1792 ignore_patterns = [pattern for pattern, filetype in 1873 ignore_patterns = [
1793 self.pdata["FILETYPES"].items() 1874 pattern
1794 if filetype == '__IGNORE__'] 1875 for pattern, filetype in self.pdata["FILETYPES"].items()
1795 1876 if filetype == "__IGNORE__"
1877 ]
1878
1796 # now recurse into subdirectories 1879 # now recurse into subdirectories
1797 for name in os.listdir(source): 1880 for name in os.listdir(source):
1798 ns = os.path.join(source, name) 1881 ns = os.path.join(source, name)
1799 if os.path.isdir(ns): 1882 if os.path.isdir(ns):
1800 skip = False 1883 skip = False
1802 if fnmatch.fnmatch(name, ignore_pattern): 1885 if fnmatch.fnmatch(name, ignore_pattern):
1803 skip = True 1886 skip = True
1804 break 1887 break
1805 if skip: 1888 if skip:
1806 continue 1889 continue
1807 1890
1808 nt = os.path.join(target, name) 1891 nt = os.path.join(target, name)
1809 self.__addRecursiveDirectory(filetype, ns, nt) 1892 self.__addRecursiveDirectory(filetype, ns, nt)
1810 1893
1811 @pyqtSlot() 1894 @pyqtSlot()
1812 def addDirectory(self, fileTypeFilter=None, startdir=None): 1895 def addDirectory(self, fileTypeFilter=None, startdir=None):
1813 """ 1896 """
1814 Public method used to add all files of a directory to the project. 1897 Public method used to add all files of a directory to the project.
1815 1898
1816 @param fileTypeFilter filter to be used by the add directory dialog 1899 @param fileTypeFilter filter to be used by the add directory dialog
1817 @type str out of source, form, resource, interface, protocol, others 1900 @type str out of source, form, resource, interface, protocol, others
1818 @param startdir start directory for the selection dialog 1901 @param startdir start directory for the selection dialog
1819 @type str 1902 @type str
1820 """ 1903 """
1821 if startdir is None: 1904 if startdir is None:
1822 startdir = self.ppath 1905 startdir = self.ppath
1823 from .AddDirectoryDialog import AddDirectoryDialog 1906 from .AddDirectoryDialog import AddDirectoryDialog
1824 dlg = AddDirectoryDialog( 1907
1825 self, fileTypeFilter, self.parent(), startdir=startdir) 1908 dlg = AddDirectoryDialog(self, fileTypeFilter, self.parent(), startdir=startdir)
1826 if dlg.exec() == QDialog.DialogCode.Accepted: 1909 if dlg.exec() == QDialog.DialogCode.Accepted:
1827 filetype, source, target, recursive = dlg.getData() 1910 filetype, source, target, recursive = dlg.getData()
1828 if target == '': 1911 if target == "":
1829 EricMessageBox.critical( 1912 EricMessageBox.critical(
1830 self.ui, 1913 self.ui,
1831 self.tr("Add directory"), 1914 self.tr("Add directory"),
1832 self.tr("The target directory must not be empty.")) 1915 self.tr("The target directory must not be empty."),
1916 )
1833 return 1917 return
1834 1918
1835 if filetype == 'OTHERS': 1919 if filetype == "OTHERS":
1836 self.addToOthers(source) 1920 self.addToOthers(source)
1837 return 1921 return
1838 1922
1839 if source == '': 1923 if source == "":
1840 EricMessageBox.critical( 1924 EricMessageBox.critical(
1841 self.ui, 1925 self.ui,
1842 self.tr("Add directory"), 1926 self.tr("Add directory"),
1843 self.tr("The source directory must not be empty.")) 1927 self.tr("The source directory must not be empty."),
1928 )
1844 return 1929 return
1845 1930
1846 if recursive: 1931 if recursive:
1847 self.__addRecursiveDirectory(filetype, source, target) 1932 self.__addRecursiveDirectory(filetype, source, target)
1848 else: 1933 else:
1849 self.__addSingleDirectory(filetype, source, target) 1934 self.__addSingleDirectory(filetype, source, target)
1850 1935
1851 def addToOthers(self, fn): 1936 def addToOthers(self, fn):
1852 """ 1937 """
1853 Public method to add a file/directory to the OTHERS project data. 1938 Public method to add a file/directory to the OTHERS project data.
1854 1939
1855 @param fn file name or directory name to add (string) 1940 @param fn file name or directory name to add (string)
1856 """ 1941 """
1857 if fn: 1942 if fn:
1858 # if it is below the project directory, make it relative to that 1943 # if it is below the project directory, make it relative to that
1859 fn = self.getRelativePath(fn) 1944 fn = self.getRelativePath(fn)
1860 1945
1861 # if it ends with the directory separator character, remove it 1946 # if it ends with the directory separator character, remove it
1862 if fn.endswith(os.sep): 1947 if fn.endswith(os.sep):
1863 fn = fn[:-1] 1948 fn = fn[:-1]
1864 1949
1865 if fn not in self.pdata["OTHERS"]: 1950 if fn not in self.pdata["OTHERS"]:
1866 self.pdata['OTHERS'].append(fn) 1951 self.pdata["OTHERS"].append(fn)
1867 self.othersAdded(fn) 1952 self.othersAdded(fn)
1868 self.setDirty(True) 1953 self.setDirty(True)
1869 1954
1870 if os.path.isdir(fn) and fn not in self.otherssubdirs: 1955 if os.path.isdir(fn) and fn not in self.otherssubdirs:
1871 self.otherssubdirs.append(fn) 1956 self.otherssubdirs.append(fn)
1872 1957
1873 def addSourceFiles(self): 1958 def addSourceFiles(self):
1874 """ 1959 """
1875 Public slot to add source files to the current project. 1960 Public slot to add source files to the current project.
1876 """ 1961 """
1877 self.addFiles('source') 1962 self.addFiles("source")
1878 1963
1879 def addUiFiles(self): 1964 def addUiFiles(self):
1880 """ 1965 """
1881 Public slot to add forms to the current project. 1966 Public slot to add forms to the current project.
1882 """ 1967 """
1883 self.addFiles('form') 1968 self.addFiles("form")
1884 1969
1885 def addIdlFiles(self): 1970 def addIdlFiles(self):
1886 """ 1971 """
1887 Public slot to add IDL interfaces to the current project. 1972 Public slot to add IDL interfaces to the current project.
1888 """ 1973 """
1889 self.addFiles('interface') 1974 self.addFiles("interface")
1890 1975
1891 def addProtoFiles(self): 1976 def addProtoFiles(self):
1892 """ 1977 """
1893 Public slot to add protocol files to the current project. 1978 Public slot to add protocol files to the current project.
1894 """ 1979 """
1895 self.addFiles('protocol') 1980 self.addFiles("protocol")
1896 1981
1897 def addResourceFiles(self): 1982 def addResourceFiles(self):
1898 """ 1983 """
1899 Public slot to add Qt resources to the current project. 1984 Public slot to add Qt resources to the current project.
1900 """ 1985 """
1901 self.addFiles('resource') 1986 self.addFiles("resource")
1902 1987
1903 def addOthersFiles(self): 1988 def addOthersFiles(self):
1904 """ 1989 """
1905 Public slot to add files to the OTHERS project data. 1990 Public slot to add files to the OTHERS project data.
1906 """ 1991 """
1907 self.addFiles('others') 1992 self.addFiles("others")
1908 1993
1909 def addSourceDir(self): 1994 def addSourceDir(self):
1910 """ 1995 """
1911 Public slot to add all source files of a directory to the current 1996 Public slot to add all source files of a directory to the current
1912 project. 1997 project.
1913 """ 1998 """
1914 self.addDirectory('source') 1999 self.addDirectory("source")
1915 2000
1916 def addUiDir(self): 2001 def addUiDir(self):
1917 """ 2002 """
1918 Public slot to add all forms of a directory to the current project. 2003 Public slot to add all forms of a directory to the current project.
1919 """ 2004 """
1920 self.addDirectory('form') 2005 self.addDirectory("form")
1921 2006
1922 def addIdlDir(self): 2007 def addIdlDir(self):
1923 """ 2008 """
1924 Public slot to add all IDL interfaces of a directory to the current 2009 Public slot to add all IDL interfaces of a directory to the current
1925 project. 2010 project.
1926 """ 2011 """
1927 self.addDirectory('interface') 2012 self.addDirectory("interface")
1928 2013
1929 def addProtoDir(self): 2014 def addProtoDir(self):
1930 """ 2015 """
1931 Public slot to add all protocol files of a directory to the current 2016 Public slot to add all protocol files of a directory to the current
1932 project. 2017 project.
1933 """ 2018 """
1934 self.addDirectory('protocol') 2019 self.addDirectory("protocol")
1935 2020
1936 def addResourceDir(self): 2021 def addResourceDir(self):
1937 """ 2022 """
1938 Public slot to add all Qt resource files of a directory to the current 2023 Public slot to add all Qt resource files of a directory to the current
1939 project. 2024 project.
1940 """ 2025 """
1941 self.addDirectory('resource') 2026 self.addDirectory("resource")
1942 2027
1943 def addOthersDir(self): 2028 def addOthersDir(self):
1944 """ 2029 """
1945 Public slot to add a directory to the OTHERS project data. 2030 Public slot to add a directory to the OTHERS project data.
1946 """ 2031 """
1947 self.addDirectory('others') 2032 self.addDirectory("others")
1948 2033
1949 def renameMainScript(self, oldfn, newfn): 2034 def renameMainScript(self, oldfn, newfn):
1950 """ 2035 """
1951 Public method to rename the main script. 2036 Public method to rename the main script.
1952 2037
1953 @param oldfn old filename (string) 2038 @param oldfn old filename (string)
1954 @param newfn new filename of the main script (string) 2039 @param newfn new filename of the main script (string)
1955 """ 2040 """
1956 if self.pdata["MAINSCRIPT"]: 2041 if self.pdata["MAINSCRIPT"]:
1957 ofn = self.getRelativePath(oldfn) 2042 ofn = self.getRelativePath(oldfn)
1958 if ofn != self.pdata["MAINSCRIPT"]: 2043 if ofn != self.pdata["MAINSCRIPT"]:
1959 return 2044 return
1960 2045
1961 fn = self.getRelativePath(newfn) 2046 fn = self.getRelativePath(newfn)
1962 self.pdata["MAINSCRIPT"] = fn 2047 self.pdata["MAINSCRIPT"] = fn
1963 self.setDirty(True) 2048 self.setDirty(True)
1964 2049
1965 def renameFile(self, oldfn, newfn=None): 2050 def renameFile(self, oldfn, newfn=None):
1966 """ 2051 """
1967 Public slot to rename a file of the project. 2052 Public slot to rename a file of the project.
1968 2053
1969 @param oldfn old filename of the file (string) 2054 @param oldfn old filename of the file (string)
1970 @param newfn new filename of the file (string) 2055 @param newfn new filename of the file (string)
1971 @return flag indicating success 2056 @return flag indicating success
1972 """ 2057 """
1973 fn = self.getRelativePath(oldfn) 2058 fn = self.getRelativePath(oldfn)
1974 isSourceFile = fn in self.pdata["SOURCES"] 2059 isSourceFile = fn in self.pdata["SOURCES"]
1975 2060
1976 if newfn is None: 2061 if newfn is None:
1977 newfn = EricFileDialog.getSaveFileName( 2062 newfn = EricFileDialog.getSaveFileName(
1978 None, 2063 None,
1979 self.tr("Rename file"), 2064 self.tr("Rename file"),
1980 oldfn, 2065 oldfn,
1981 "", 2066 "",
1982 EricFileDialog.DontConfirmOverwrite) 2067 EricFileDialog.DontConfirmOverwrite,
2068 )
1983 if not newfn: 2069 if not newfn:
1984 return False 2070 return False
1985 newfn = Utilities.toNativeSeparators(newfn) 2071 newfn = Utilities.toNativeSeparators(newfn)
1986 2072
1987 if os.path.exists(newfn): 2073 if os.path.exists(newfn):
1988 res = EricMessageBox.yesNo( 2074 res = EricMessageBox.yesNo(
1989 self.ui, 2075 self.ui,
1990 self.tr("Rename File"), 2076 self.tr("Rename File"),
1991 self.tr("""<p>The file <b>{0}</b> already exists.""" 2077 self.tr(
1992 """ Overwrite it?</p>""") 2078 """<p>The file <b>{0}</b> already exists."""
1993 .format(newfn), 2079 """ Overwrite it?</p>"""
1994 icon=EricMessageBox.Warning) 2080 ).format(newfn),
2081 icon=EricMessageBox.Warning,
2082 )
1995 if not res: 2083 if not res:
1996 return False 2084 return False
1997 2085
1998 try: 2086 try:
1999 os.rename(oldfn, newfn) 2087 os.rename(oldfn, newfn)
2000 except OSError as msg: 2088 except OSError as msg:
2001 EricMessageBox.critical( 2089 EricMessageBox.critical(
2002 self.ui, 2090 self.ui,
2003 self.tr("Rename File"), 2091 self.tr("Rename File"),
2004 self.tr( 2092 self.tr(
2005 """<p>The file <b>{0}</b> could not be renamed.<br />""" 2093 """<p>The file <b>{0}</b> could not be renamed.<br />"""
2006 """Reason: {1}</p>""").format(oldfn, str(msg))) 2094 """Reason: {1}</p>"""
2095 ).format(oldfn, str(msg)),
2096 )
2007 return False 2097 return False
2008 2098
2009 if ( 2099 if (
2010 fn in self.pdata["SOURCES"] or 2100 fn in self.pdata["SOURCES"]
2011 fn in self.pdata["FORMS"] or 2101 or fn in self.pdata["FORMS"]
2012 fn in self.pdata["TRANSLATIONS"] or 2102 or fn in self.pdata["TRANSLATIONS"]
2013 fn in self.pdata["INTERFACES"] or 2103 or fn in self.pdata["INTERFACES"]
2014 fn in self.pdata["PROTOCOLS"] or 2104 or fn in self.pdata["PROTOCOLS"]
2015 fn in self.pdata["RESOURCES"] or 2105 or fn in self.pdata["RESOURCES"]
2016 fn in self.pdata["OTHERS"] 2106 or fn in self.pdata["OTHERS"]
2017 ): 2107 ):
2018 self.renameFileInPdata(oldfn, newfn, isSourceFile) 2108 self.renameFileInPdata(oldfn, newfn, isSourceFile)
2019 2109
2020 return True 2110 return True
2021 2111
2022 def renameFileInPdata(self, oldname, newname, isSourceFile=False): 2112 def renameFileInPdata(self, oldname, newname, isSourceFile=False):
2023 """ 2113 """
2024 Public method to rename a file in the pdata structure. 2114 Public method to rename a file in the pdata structure.
2025 2115
2026 @param oldname old filename (string) 2116 @param oldname old filename (string)
2027 @param newname new filename (string) 2117 @param newname new filename (string)
2028 @param isSourceFile flag indicating that this is a source file 2118 @param isSourceFile flag indicating that this is a source file
2029 even if it doesn't have the source extension (boolean) 2119 even if it doesn't have the source extension (boolean)
2030 """ 2120 """
2036 self.__model.renameItem(fn, newname) 2126 self.__model.renameItem(fn, newname)
2037 else: 2127 else:
2038 self.removeFile(oldname) 2128 self.removeFile(oldname)
2039 self.appendFile(newname, isSourceFile) 2129 self.appendFile(newname, isSourceFile)
2040 self.projectFileRenamed.emit(oldname, newname) 2130 self.projectFileRenamed.emit(oldname, newname)
2041 2131
2042 self.renameMainScript(fn, newname) 2132 self.renameMainScript(fn, newname)
2043 2133
2044 def getFiles(self, start): 2134 def getFiles(self, start):
2045 """ 2135 """
2046 Public method to get all files starting with a common prefix. 2136 Public method to get all files starting with a common prefix.
2047 2137
2048 @param start prefix (string) 2138 @param start prefix (string)
2049 @return list of files starting with a common prefix (list of strings) 2139 @return list of files starting with a common prefix (list of strings)
2050 """ 2140 """
2051 filelist = [] 2141 filelist = []
2052 start = self.getRelativePath(start) 2142 start = self.getRelativePath(start)
2053 for key in ["SOURCES", "FORMS", "INTERFACES", "PROTOCOLS", "RESOURCES", 2143 for key in [
2054 "OTHERS"]: 2144 "SOURCES",
2145 "FORMS",
2146 "INTERFACES",
2147 "PROTOCOLS",
2148 "RESOURCES",
2149 "OTHERS",
2150 ]:
2055 for entry in self.pdata[key][:]: 2151 for entry in self.pdata[key][:]:
2056 if entry.startswith(start): 2152 if entry.startswith(start):
2057 filelist.append(os.path.join(self.ppath, entry)) 2153 filelist.append(os.path.join(self.ppath, entry))
2058 return filelist 2154 return filelist
2059 2155
2060 def __reorganizeFiles(self): 2156 def __reorganizeFiles(self):
2061 """ 2157 """
2062 Private method to reorganize files stored in the project. 2158 Private method to reorganize files stored in the project.
2063 """ 2159 """
2064 reorganized = False 2160 reorganized = False
2065 2161
2066 # init data store for the reorganization 2162 # init data store for the reorganization
2067 newPdata = {} 2163 newPdata = {}
2068 for key in ["SOURCES", "FORMS", "INTERFACES", "PROTOCOLS", "RESOURCES", 2164 for key in [
2069 "OTHERS", "TRANSLATIONS"]: 2165 "SOURCES",
2166 "FORMS",
2167 "INTERFACES",
2168 "PROTOCOLS",
2169 "RESOURCES",
2170 "OTHERS",
2171 "TRANSLATIONS",
2172 ]:
2070 newPdata[key] = [] 2173 newPdata[key] = []
2071 2174
2072 # iterate over all files checking for a reassignment 2175 # iterate over all files checking for a reassignment
2073 for key in ["SOURCES", "FORMS", "INTERFACES", "PROTOCOLS", "RESOURCES", 2176 for key in [
2074 "OTHERS", "TRANSLATIONS"]: 2177 "SOURCES",
2178 "FORMS",
2179 "INTERFACES",
2180 "PROTOCOLS",
2181 "RESOURCES",
2182 "OTHERS",
2183 "TRANSLATIONS",
2184 ]:
2075 for fn in self.pdata[key][:]: 2185 for fn in self.pdata[key][:]:
2076 filetype = key 2186 filetype = key
2077 bfn = os.path.basename(fn) 2187 bfn = os.path.basename(fn)
2078 for pattern in sorted(self.pdata["FILETYPES"].keys(), 2188 for pattern in sorted(self.pdata["FILETYPES"].keys(), reverse=True):
2079 reverse=True):
2080 if fnmatch.fnmatch(bfn, pattern): 2189 if fnmatch.fnmatch(bfn, pattern):
2081 filetype = self.pdata["FILETYPES"][pattern] 2190 filetype = self.pdata["FILETYPES"][pattern]
2082 break 2191 break
2083 2192
2084 if filetype != "__IGNORE__": 2193 if filetype != "__IGNORE__":
2085 newPdata[filetype].append(fn) 2194 newPdata[filetype].append(fn)
2086 if filetype != key: 2195 if filetype != key:
2087 reorganized = True 2196 reorganized = True
2088 2197
2089 if reorganized: 2198 if reorganized:
2090 # copy the reorganized files back to the project 2199 # copy the reorganized files back to the project
2091 for key in ["SOURCES", "FORMS", "INTERFACES", "PROTOCOLS", 2200 for key in [
2092 "RESOURCES", "OTHERS", "TRANSLATIONS"]: 2201 "SOURCES",
2202 "FORMS",
2203 "INTERFACES",
2204 "PROTOCOLS",
2205 "RESOURCES",
2206 "OTHERS",
2207 "TRANSLATIONS",
2208 ]:
2093 self.pdata[key] = newPdata[key][:] 2209 self.pdata[key] = newPdata[key][:]
2094 2210
2095 # repopulate the model 2211 # repopulate the model
2096 self.__model.projectClosed(False) 2212 self.__model.projectClosed(False)
2097 self.__model.projectOpened() 2213 self.__model.projectOpened()
2098 2214
2099 def copyDirectory(self, olddn, newdn): 2215 def copyDirectory(self, olddn, newdn):
2100 """ 2216 """
2101 Public slot to copy a directory. 2217 Public slot to copy a directory.
2102 2218
2103 @param olddn original directory name (string) 2219 @param olddn original directory name (string)
2104 @param newdn new directory name (string) 2220 @param newdn new directory name (string)
2105 """ 2221 """
2106 olddn = self.getRelativePath(olddn) 2222 olddn = self.getRelativePath(olddn)
2107 newdn = self.getRelativePath(newdn) 2223 newdn = self.getRelativePath(newdn)
2108 for key in ["SOURCES", "FORMS", "INTERFACES", "PROTOCOLS", "RESOURCES", 2224 for key in [
2109 "OTHERS"]: 2225 "SOURCES",
2226 "FORMS",
2227 "INTERFACES",
2228 "PROTOCOLS",
2229 "RESOURCES",
2230 "OTHERS",
2231 ]:
2110 for entry in self.pdata[key][:]: 2232 for entry in self.pdata[key][:]:
2111 if entry.startswith(olddn): 2233 if entry.startswith(olddn):
2112 entry = entry.replace(olddn, newdn) 2234 entry = entry.replace(olddn, newdn)
2113 self.appendFile(os.path.join(self.ppath, entry), 2235 self.appendFile(os.path.join(self.ppath, entry), key == "SOURCES")
2114 key == "SOURCES")
2115 self.setDirty(True) 2236 self.setDirty(True)
2116 2237
2117 def moveDirectory(self, olddn, newdn): 2238 def moveDirectory(self, olddn, newdn):
2118 """ 2239 """
2119 Public slot to move a directory. 2240 Public slot to move a directory.
2120 2241
2121 @param olddn old directory name (string) 2242 @param olddn old directory name (string)
2122 @param newdn new directory name (string) 2243 @param newdn new directory name (string)
2123 """ 2244 """
2124 olddn = self.getRelativePath(olddn) 2245 olddn = self.getRelativePath(olddn)
2125 newdn = self.getRelativePath(newdn) 2246 newdn = self.getRelativePath(newdn)
2126 typeStrings = [] 2247 typeStrings = []
2127 for key in ["SOURCES", "FORMS", "INTERFACES", "PROTOCOLS", "RESOURCES", 2248 for key in [
2128 "OTHERS"]: 2249 "SOURCES",
2250 "FORMS",
2251 "INTERFACES",
2252 "PROTOCOLS",
2253 "RESOURCES",
2254 "OTHERS",
2255 ]:
2129 for entry in self.pdata[key][:]: 2256 for entry in self.pdata[key][:]:
2130 if entry.startswith(olddn): 2257 if entry.startswith(olddn):
2131 if key not in typeStrings: 2258 if key not in typeStrings:
2132 typeStrings.append(key) 2259 typeStrings.append(key)
2133 self.pdata[key].remove(entry) 2260 self.pdata[key].remove(entry)
2147 del typeStrings[0] 2274 del typeStrings[0]
2148 self.__model.addNewItem(typeString, newdn, typeStrings) 2275 self.__model.addNewItem(typeString, newdn, typeStrings)
2149 else: 2276 else:
2150 self.__model.renameItem(olddn, self.getAbsolutePath(newdn)) 2277 self.__model.renameItem(olddn, self.getAbsolutePath(newdn))
2151 self.directoryRemoved.emit(olddn) 2278 self.directoryRemoved.emit(olddn)
2152 2279
2153 def removeFile(self, fn, updateModel=True): 2280 def removeFile(self, fn, updateModel=True):
2154 """ 2281 """
2155 Public slot to remove a file from the project. 2282 Public slot to remove a file from the project.
2156 2283
2157 The file is not deleted from the project directory. 2284 The file is not deleted from the project directory.
2158 2285
2159 @param fn filename to be removed from the project 2286 @param fn filename to be removed from the project
2160 @param updateModel flag indicating an update of the model is 2287 @param updateModel flag indicating an update of the model is
2161 requested (boolean) 2288 requested (boolean)
2162 """ 2289 """
2163 fn = self.getRelativePath(fn) 2290 fn = self.getRelativePath(fn)
2186 else: 2313 else:
2187 dirty = False 2314 dirty = False
2188 updateModel and self.__model.removeItem(fn) 2315 updateModel and self.__model.removeItem(fn)
2189 if dirty: 2316 if dirty:
2190 self.setDirty(True) 2317 self.setDirty(True)
2191 2318
2192 def removeDirectory(self, dn): 2319 def removeDirectory(self, dn):
2193 """ 2320 """
2194 Public method to remove a directory from the project. 2321 Public method to remove a directory from the project.
2195 2322
2196 The directory is not deleted from the project directory. 2323 The directory is not deleted from the project directory.
2197 2324
2198 @param dn directory name to be removed from the project 2325 @param dn directory name to be removed from the project
2199 """ 2326 """
2200 dirty = False 2327 dirty = False
2201 dn = self.getRelativePath(dn) 2328 dn = self.getRelativePath(dn)
2202 for entry in self.pdata["OTHERS"][:]: 2329 for entry in self.pdata["OTHERS"][:]:
2203 if entry.startswith(dn): 2330 if entry.startswith(dn):
2204 self.pdata["OTHERS"].remove(entry) 2331 self.pdata["OTHERS"].remove(entry)
2205 dirty = True 2332 dirty = True
2206 dn2 = dn if dn.endswith(os.sep) else dn + os.sep 2333 dn2 = dn if dn.endswith(os.sep) else dn + os.sep
2207 for key in ["SOURCES", "FORMS", "INTERFACES", "PROTOCOLS", "RESOURCES", 2334 for key in [
2208 "TRANSLATIONS", ]: 2335 "SOURCES",
2336 "FORMS",
2337 "INTERFACES",
2338 "PROTOCOLS",
2339 "RESOURCES",
2340 "TRANSLATIONS",
2341 ]:
2209 for entry in self.pdata[key][:]: 2342 for entry in self.pdata[key][:]:
2210 if entry.startswith(dn2): 2343 if entry.startswith(dn2):
2211 self.pdata[key].remove(entry) 2344 self.pdata[key].remove(entry)
2212 dirty = True 2345 dirty = True
2213 self.__model.removeItem(dn) 2346 self.__model.removeItem(dn)
2214 if dirty: 2347 if dirty:
2215 self.setDirty(True) 2348 self.setDirty(True)
2216 self.directoryRemoved.emit(dn) 2349 self.directoryRemoved.emit(dn)
2217 2350
2218 def deleteFile(self, fn): 2351 def deleteFile(self, fn):
2219 """ 2352 """
2220 Public method to delete a file from the project directory. 2353 Public method to delete a file from the project directory.
2221 2354
2222 @param fn filename to be deleted from the project 2355 @param fn filename to be deleted from the project
2223 @return flag indicating success (boolean) 2356 @return flag indicating success (boolean)
2224 """ 2357 """
2225 try: 2358 try:
2226 from send2trash import send2trash as s2t 2359 from send2trash import send2trash as s2t
2227 except ImportError: 2360 except ImportError:
2228 s2t = os.remove 2361 s2t = os.remove
2229 2362
2230 try: 2363 try:
2231 s2t(os.path.join(self.ppath, fn)) 2364 s2t(os.path.join(self.ppath, fn))
2232 path, ext = os.path.splitext(fn) 2365 path, ext = os.path.splitext(fn)
2233 if ext == '.ui': 2366 if ext == ".ui":
2234 fn2 = os.path.join(self.ppath, '{0}.h'.format(fn)) 2367 fn2 = os.path.join(self.ppath, "{0}.h".format(fn))
2235 if os.path.isfile(fn2): 2368 if os.path.isfile(fn2):
2236 s2t(fn2) 2369 s2t(fn2)
2237 head, tail = os.path.split(path) 2370 head, tail = os.path.split(path)
2238 for ext in ['.pyc', '.pyo']: 2371 for ext in [".pyc", ".pyo"]:
2239 fn2 = os.path.join(self.ppath, path + ext) 2372 fn2 = os.path.join(self.ppath, path + ext)
2240 if os.path.isfile(fn2): 2373 if os.path.isfile(fn2):
2241 s2t(fn2) 2374 s2t(fn2)
2242 pat = os.path.join( 2375 pat = os.path.join(
2243 self.ppath, head, 2376 self.ppath, head, "__pycache__", "{0}.*{1}".format(tail, ext)
2244 "__pycache__", "{0}.*{1}".format(tail, ext)) 2377 )
2245 for f in glob.glob(pat): 2378 for f in glob.glob(pat):
2246 s2t(f) 2379 s2t(f)
2247 except OSError as err: 2380 except OSError as err:
2248 EricMessageBox.critical( 2381 EricMessageBox.critical(
2249 self.ui, 2382 self.ui,
2250 self.tr("Delete file"), 2383 self.tr("Delete file"),
2251 self.tr( 2384 self.tr(
2252 "<p>The selected file <b>{0}</b> could not be" 2385 "<p>The selected file <b>{0}</b> could not be"
2253 " deleted.</p><p>Reason: {1}</p>").format( 2386 " deleted.</p><p>Reason: {1}</p>"
2254 fn, str(err))) 2387 ).format(fn, str(err)),
2388 )
2255 return False 2389 return False
2256 2390
2257 self.removeFile(fn) 2391 self.removeFile(fn)
2258 if ext == '.ui': 2392 if ext == ".ui":
2259 self.removeFile(fn + '.h') 2393 self.removeFile(fn + ".h")
2260 return True 2394 return True
2261 2395
2262 def deleteDirectory(self, dn): 2396 def deleteDirectory(self, dn):
2263 """ 2397 """
2264 Public method to delete a directory from the project directory. 2398 Public method to delete a directory from the project directory.
2265 2399
2266 @param dn directory name to be removed from the project 2400 @param dn directory name to be removed from the project
2267 @return flag indicating success (boolean) 2401 @return flag indicating success (boolean)
2268 """ 2402 """
2269 if not os.path.isabs(dn): 2403 if not os.path.isabs(dn):
2270 dn = os.path.join(self.ppath, dn) 2404 dn = os.path.join(self.ppath, dn)
2271 try: 2405 try:
2272 try: 2406 try:
2273 from send2trash import send2trash 2407 from send2trash import send2trash
2408
2274 send2trash(dn) 2409 send2trash(dn)
2275 except ImportError: 2410 except ImportError:
2276 shutil.rmtree(dn, True) 2411 shutil.rmtree(dn, True)
2277 except OSError as err: 2412 except OSError as err:
2278 EricMessageBox.critical( 2413 EricMessageBox.critical(
2279 self.ui, 2414 self.ui,
2280 self.tr("Delete directory"), 2415 self.tr("Delete directory"),
2281 self.tr( 2416 self.tr(
2282 "<p>The selected directory <b>{0}</b> could not be" 2417 "<p>The selected directory <b>{0}</b> could not be"
2283 " deleted.</p><p>Reason: {1}</p>").format(dn, str(err))) 2418 " deleted.</p><p>Reason: {1}</p>"
2419 ).format(dn, str(err)),
2420 )
2284 return False 2421 return False
2285 2422
2286 self.removeDirectory(dn) 2423 self.removeDirectory(dn)
2287 return True 2424 return True
2288 2425
2289 def hasEntry(self, fn): 2426 def hasEntry(self, fn):
2290 """ 2427 """
2291 Public method to check the project for a file. 2428 Public method to check the project for a file.
2292 2429
2293 @param fn filename to be checked (string) 2430 @param fn filename to be checked (string)
2294 @return flag indicating, if the project contains the file (boolean) 2431 @return flag indicating, if the project contains the file (boolean)
2295 """ 2432 """
2296 fn = self.getRelativePath(fn) 2433 fn = self.getRelativePath(fn)
2297 return ( 2434 return (
2298 fn in self.pdata["SOURCES"] or 2435 fn in self.pdata["SOURCES"]
2299 fn in self.pdata["FORMS"] or 2436 or fn in self.pdata["FORMS"]
2300 fn in self.pdata["INTERFACES"] or 2437 or fn in self.pdata["INTERFACES"]
2301 fn in self.pdata["PROTOCOLS"] or 2438 or fn in self.pdata["PROTOCOLS"]
2302 fn in self.pdata["RESOURCES"] or 2439 or fn in self.pdata["RESOURCES"]
2303 fn in self.pdata["OTHERS"] 2440 or fn in self.pdata["OTHERS"]
2304 ) 2441 )
2305 2442
2306 def createNewProject(self): 2443 def createNewProject(self):
2307 """ 2444 """
2308 Public slot to built a new project. 2445 Public slot to built a new project.
2309 2446
2310 This method displays the new project dialog and initializes 2447 This method displays the new project dialog and initializes
2311 the project object with the data entered. 2448 the project object with the data entered.
2312 """ 2449 """
2313 if not self.checkDirty(): 2450 if not self.checkDirty():
2314 return 2451 return
2315 2452
2316 from .PropertiesDialog import PropertiesDialog 2453 from .PropertiesDialog import PropertiesDialog
2454
2317 dlg = PropertiesDialog(self, True) 2455 dlg = PropertiesDialog(self, True)
2318 if dlg.exec() == QDialog.DialogCode.Accepted: 2456 if dlg.exec() == QDialog.DialogCode.Accepted:
2319 self.closeProject() 2457 self.closeProject()
2320 dlg.storeData() 2458 dlg.storeData()
2321 self.pdata["VCS"] = 'None' 2459 self.pdata["VCS"] = "None"
2322 self.opened = True 2460 self.opened = True
2323 if not self.pdata["FILETYPES"]: 2461 if not self.pdata["FILETYPES"]:
2324 self.initFileTypes() 2462 self.initFileTypes()
2325 self.setDirty(True) 2463 self.setDirty(True)
2326 self.closeAct.setEnabled(True) 2464 self.closeAct.setEnabled(True)
2337 self.menuCheckAct.setEnabled(True) 2475 self.menuCheckAct.setEnabled(True)
2338 self.menuShowAct.setEnabled(True) 2476 self.menuShowAct.setEnabled(True)
2339 self.menuDiagramAct.setEnabled(True) 2477 self.menuDiagramAct.setEnabled(True)
2340 self.menuApidocAct.setEnabled(True) 2478 self.menuApidocAct.setEnabled(True)
2341 self.menuPackagersAct.setEnabled(True) 2479 self.menuPackagersAct.setEnabled(True)
2342 self.pluginGrp.setEnabled( 2480 self.pluginGrp.setEnabled(self.pdata["PROJECTTYPE"] in ["E7Plugin"])
2343 self.pdata["PROJECTTYPE"] in ["E7Plugin"]) 2481 self.addLanguageAct.setEnabled(bool(self.pdata["TRANSLATIONPATTERN"]))
2344 self.addLanguageAct.setEnabled( 2482 self.makeGrp.setEnabled(self.pdata["MAKEPARAMS"]["MakeEnabled"])
2345 bool(self.pdata["TRANSLATIONPATTERN"])) 2483 self.menuMakeAct.setEnabled(self.pdata["MAKEPARAMS"]["MakeEnabled"])
2346 self.makeGrp.setEnabled(
2347 self.pdata["MAKEPARAMS"]["MakeEnabled"])
2348 self.menuMakeAct.setEnabled(
2349 self.pdata["MAKEPARAMS"]["MakeEnabled"])
2350 self.menuOtherToolsAct.setEnabled(True) 2484 self.menuOtherToolsAct.setEnabled(True)
2351 self.menuFormattingAct.setEnabled(True) 2485 self.menuFormattingAct.setEnabled(True)
2352 2486
2353 self.projectAboutToBeCreated.emit() 2487 self.projectAboutToBeCreated.emit()
2354 2488
2355 hashStr = str(QCryptographicHash.hash( 2489 hashStr = str(
2356 QByteArray(self.ppath.encode("utf-8")), 2490 QCryptographicHash.hash(
2357 QCryptographicHash.Algorithm.Sha1).toHex(), 2491 QByteArray(self.ppath.encode("utf-8")),
2358 encoding="utf-8") 2492 QCryptographicHash.Algorithm.Sha1,
2493 ).toHex(),
2494 encoding="utf-8",
2495 )
2359 self.pdata["HASH"] = hashStr 2496 self.pdata["HASH"] = hashStr
2360 2497
2361 if self.pdata["PROGLANGUAGE"] == "MicroPython": 2498 if self.pdata["PROGLANGUAGE"] == "MicroPython":
2362 # change the lexer association for *.py files 2499 # change the lexer association for *.py files
2363 self.pdata["LEXERASSOCS"] = { 2500 self.pdata["LEXERASSOCS"] = {
2364 "*.py": "MicroPython", 2501 "*.py": "MicroPython",
2365 } 2502 }
2366 2503
2367 # create the project directory if it doesn't exist already 2504 # create the project directory if it doesn't exist already
2368 if not os.path.isdir(self.ppath): 2505 if not os.path.isdir(self.ppath):
2369 try: 2506 try:
2370 os.makedirs(self.ppath) 2507 os.makedirs(self.ppath)
2371 except OSError: 2508 except OSError:
2372 EricMessageBox.critical( 2509 EricMessageBox.critical(
2373 self.ui, 2510 self.ui,
2374 self.tr("Create project directory"), 2511 self.tr("Create project directory"),
2375 self.tr( 2512 self.tr(
2376 "<p>The project directory <b>{0}</b> could not" 2513 "<p>The project directory <b>{0}</b> could not"
2377 " be created.</p>") 2514 " be created.</p>"
2378 .format(self.ppath)) 2515 ).format(self.ppath),
2516 )
2379 self.vcs = self.initVCS() 2517 self.vcs = self.initVCS()
2380 return 2518 return
2381 2519
2382 # create an empty __init__.py file to make it a Python package 2520 # create an empty __init__.py file to make it a Python package
2383 # (only for Python and Python3) 2521 # (only for Python and Python3)
2384 if self.pdata["PROGLANGUAGE"] in [ 2522 if self.pdata["PROGLANGUAGE"] in ["Python3", "MicroPython"]:
2385 "Python3", "MicroPython"
2386 ]:
2387 fn = os.path.join(self.ppath, "__init__.py") 2523 fn = os.path.join(self.ppath, "__init__.py")
2388 with open(fn, "w", encoding="utf-8"): 2524 with open(fn, "w", encoding="utf-8"):
2389 pass 2525 pass
2390 self.appendFile(fn, True) 2526 self.appendFile(fn, True)
2391 2527
2392 # create an empty main script file, if a name was given 2528 # create an empty main script file, if a name was given
2393 if self.pdata["MAINSCRIPT"]: 2529 if self.pdata["MAINSCRIPT"]:
2394 if not os.path.isabs(self.pdata["MAINSCRIPT"]): 2530 if not os.path.isabs(self.pdata["MAINSCRIPT"]):
2395 ms = os.path.join( 2531 ms = os.path.join(self.ppath, self.pdata["MAINSCRIPT"])
2396 self.ppath, self.pdata["MAINSCRIPT"])
2397 else: 2532 else:
2398 ms = self.pdata["MAINSCRIPT"] 2533 ms = self.pdata["MAINSCRIPT"]
2399 os.makedirs(os.path.dirname(ms), exist_ok=True) 2534 os.makedirs(os.path.dirname(ms), exist_ok=True)
2400 with open(ms, "w"): 2535 with open(ms, "w"):
2401 pass 2536 pass
2402 self.appendFile(ms, True) 2537 self.appendFile(ms, True)
2403 2538
2404 if self.pdata["MAKEPARAMS"]["MakeEnabled"]: 2539 if self.pdata["MAKEPARAMS"]["MakeEnabled"]:
2405 mf = self.pdata["MAKEPARAMS"]["MakeFile"] 2540 mf = self.pdata["MAKEPARAMS"]["MakeFile"]
2406 if mf: 2541 if mf:
2407 if not os.path.isabs(mf): 2542 if not os.path.isabs(mf):
2408 mf = os.path.join(self.ppath, mf) 2543 mf = os.path.join(self.ppath, mf)
2410 mf = os.path.join(self.ppath, Project.DefaultMakefile) 2545 mf = os.path.join(self.ppath, Project.DefaultMakefile)
2411 os.makedirs(os.path.dirname(mf), exist_ok=True) 2546 os.makedirs(os.path.dirname(mf), exist_ok=True)
2412 with open(mf, "w"): 2547 with open(mf, "w"):
2413 pass 2548 pass
2414 self.appendFile(mf) 2549 self.appendFile(mf)
2415 2550
2416 tpd = os.path.join(self.ppath, self.translationsRoot) 2551 tpd = os.path.join(self.ppath, self.translationsRoot)
2417 if not self.translationsRoot.endswith(os.sep): 2552 if not self.translationsRoot.endswith(os.sep):
2418 tpd = os.path.dirname(tpd) 2553 tpd = os.path.dirname(tpd)
2419 if not os.path.isdir(tpd): 2554 if not os.path.isdir(tpd):
2420 os.makedirs(tpd, exist_ok=True) 2555 os.makedirs(tpd, exist_ok=True)
2421 if self.pdata["TRANSLATIONSBINPATH"]: 2556 if self.pdata["TRANSLATIONSBINPATH"]:
2422 tpd = os.path.join( 2557 tpd = os.path.join(self.ppath, self.pdata["TRANSLATIONSBINPATH"])
2423 self.ppath, self.pdata["TRANSLATIONSBINPATH"])
2424 if not os.path.isdir(tpd): 2558 if not os.path.isdir(tpd):
2425 os.makedirs(tpd, exist_ok=True) 2559 os.makedirs(tpd, exist_ok=True)
2426 2560
2427 # create management directory if not present 2561 # create management directory if not present
2428 self.createProjectManagementDir() 2562 self.createProjectManagementDir()
2429 2563
2430 self.saveProject() 2564 self.saveProject()
2431 addAllToVcs = True 2565 addAllToVcs = True
2432 else: 2566 else:
2433 try: 2567 try:
2434 # create management directory if not present 2568 # create management directory if not present
2437 EricMessageBox.critical( 2571 EricMessageBox.critical(
2438 self.ui, 2572 self.ui,
2439 self.tr("Create project management directory"), 2573 self.tr("Create project management directory"),
2440 self.tr( 2574 self.tr(
2441 "<p>The project directory <b>{0}</b> is not" 2575 "<p>The project directory <b>{0}</b> is not"
2442 " writable.</p>") 2576 " writable.</p>"
2443 .format(self.ppath)) 2577 ).format(self.ppath),
2578 )
2444 return 2579 return
2445 2580
2446 if self.pdata["MAINSCRIPT"]: 2581 if self.pdata["MAINSCRIPT"]:
2447 if not os.path.isabs(self.pdata["MAINSCRIPT"]): 2582 if not os.path.isabs(self.pdata["MAINSCRIPT"]):
2448 ms = os.path.join( 2583 ms = os.path.join(self.ppath, self.pdata["MAINSCRIPT"])
2449 self.ppath, self.pdata["MAINSCRIPT"])
2450 else: 2584 else:
2451 ms = self.pdata["MAINSCRIPT"] 2585 ms = self.pdata["MAINSCRIPT"]
2452 if not os.path.exists(ms): 2586 if not os.path.exists(ms):
2453 try: 2587 try:
2454 os.makedirs(os.path.dirname(ms)) 2588 os.makedirs(os.path.dirname(ms))
2458 EricMessageBox.critical( 2592 EricMessageBox.critical(
2459 self.ui, 2593 self.ui,
2460 self.tr("Create main script"), 2594 self.tr("Create main script"),
2461 self.tr( 2595 self.tr(
2462 "<p>The mainscript <b>{0}</b> could not" 2596 "<p>The mainscript <b>{0}</b> could not"
2463 " be created.<br/>Reason: {1}</p>") 2597 " be created.<br/>Reason: {1}</p>"
2464 .format(ms, str(err))) 2598 ).format(ms, str(err)),
2599 )
2465 self.appendFile(ms, True) 2600 self.appendFile(ms, True)
2466 else: 2601 else:
2467 ms = "" 2602 ms = ""
2468 2603
2469 if self.pdata["MAKEPARAMS"]["MakeEnabled"]: 2604 if self.pdata["MAKEPARAMS"]["MakeEnabled"]:
2470 mf = self.pdata["MAKEPARAMS"]["MakeFile"] 2605 mf = self.pdata["MAKEPARAMS"]["MakeFile"]
2471 if mf: 2606 if mf:
2472 if not os.path.isabs(mf): 2607 if not os.path.isabs(mf):
2473 mf = os.path.join(self.ppath, mf) 2608 mf = os.path.join(self.ppath, mf)
2482 EricMessageBox.critical( 2617 EricMessageBox.critical(
2483 self.ui, 2618 self.ui,
2484 self.tr("Create Makefile"), 2619 self.tr("Create Makefile"),
2485 self.tr( 2620 self.tr(
2486 "<p>The makefile <b>{0}</b> could not" 2621 "<p>The makefile <b>{0}</b> could not"
2487 " be created.<br/>Reason: {1}</p>") 2622 " be created.<br/>Reason: {1}</p>"
2488 .format(mf, str(err))) 2623 ).format(mf, str(err)),
2624 )
2489 self.appendFile(mf) 2625 self.appendFile(mf)
2490 2626
2491 # add existing files to the project 2627 # add existing files to the project
2492 res = EricMessageBox.yesNo( 2628 res = EricMessageBox.yesNo(
2493 self.ui, 2629 self.ui,
2494 self.tr("New Project"), 2630 self.tr("New Project"),
2495 self.tr("""Add existing files to the project?"""), 2631 self.tr("""Add existing files to the project?"""),
2496 yesDefault=True) 2632 yesDefault=True,
2633 )
2497 if res: 2634 if res:
2498 self.newProjectAddFiles(ms) 2635 self.newProjectAddFiles(ms)
2499 addAllToVcs = res 2636 addAllToVcs = res
2500 # create an empty __init__.py file to make it a Python package 2637 # create an empty __init__.py file to make it a Python package
2501 # if none exists (only for Python and Python3) 2638 # if none exists (only for Python and Python3)
2502 if self.pdata["PROGLANGUAGE"] in [ 2639 if self.pdata["PROGLANGUAGE"] in ["Python3", "MicroPython"]:
2503 "Python3", "MicroPython"
2504 ]:
2505 fn = os.path.join(self.ppath, "__init__.py") 2640 fn = os.path.join(self.ppath, "__init__.py")
2506 if not os.path.exists(fn): 2641 if not os.path.exists(fn):
2507 with open(fn, "w", encoding="utf-8"): 2642 with open(fn, "w", encoding="utf-8"):
2508 pass 2643 pass
2509 self.appendFile(fn, True) 2644 self.appendFile(fn, True)
2510 self.saveProject() 2645 self.saveProject()
2511 2646
2512 # check, if the existing project directory is already under 2647 # check, if the existing project directory is already under
2513 # VCS control 2648 # VCS control
2514 pluginManager = ericApp().getObject("PluginManager") 2649 pluginManager = ericApp().getObject("PluginManager")
2515 for indicator, vcsData in list( 2650 for indicator, vcsData in list(
2516 pluginManager.getVcsSystemIndicators().items()): 2651 pluginManager.getVcsSystemIndicators().items()
2652 ):
2517 if os.path.exists(os.path.join(self.ppath, indicator)): 2653 if os.path.exists(os.path.join(self.ppath, indicator)):
2518 if len(vcsData) > 1: 2654 if len(vcsData) > 1:
2519 vcsList = [] 2655 vcsList = []
2520 for _vcsSystemStr, vcsSystemDisplay in vcsData: 2656 for _vcsSystemStr, vcsSystemDisplay in vcsData:
2521 vcsList.append(vcsSystemDisplay) 2657 vcsList.append(vcsSystemDisplay)
2522 res, vcs_ok = QInputDialog.getItem( 2658 res, vcs_ok = QInputDialog.getItem(
2523 None, 2659 None,
2524 self.tr("New Project"), 2660 self.tr("New Project"),
2525 self.tr("Select Version Control System"), 2661 self.tr("Select Version Control System"),
2526 vcsList, 2662 vcsList,
2527 0, False) 2663 0,
2664 False,
2665 )
2528 if vcs_ok: 2666 if vcs_ok:
2529 for vcsSystemStr, vcsSystemDisplay in vcsData: 2667 for vcsSystemStr, vcsSystemDisplay in vcsData:
2530 if res == vcsSystemDisplay: 2668 if res == vcsSystemDisplay:
2531 vcsSystem = vcsSystemStr 2669 vcsSystem = vcsSystemStr
2532 break 2670 break
2545 vcores = EricMessageBox.yesNo( 2683 vcores = EricMessageBox.yesNo(
2546 self.ui, 2684 self.ui,
2547 self.tr("New Project"), 2685 self.tr("New Project"),
2548 self.tr( 2686 self.tr(
2549 """Would you like to edit the VCS""" 2687 """Would you like to edit the VCS"""
2550 """ command options?""")) 2688 """ command options?"""
2689 ),
2690 )
2551 else: 2691 else:
2552 vcores = False 2692 vcores = False
2553 if vcores: 2693 if vcores:
2554 from VCS.CommandOptionsDialog import ( 2694 from VCS.CommandOptionsDialog import (
2555 VcsCommandOptionsDialog 2695 VcsCommandOptionsDialog,
2556 ) 2696 )
2697
2557 codlg = VcsCommandOptionsDialog(self.vcs) 2698 codlg = VcsCommandOptionsDialog(self.vcs)
2558 if codlg.exec() == QDialog.DialogCode.Accepted: 2699 if codlg.exec() == QDialog.DialogCode.Accepted:
2559 self.vcs.vcsSetOptions(codlg.getOptions()) 2700 self.vcs.vcsSetOptions(codlg.getOptions())
2560 # add project file to repository 2701 # add project file to repository
2561 if res == 0: 2702 if res == 0:
2562 apres = EricMessageBox.yesNo( 2703 apres = EricMessageBox.yesNo(
2563 self.ui, 2704 self.ui,
2564 self.tr("New project"), 2705 self.tr("New project"),
2565 self.tr( 2706 self.tr(
2566 "Shall the project file be added" 2707 "Shall the project file be added"
2567 " to the repository?"), 2708 " to the repository?"
2568 yesDefault=True) 2709 ),
2710 yesDefault=True,
2711 )
2569 if apres: 2712 if apres:
2570 self.saveProject() 2713 self.saveProject()
2571 self.vcs.vcsAdd(self.pfile) 2714 self.vcs.vcsAdd(self.pfile)
2572 else: 2715 else:
2573 self.pdata["VCS"] = 'None' 2716 self.pdata["VCS"] = "None"
2574 self.saveProject() 2717 self.saveProject()
2575 break 2718 break
2576 2719
2577 # put the project under VCS control 2720 # put the project under VCS control
2578 if ( 2721 if self.vcs is None and self.vcsSoftwareAvailable() and self.vcsRequested:
2579 self.vcs is None and
2580 self.vcsSoftwareAvailable() and
2581 self.vcsRequested
2582 ):
2583 vcsSystemsDict = ( 2722 vcsSystemsDict = (
2584 ericApp().getObject("PluginManager") 2723 ericApp()
2724 .getObject("PluginManager")
2585 .getPluginDisplayStrings("version_control") 2725 .getPluginDisplayStrings("version_control")
2586 ) 2726 )
2587 vcsSystemsDisplay = [self.tr("None")] 2727 vcsSystemsDisplay = [self.tr("None")]
2588 keys = sorted(vcsSystemsDict.keys()) 2728 keys = sorted(vcsSystemsDict.keys())
2589 for key in keys: 2729 for key in keys:
2590 vcsSystemsDisplay.append(vcsSystemsDict[key]) 2730 vcsSystemsDisplay.append(vcsSystemsDict[key])
2591 vcsSelected, ok = QInputDialog.getItem( 2731 vcsSelected, ok = QInputDialog.getItem(
2592 None, 2732 None,
2593 self.tr("New Project"), 2733 self.tr("New Project"),
2594 self.tr( 2734 self.tr("Select version control system for the project"),
2595 "Select version control system for the project"),
2596 vcsSystemsDisplay, 2735 vcsSystemsDisplay,
2597 0, False) 2736 0,
2737 False,
2738 )
2598 if ok and vcsSelected != self.tr("None"): 2739 if ok and vcsSelected != self.tr("None"):
2599 for vcsSystem, vcsSystemDisplay in vcsSystemsDict.items(): 2740 for vcsSystem, vcsSystemDisplay in vcsSystemsDict.items():
2600 if vcsSystemDisplay == vcsSelected: 2741 if vcsSystemDisplay == vcsSelected:
2601 self.pdata["VCS"] = vcsSystem 2742 self.pdata["VCS"] = vcsSystem
2602 break 2743 break
2603 else: 2744 else:
2604 self.pdata["VCS"] = 'None' 2745 self.pdata["VCS"] = "None"
2605 else: 2746 else:
2606 self.pdata["VCS"] = 'None' 2747 self.pdata["VCS"] = "None"
2607 self.vcs = self.initVCS() 2748 self.vcs = self.initVCS()
2608 if self.vcs is not None: 2749 if self.vcs is not None:
2609 vcsdlg = self.vcs.vcsOptionsDialog(self, self.name) 2750 vcsdlg = self.vcs.vcsOptionsDialog(self, self.name)
2610 if vcsdlg.exec() == QDialog.DialogCode.Accepted: 2751 if vcsdlg.exec() == QDialog.DialogCode.Accepted:
2611 vcsDataDict = vcsdlg.getData() 2752 vcsDataDict = vcsdlg.getData()
2612 else: 2753 else:
2613 self.pdata["VCS"] = 'None' 2754 self.pdata["VCS"] = "None"
2614 self.vcs = self.initVCS() 2755 self.vcs = self.initVCS()
2615 self.setDirty(True) 2756 self.setDirty(True)
2616 if self.vcs is not None: 2757 if self.vcs is not None:
2617 # edit VCS command options 2758 # edit VCS command options
2618 if self.vcs.vcsSupportCommandOptions(): 2759 if self.vcs.vcsSupportCommandOptions():
2619 vcores = EricMessageBox.yesNo( 2760 vcores = EricMessageBox.yesNo(
2620 self.ui, 2761 self.ui,
2621 self.tr("New Project"), 2762 self.tr("New Project"),
2622 self.tr( 2763 self.tr(
2623 """Would you like to edit the VCS command""" 2764 """Would you like to edit the VCS command"""
2624 """ options?""")) 2765 """ options?"""
2766 ),
2767 )
2625 else: 2768 else:
2626 vcores = False 2769 vcores = False
2627 if vcores: 2770 if vcores:
2628 from VCS.CommandOptionsDialog import ( 2771 from VCS.CommandOptionsDialog import VcsCommandOptionsDialog
2629 VcsCommandOptionsDialog 2772
2630 )
2631 codlg = VcsCommandOptionsDialog(self.vcs) 2773 codlg = VcsCommandOptionsDialog(self.vcs)
2632 if codlg.exec() == QDialog.DialogCode.Accepted: 2774 if codlg.exec() == QDialog.DialogCode.Accepted:
2633 self.vcs.vcsSetOptions(codlg.getOptions()) 2775 self.vcs.vcsSetOptions(codlg.getOptions())
2634 2776
2635 # create the project in the VCS 2777 # create the project in the VCS
2636 self.vcs.vcsSetDataFromDict(vcsDataDict) 2778 self.vcs.vcsSetDataFromDict(vcsDataDict)
2637 self.saveProject() 2779 self.saveProject()
2638 self.vcs.vcsConvertProject(vcsDataDict, self, 2780 self.vcs.vcsConvertProject(vcsDataDict, self, addAll=addAllToVcs)
2639 addAll=addAllToVcs)
2640 else: 2781 else:
2641 self.newProjectHooks.emit() 2782 self.newProjectHooks.emit()
2642 self.newProject.emit() 2783 self.newProject.emit()
2643 2784
2644 else: 2785 else:
2645 self.newProjectHooks.emit() 2786 self.newProjectHooks.emit()
2646 self.newProject.emit() 2787 self.newProject.emit()
2647 2788
2648 def newProjectAddFiles(self, mainscript): 2789 def newProjectAddFiles(self, mainscript):
2649 """ 2790 """
2650 Public method to add files to a new project. 2791 Public method to add files to a new project.
2651 2792
2652 @param mainscript name of the mainscript (string) 2793 @param mainscript name of the mainscript (string)
2653 """ 2794 """
2654 # Show the file type associations for the user to change 2795 # Show the file type associations for the user to change
2655 self.__showFiletypeAssociations() 2796 self.__showFiletypeAssociations()
2656 2797
2657 with EricOverrideCursor(): 2798 with EricOverrideCursor():
2658 # search the project directory for files with known extensions 2799 # search the project directory for files with known extensions
2659 filespecs = list(self.pdata["FILETYPES"].keys()) 2800 filespecs = list(self.pdata["FILETYPES"].keys())
2660 for filespec in filespecs: 2801 for filespec in filespecs:
2661 files = Utilities.direntries(self.ppath, True, filespec) 2802 files = Utilities.direntries(self.ppath, True, filespec)
2662 for file in files: 2803 for file in files:
2663 self.appendFile(file) 2804 self.appendFile(file)
2664 2805
2665 # special handling for translation files 2806 # special handling for translation files
2666 if self.translationsRoot: 2807 if self.translationsRoot:
2667 tpd = os.path.join(self.ppath, self.translationsRoot) 2808 tpd = os.path.join(self.ppath, self.translationsRoot)
2668 if not self.translationsRoot.endswith(os.sep): 2809 if not self.translationsRoot.endswith(os.sep):
2669 tpd = os.path.dirname(tpd) 2810 tpd = os.path.dirname(tpd)
2673 if self.pdata["TRANSLATIONPATTERN"]: 2814 if self.pdata["TRANSLATIONPATTERN"]:
2674 pattern = os.path.basename(self.pdata["TRANSLATIONPATTERN"]) 2815 pattern = os.path.basename(self.pdata["TRANSLATIONPATTERN"])
2675 if "%language%" in pattern: 2816 if "%language%" in pattern:
2676 pattern = pattern.replace("%language%", "*") 2817 pattern = pattern.replace("%language%", "*")
2677 else: 2818 else:
2678 tpd = self.pdata["TRANSLATIONPATTERN"].split( 2819 tpd = self.pdata["TRANSLATIONPATTERN"].split("%language%")[0]
2679 "%language%")[0]
2680 else: 2820 else:
2681 pattern = "*.ts" 2821 pattern = "*.ts"
2682 tslist.extend(Utilities.direntries(tpd, True, pattern)) 2822 tslist.extend(Utilities.direntries(tpd, True, pattern))
2683 pattern = self.__binaryTranslationFile(pattern) 2823 pattern = self.__binaryTranslationFile(pattern)
2684 if pattern: 2824 if pattern:
2685 tslist.extend(Utilities.direntries(tpd, True, pattern)) 2825 tslist.extend(Utilities.direntries(tpd, True, pattern))
2686 if tslist: 2826 if tslist:
2687 if '_' in os.path.basename(tslist[0]): 2827 if "_" in os.path.basename(tslist[0]):
2688 # the first entry determines the mainscript name 2828 # the first entry determines the mainscript name
2689 mainscriptname = ( 2829 mainscriptname = (
2690 os.path.splitext(mainscript)[0] or 2830 os.path.splitext(mainscript)[0]
2691 os.path.basename(tslist[0]).split('_')[0] 2831 or os.path.basename(tslist[0]).split("_")[0]
2692 ) 2832 )
2693 self.pdata["TRANSLATIONPATTERN"] = os.path.join( 2833 self.pdata["TRANSLATIONPATTERN"] = os.path.join(
2694 os.path.dirname(tslist[0]), 2834 os.path.dirname(tslist[0]),
2695 "{0}_%language%{1}".format( 2835 "{0}_%language%{1}".format(
2696 os.path.basename(tslist[0]).split('_')[0], 2836 os.path.basename(tslist[0]).split("_")[0],
2697 os.path.splitext(tslist[0])[1])) 2837 os.path.splitext(tslist[0])[1],
2838 ),
2839 )
2698 else: 2840 else:
2699 mainscriptname = "" 2841 mainscriptname = ""
2700 pattern, ok = QInputDialog.getText( 2842 pattern, ok = QInputDialog.getText(
2701 None, 2843 None,
2702 self.tr("Translation Pattern"), 2844 self.tr("Translation Pattern"),
2703 self.tr( 2845 self.tr(
2704 "Enter the path pattern for translation files " 2846 "Enter the path pattern for translation files "
2705 "(use '%language%' in place of the language" 2847 "(use '%language%' in place of the language"
2706 " code):"), 2848 " code):"
2849 ),
2707 QLineEdit.EchoMode.Normal, 2850 QLineEdit.EchoMode.Normal,
2708 tslist[0]) 2851 tslist[0],
2852 )
2709 if pattern: 2853 if pattern:
2710 self.pdata["TRANSLATIONPATTERN"] = pattern 2854 self.pdata["TRANSLATIONPATTERN"] = pattern
2711 if self.pdata["TRANSLATIONPATTERN"]: 2855 if self.pdata["TRANSLATIONPATTERN"]:
2712 self.pdata["TRANSLATIONPATTERN"] = self.getRelativePath( 2856 self.pdata["TRANSLATIONPATTERN"] = self.getRelativePath(
2713 self.pdata["TRANSLATIONPATTERN"]) 2857 self.pdata["TRANSLATIONPATTERN"]
2858 )
2714 pattern = self.pdata["TRANSLATIONPATTERN"].replace( 2859 pattern = self.pdata["TRANSLATIONPATTERN"].replace(
2715 "%language%", "*") 2860 "%language%", "*"
2861 )
2716 for ts in tslist: 2862 for ts in tslist:
2717 if fnmatch.fnmatch(ts, pattern): 2863 if fnmatch.fnmatch(ts, pattern):
2718 self.pdata["TRANSLATIONS"].append(ts) 2864 self.pdata["TRANSLATIONS"].append(ts)
2719 self.projectLanguageAdded.emit(ts) 2865 self.projectLanguageAdded.emit(ts)
2720 if self.pdata["TRANSLATIONSBINPATH"]: 2866 if self.pdata["TRANSLATIONSBINPATH"]:
2721 tpd = os.path.join(self.ppath, 2867 tpd = os.path.join(
2722 self.pdata["TRANSLATIONSBINPATH"]) 2868 self.ppath, self.pdata["TRANSLATIONSBINPATH"]
2869 )
2723 pattern = os.path.basename( 2870 pattern = os.path.basename(
2724 self.pdata["TRANSLATIONPATTERN"]).replace( 2871 self.pdata["TRANSLATIONPATTERN"]
2725 "%language%", "*") 2872 ).replace("%language%", "*")
2726 pattern = self.__binaryTranslationFile(pattern) 2873 pattern = self.__binaryTranslationFile(pattern)
2727 qmlist = Utilities.direntries(tpd, True, pattern) 2874 qmlist = Utilities.direntries(tpd, True, pattern)
2728 for qm in qmlist: 2875 for qm in qmlist:
2729 self.pdata["TRANSLATIONS"].append(qm) 2876 self.pdata["TRANSLATIONS"].append(qm)
2730 self.projectLanguageAdded.emit(qm) 2877 self.projectLanguageAdded.emit(qm)
2731 if not self.pdata["MAINSCRIPT"] and bool(mainscriptname): 2878 if not self.pdata["MAINSCRIPT"] and bool(mainscriptname):
2732 if self.pdata["PROGLANGUAGE"] in [ 2879 if self.pdata["PROGLANGUAGE"] in ["Python3", "MicroPython"]:
2733 "Python3", "MicroPython" 2880 self.pdata["MAINSCRIPT"] = "{0}.py".format(mainscriptname)
2734 ]:
2735 self.pdata["MAINSCRIPT"] = '{0}.py'.format(
2736 mainscriptname)
2737 elif self.pdata["PROGLANGUAGE"] == "Ruby": 2881 elif self.pdata["PROGLANGUAGE"] == "Ruby":
2738 self.pdata["MAINSCRIPT"] = '{0}.rb'.format( 2882 self.pdata["MAINSCRIPT"] = "{0}.rb".format(mainscriptname)
2739 mainscriptname)
2740 self.setDirty(True) 2883 self.setDirty(True)
2741 2884
2742 def __showProperties(self): 2885 def __showProperties(self):
2743 """ 2886 """
2744 Private slot to display the properties dialog. 2887 Private slot to display the properties dialog.
2745 """ 2888 """
2746 from .PropertiesDialog import PropertiesDialog 2889 from .PropertiesDialog import PropertiesDialog
2890
2747 dlg = PropertiesDialog(self, False) 2891 dlg = PropertiesDialog(self, False)
2748 if dlg.exec() == QDialog.DialogCode.Accepted: 2892 if dlg.exec() == QDialog.DialogCode.Accepted:
2749 projectType = self.pdata["PROJECTTYPE"] 2893 projectType = self.pdata["PROJECTTYPE"]
2750 dlg.storeData() 2894 dlg.storeData()
2751 self.setDirty(True) 2895 self.setDirty(True)
2752 if self.pdata["MAINSCRIPT"]: 2896 if self.pdata["MAINSCRIPT"]:
2753 if not os.path.isabs(self.pdata["MAINSCRIPT"]): 2897 if not os.path.isabs(self.pdata["MAINSCRIPT"]):
2754 ms = os.path.join( 2898 ms = os.path.join(self.ppath, self.pdata["MAINSCRIPT"])
2755 self.ppath, self.pdata["MAINSCRIPT"])
2756 else: 2899 else:
2757 ms = self.pdata["MAINSCRIPT"] 2900 ms = self.pdata["MAINSCRIPT"]
2758 if os.path.exists(ms): 2901 if os.path.exists(ms):
2759 self.appendFile(ms) 2902 self.appendFile(ms)
2760 2903
2761 if self.pdata["MAKEPARAMS"]["MakeEnabled"]: 2904 if self.pdata["MAKEPARAMS"]["MakeEnabled"]:
2762 mf = self.pdata["MAKEPARAMS"]["MakeFile"] 2905 mf = self.pdata["MAKEPARAMS"]["MakeFile"]
2763 if mf: 2906 if mf:
2764 if not os.path.isabs(mf): 2907 if not os.path.isabs(mf):
2765 mf = os.path.join(self.ppath, mf) 2908 mf = os.path.join(self.ppath, mf)
2773 EricMessageBox.critical( 2916 EricMessageBox.critical(
2774 self.ui, 2917 self.ui,
2775 self.tr("Create Makefile"), 2918 self.tr("Create Makefile"),
2776 self.tr( 2919 self.tr(
2777 "<p>The makefile <b>{0}</b> could not" 2920 "<p>The makefile <b>{0}</b> could not"
2778 " be created.<br/>Reason: {1}</p>") 2921 " be created.<br/>Reason: {1}</p>"
2779 .format(mf, str(err))) 2922 ).format(mf, str(err)),
2923 )
2780 self.appendFile(mf) 2924 self.appendFile(mf)
2781 2925
2782 if self.pdata["PROJECTTYPE"] != projectType: 2926 if self.pdata["PROJECTTYPE"] != projectType:
2783 # reinitialize filetype associations 2927 # reinitialize filetype associations
2784 self.initFileTypes() 2928 self.initFileTypes()
2785 2929
2786 if self.translationsRoot: 2930 if self.translationsRoot:
2787 tp = os.path.join(self.ppath, self.translationsRoot) 2931 tp = os.path.join(self.ppath, self.translationsRoot)
2788 if not self.translationsRoot.endswith(os.sep): 2932 if not self.translationsRoot.endswith(os.sep):
2789 tp = os.path.dirname(tp) 2933 tp = os.path.dirname(tp)
2790 else: 2934 else:
2791 tp = self.ppath 2935 tp = self.ppath
2792 if not os.path.isdir(tp): 2936 if not os.path.isdir(tp):
2793 os.makedirs(tp) 2937 os.makedirs(tp)
2794 if tp != self.ppath and tp not in self.subdirs: 2938 if tp != self.ppath and tp not in self.subdirs:
2795 self.subdirs.append(tp) 2939 self.subdirs.append(tp)
2796 2940
2797 if self.pdata["TRANSLATIONSBINPATH"]: 2941 if self.pdata["TRANSLATIONSBINPATH"]:
2798 tp = os.path.join( 2942 tp = os.path.join(self.ppath, self.pdata["TRANSLATIONSBINPATH"])
2799 self.ppath, self.pdata["TRANSLATIONSBINPATH"])
2800 if not os.path.isdir(tp): 2943 if not os.path.isdir(tp):
2801 os.makedirs(tp) 2944 os.makedirs(tp)
2802 if tp != self.ppath and tp not in self.subdirs: 2945 if tp != self.ppath and tp not in self.subdirs:
2803 self.subdirs.append(tp) 2946 self.subdirs.append(tp)
2804 2947
2805 self.pluginGrp.setEnabled( 2948 self.pluginGrp.setEnabled(self.pdata["PROJECTTYPE"] in ["E7Plugin"])
2806 self.pdata["PROJECTTYPE"] in ["E7Plugin"]) 2949
2807
2808 self.__model.projectPropertiesChanged() 2950 self.__model.projectPropertiesChanged()
2809 self.projectPropertiesChanged.emit() 2951 self.projectPropertiesChanged.emit()
2810 2952
2811 if self.pdata["PROJECTTYPE"] != projectType: 2953 if self.pdata["PROJECTTYPE"] != projectType:
2812 self.__reorganizeFiles() 2954 self.__reorganizeFiles()
2813 2955
2814 def __showUserProperties(self): 2956 def __showUserProperties(self):
2815 """ 2957 """
2816 Private slot to display the user specific properties dialog. 2958 Private slot to display the user specific properties dialog.
2817 """ 2959 """
2818 vcsSystem = self.pdata["VCS"] or None 2960 vcsSystem = self.pdata["VCS"] or None
2819 vcsSystemOverride = self.pudata["VCSOVERRIDE"] or None 2961 vcsSystemOverride = self.pudata["VCSOVERRIDE"] or None
2820 2962
2821 from .UserPropertiesDialog import UserPropertiesDialog 2963 from .UserPropertiesDialog import UserPropertiesDialog
2964
2822 dlg = UserPropertiesDialog(self) 2965 dlg = UserPropertiesDialog(self)
2823 if dlg.exec() == QDialog.DialogCode.Accepted: 2966 if dlg.exec() == QDialog.DialogCode.Accepted:
2824 dlg.storeData() 2967 dlg.storeData()
2825 2968
2826 if ( 2969 if (
2827 (self.pdata["VCS"] and 2970 (self.pdata["VCS"] and self.pdata["VCS"] != vcsSystem)
2828 self.pdata["VCS"] != vcsSystem) or 2971 or (
2829 (self.pudata["VCSOVERRIDE"] and 2972 self.pudata["VCSOVERRIDE"]
2830 self.pudata["VCSOVERRIDE"] != vcsSystemOverride) or 2973 and self.pudata["VCSOVERRIDE"] != vcsSystemOverride
2831 (vcsSystemOverride is not None and 2974 )
2832 not self.pudata["VCSOVERRIDE"]) 2975 or (vcsSystemOverride is not None and not self.pudata["VCSOVERRIDE"])
2833 ): 2976 ):
2834 # stop the VCS monitor thread and shutdown VCS 2977 # stop the VCS monitor thread and shutdown VCS
2835 if self.vcs is not None: 2978 if self.vcs is not None:
2836 self.vcs.stopStatusMonitor() 2979 self.vcs.stopStatusMonitor()
2837 self.vcs.vcsShutdown() 2980 self.vcs.vcsShutdown()
2841 # reinit VCS 2984 # reinit VCS
2842 self.vcs = self.initVCS() 2985 self.vcs = self.initVCS()
2843 # start the VCS monitor thread 2986 # start the VCS monitor thread
2844 self.__vcsConnectStatusMonitor() 2987 self.__vcsConnectStatusMonitor()
2845 self.reinitVCS.emit() 2988 self.reinitVCS.emit()
2846 2989
2847 if self.pudata["VCSSTATUSMONITORINTERVAL"]: 2990 if self.pudata["VCSSTATUSMONITORINTERVAL"]:
2848 self.setStatusMonitorInterval( 2991 self.setStatusMonitorInterval(self.pudata["VCSSTATUSMONITORINTERVAL"])
2849 self.pudata["VCSSTATUSMONITORINTERVAL"])
2850 else: 2992 else:
2851 self.setStatusMonitorInterval( 2993 self.setStatusMonitorInterval(
2852 Preferences.getVCS("StatusMonitorInterval")) 2994 Preferences.getVCS("StatusMonitorInterval")
2853 2995 )
2996
2854 def __showFiletypeAssociations(self): 2997 def __showFiletypeAssociations(self):
2855 """ 2998 """
2856 Private slot to display the filetype association dialog. 2999 Private slot to display the filetype association dialog.
2857 """ 3000 """
2858 from .FiletypeAssociationDialog import FiletypeAssociationDialog 3001 from .FiletypeAssociationDialog import FiletypeAssociationDialog
3002
2859 dlg = FiletypeAssociationDialog(self) 3003 dlg = FiletypeAssociationDialog(self)
2860 if dlg.exec() == QDialog.DialogCode.Accepted: 3004 if dlg.exec() == QDialog.DialogCode.Accepted:
2861 dlg.transferData() 3005 dlg.transferData()
2862 self.setDirty(True) 3006 self.setDirty(True)
2863 self.__reorganizeFiles() 3007 self.__reorganizeFiles()
2864 3008
2865 def getFiletypeAssociations(self, associationType): 3009 def getFiletypeAssociations(self, associationType):
2866 """ 3010 """
2867 Public method to get the list of file type associations for 3011 Public method to get the list of file type associations for
2868 the given association type. 3012 the given association type.
2869 3013
2870 @param associationType type of the association (one of FORMS, 3014 @param associationType type of the association (one of FORMS,
2871 INTERFACES, OTHERS, PROTOCOLS, RESOURCES, SOURCES, 3015 INTERFACES, OTHERS, PROTOCOLS, RESOURCES, SOURCES,
2872 TRANSLATIONS or __IGNORE__) 3016 TRANSLATIONS or __IGNORE__)
2873 @type str 3017 @type str
2874 @return list of file patterns for the given type 3018 @return list of file patterns for the given type
2875 @rtype list of str 3019 @rtype list of str
2876 """ 3020 """
2877 return [assoc for assoc in self.pdata["FILETYPES"] 3021 return [
2878 if self.pdata["FILETYPES"][assoc] == associationType] 3022 assoc
2879 3023 for assoc in self.pdata["FILETYPES"]
3024 if self.pdata["FILETYPES"][assoc] == associationType
3025 ]
3026
2880 def __showLexerAssociations(self): 3027 def __showLexerAssociations(self):
2881 """ 3028 """
2882 Private slot to display the lexer association dialog. 3029 Private slot to display the lexer association dialog.
2883 """ 3030 """
2884 from .LexerAssociationDialog import LexerAssociationDialog 3031 from .LexerAssociationDialog import LexerAssociationDialog
3032
2885 dlg = LexerAssociationDialog(self) 3033 dlg = LexerAssociationDialog(self)
2886 if dlg.exec() == QDialog.DialogCode.Accepted: 3034 if dlg.exec() == QDialog.DialogCode.Accepted:
2887 dlg.transferData() 3035 dlg.transferData()
2888 self.setDirty(True) 3036 self.setDirty(True)
2889 self.lexerAssociationsChanged.emit() 3037 self.lexerAssociationsChanged.emit()
2890 3038
2891 def getEditorLexerAssoc(self, filename): 3039 def getEditorLexerAssoc(self, filename):
2892 """ 3040 """
2893 Public method to retrieve a lexer association. 3041 Public method to retrieve a lexer association.
2894 3042
2895 @param filename filename used to determine the associated lexer 3043 @param filename filename used to determine the associated lexer
2896 language (string) 3044 language (string)
2897 @return the requested lexer language (string) 3045 @return the requested lexer language (string)
2898 """ 3046 """
2899 # try user settings first 3047 # try user settings first
2900 for pattern, language in list(self.pdata["LEXERASSOCS"].items()): 3048 for pattern, language in list(self.pdata["LEXERASSOCS"].items()):
2901 if fnmatch.fnmatch(filename, pattern): 3049 if fnmatch.fnmatch(filename, pattern):
2902 return language 3050 return language
2903 3051
2904 # try project type specific defaults next 3052 # try project type specific defaults next
2905 projectType = self.pdata["PROJECTTYPE"] 3053 projectType = self.pdata["PROJECTTYPE"]
2906 with contextlib.suppress(KeyError): 3054 with contextlib.suppress(KeyError):
2907 if self.__lexerAssociationCallbacks[projectType] is not None: 3055 if self.__lexerAssociationCallbacks[projectType] is not None:
2908 return self.__lexerAssociationCallbacks[projectType](filename) 3056 return self.__lexerAssociationCallbacks[projectType](filename)
2909 3057
2910 # return empty string to signal to use the global setting 3058 # return empty string to signal to use the global setting
2911 return "" 3059 return ""
2912 3060
2913 def getIgnorePatterns(self): 3061 def getIgnorePatterns(self):
2914 """ 3062 """
2915 Public method to get the list of file name patterns for files to be 3063 Public method to get the list of file name patterns for files to be
2916 ignored. 3064 ignored.
2917 3065
2918 @return list of ignore file name patterns 3066 @return list of ignore file name patterns
2919 @rtype list of str 3067 @rtype list of str
2920 """ 3068 """
2921 return self.getFiletypeAssociations("__IGNORE__") 3069 return self.getFiletypeAssociations("__IGNORE__")
2922 3070
2923 @pyqtSlot() 3071 @pyqtSlot()
2924 @pyqtSlot(str) 3072 @pyqtSlot(str)
2925 def openProject(self, fn=None, restoreSession=True, reopen=False): 3073 def openProject(self, fn=None, restoreSession=True, reopen=False):
2926 """ 3074 """
2927 Public slot to open a project. 3075 Public slot to open a project.
2928 3076
2929 @param fn optional filename of the project file to be read 3077 @param fn optional filename of the project file to be read
2930 @param restoreSession flag indicating to restore the project 3078 @param restoreSession flag indicating to restore the project
2931 session (boolean) 3079 session (boolean)
2932 @param reopen flag indicating a reopening of the project (boolean) 3080 @param reopen flag indicating a reopening of the project (boolean)
2933 """ 3081 """
2934 if not self.checkDirty(): 3082 if not self.checkDirty():
2935 return 3083 return
2936 3084
2937 if fn is None: 3085 if fn is None:
2938 fn = EricFileDialog.getOpenFileName( 3086 fn = EricFileDialog.getOpenFileName(
2939 self.parent(), 3087 self.parent(),
2940 self.tr("Open project"), 3088 self.tr("Open project"),
2941 Preferences.getMultiProject("Workspace") or 3089 Preferences.getMultiProject("Workspace") or Utilities.getHomeDir(),
2942 Utilities.getHomeDir(), 3090 self.tr("Project Files (*.epj);;XML Project Files (*.e4p)"),
2943 self.tr("Project Files (*.epj);;XML Project Files (*.e4p)")) 3091 )
2944 3092
2945 if fn and self.closeProject(): 3093 if fn and self.closeProject():
2946 with EricOverrideCursor(): 3094 with EricOverrideCursor():
2947 ok = self.__readProject(fn) 3095 ok = self.__readProject(fn)
2948 if ok: 3096 if ok:
2949 self.opened = True 3097 self.opened = True
2950 if not self.pdata["FILETYPES"]: 3098 if not self.pdata["FILETYPES"]:
2951 self.initFileTypes() 3099 self.initFileTypes()
2952 else: 3100 else:
2953 self.updateFileTypes() 3101 self.updateFileTypes()
2954 3102
2955 try: 3103 try:
2956 # create management directory if not present 3104 # create management directory if not present
2957 self.createProjectManagementDir() 3105 self.createProjectManagementDir()
2958 except OSError: 3106 except OSError:
2959 EricMessageBox.critical( 3107 EricMessageBox.critical(
2960 self.ui, 3108 self.ui,
2961 self.tr("Create project management directory"), 3109 self.tr("Create project management directory"),
2962 self.tr( 3110 self.tr(
2963 "<p>The project directory <b>{0}</b> is not" 3111 "<p>The project directory <b>{0}</b> is not"
2964 " writable.</p>") 3112 " writable.</p>"
2965 .format(self.ppath)) 3113 ).format(self.ppath),
3114 )
2966 return 3115 return
2967 3116
2968 # read a user specific project file 3117 # read a user specific project file
2969 self.__readUserProperties() 3118 self.__readUserProperties()
2970 3119
2971 with EricOverrideCursor(): 3120 with EricOverrideCursor():
2972 oldState = self.isDirty() 3121 oldState = self.isDirty()
2973 self.vcs = self.initVCS() 3122 self.vcs = self.initVCS()
2974 if self.vcs is None and self.isDirty() == oldState: 3123 if self.vcs is None and self.isDirty() == oldState:
2975 # check, if project is version controlled 3124 # check, if project is version controlled
2976 pluginManager = ericApp().getObject("PluginManager") 3125 pluginManager = ericApp().getObject("PluginManager")
2977 for indicator, vcsData in ( 3126 for (
2978 pluginManager.getVcsSystemIndicators().items() 3127 indicator,
2979 ): 3128 vcsData,
2980 if os.path.exists( 3129 ) in pluginManager.getVcsSystemIndicators().items():
2981 os.path.join(self.ppath, indicator)): 3130 if os.path.exists(os.path.join(self.ppath, indicator)):
2982 if len(vcsData) > 1: 3131 if len(vcsData) > 1:
2983 vcsList = [] 3132 vcsList = []
2984 for ( 3133 for (_vcsSystemStr, vcsSystemDisplay) in vcsData:
2985 _vcsSystemStr, vcsSystemDisplay
2986 ) in vcsData:
2987 vcsList.append(vcsSystemDisplay) 3134 vcsList.append(vcsSystemDisplay)
2988 with EricOverridenCursor(): 3135 with EricOverridenCursor():
2989 res, vcs_ok = QInputDialog.getItem( 3136 res, vcs_ok = QInputDialog.getItem(
2990 None, 3137 None,
2991 self.tr("New Project"), 3138 self.tr("New Project"),
2992 self.tr( 3139 self.tr("Select Version Control" " System"),
2993 "Select Version Control"
2994 " System"),
2995 vcsList, 3140 vcsList,
2996 0, False) 3141 0,
3142 False,
3143 )
2997 if vcs_ok: 3144 if vcs_ok:
2998 for ( 3145 for (vcsSystemStr, vcsSystemDisplay) in vcsData:
2999 vcsSystemStr, vcsSystemDisplay
3000 ) in vcsData:
3001 if res == vcsSystemDisplay: 3146 if res == vcsSystemDisplay:
3002 vcsSystem = vcsSystemStr 3147 vcsSystem = vcsSystemStr
3003 break 3148 break
3004 else: 3149 else:
3005 vcsSystem = "None" 3150 vcsSystem = "None"
3008 else: 3153 else:
3009 vcsSystem = vcsData[0][0] 3154 vcsSystem = vcsData[0][0]
3010 self.pdata["VCS"] = vcsSystem 3155 self.pdata["VCS"] = vcsSystem
3011 self.vcs = self.initVCS() 3156 self.vcs = self.initVCS()
3012 self.setDirty(True) 3157 self.setDirty(True)
3013 if ( 3158 if self.vcs is not None and (
3014 self.vcs is not None and 3159 self.vcs.vcsRegisteredState(self.ppath)
3015 (self.vcs.vcsRegisteredState(self.ppath) != 3160 != self.vcs.canBeCommitted
3016 self.vcs.canBeCommitted)
3017 ): 3161 ):
3018 self.pdata["VCS"] = 'None' 3162 self.pdata["VCS"] = "None"
3019 self.vcs = self.initVCS() 3163 self.vcs = self.initVCS()
3020 self.closeAct.setEnabled(True) 3164 self.closeAct.setEnabled(True)
3021 self.saveasAct.setEnabled(True) 3165 self.saveasAct.setEnabled(True)
3022 self.actGrp2.setEnabled(True) 3166 self.actGrp2.setEnabled(True)
3023 self.propsAct.setEnabled(True) 3167 self.propsAct.setEnabled(True)
3031 self.menuCheckAct.setEnabled(True) 3175 self.menuCheckAct.setEnabled(True)
3032 self.menuShowAct.setEnabled(True) 3176 self.menuShowAct.setEnabled(True)
3033 self.menuDiagramAct.setEnabled(True) 3177 self.menuDiagramAct.setEnabled(True)
3034 self.menuApidocAct.setEnabled(True) 3178 self.menuApidocAct.setEnabled(True)
3035 self.menuPackagersAct.setEnabled(True) 3179 self.menuPackagersAct.setEnabled(True)
3036 self.pluginGrp.setEnabled( 3180 self.pluginGrp.setEnabled(self.pdata["PROJECTTYPE"] in ["E7Plugin"])
3037 self.pdata["PROJECTTYPE"] in ["E7Plugin"])
3038 self.addLanguageAct.setEnabled( 3181 self.addLanguageAct.setEnabled(
3039 bool(self.pdata["TRANSLATIONPATTERN"])) 3182 bool(self.pdata["TRANSLATIONPATTERN"])
3040 self.makeGrp.setEnabled( 3183 )
3041 self.pdata["MAKEPARAMS"]["MakeEnabled"]) 3184 self.makeGrp.setEnabled(self.pdata["MAKEPARAMS"]["MakeEnabled"])
3042 self.menuMakeAct.setEnabled( 3185 self.menuMakeAct.setEnabled(self.pdata["MAKEPARAMS"]["MakeEnabled"])
3043 self.pdata["MAKEPARAMS"]["MakeEnabled"])
3044 self.menuOtherToolsAct.setEnabled(True) 3186 self.menuOtherToolsAct.setEnabled(True)
3045 self.menuFormattingAct.setEnabled(True) 3187 self.menuFormattingAct.setEnabled(True)
3046 3188
3047 # open a project debugger properties file being quiet 3189 # open a project debugger properties file being quiet
3048 # about errors 3190 # about errors
3049 if Preferences.getProject("AutoLoadDbgProperties"): 3191 if Preferences.getProject("AutoLoadDbgProperties"):
3050 self.__readDebugProperties(True) 3192 self.__readDebugProperties(True)
3051 3193
3052 self.__model.projectOpened() 3194 self.__model.projectOpened()
3053 self.projectOpenedHooks.emit() 3195 self.projectOpenedHooks.emit()
3054 self.projectOpened.emit() 3196 self.projectOpened.emit()
3055 3197
3056 if Preferences.getProject("SearchNewFiles"): 3198 if Preferences.getProject("SearchNewFiles"):
3057 self.__doSearchNewFiles() 3199 self.__doSearchNewFiles()
3058 3200
3059 # read a project tasks file 3201 # read a project tasks file
3060 self.__readTasks() 3202 self.__readTasks()
3061 self.ui.taskViewer.setProjectOpen(True) 3203 self.ui.taskViewer.setProjectOpen(True)
3062 # rescan project tasks 3204 # rescan project tasks
3063 if Preferences.getProject("TasksProjectRescanOnOpen"): 3205 if Preferences.getProject("TasksProjectRescanOnOpen"):
3064 ericApp().getObject("TaskViewer" 3206 ericApp().getObject("TaskViewer").regenerateProjectTasks(quiet=True)
3065 ).regenerateProjectTasks(quiet=True) 3207
3066
3067 if restoreSession: 3208 if restoreSession:
3068 # open the main script 3209 # open the main script
3069 if self.pdata["MAINSCRIPT"]: 3210 if self.pdata["MAINSCRIPT"]:
3070 if not os.path.isabs(self.pdata["MAINSCRIPT"]): 3211 if not os.path.isabs(self.pdata["MAINSCRIPT"]):
3071 ms = os.path.join( 3212 ms = os.path.join(self.ppath, self.pdata["MAINSCRIPT"])
3072 self.ppath, self.pdata["MAINSCRIPT"])
3073 else: 3213 else:
3074 ms = self.pdata["MAINSCRIPT"] 3214 ms = self.pdata["MAINSCRIPT"]
3075 self.sourceFile.emit(ms) 3215 self.sourceFile.emit(ms)
3076 3216
3077 # open a project session file being quiet about errors 3217 # open a project session file being quiet about errors
3078 if reopen: 3218 if reopen:
3079 self.__readSession(quiet=True, indicator="_tmp") 3219 self.__readSession(quiet=True, indicator="_tmp")
3080 elif Preferences.getProject("AutoLoadSession"): 3220 elif Preferences.getProject("AutoLoadSession"):
3081 self.__readSession(quiet=True) 3221 self.__readSession(quiet=True)
3082 3222
3083 # start the VCS monitor thread 3223 # start the VCS monitor thread
3084 self.__vcsConnectStatusMonitor() 3224 self.__vcsConnectStatusMonitor()
3085 3225
3086 def reopenProject(self): 3226 def reopenProject(self):
3087 """ 3227 """
3088 Public slot to reopen the current project. 3228 Public slot to reopen the current project.
3089 """ 3229 """
3090 projectFile = self.pfile 3230 projectFile = self.pfile
3091 res = self.closeProject(reopen=True) 3231 res = self.closeProject(reopen=True)
3092 if res: 3232 if res:
3093 self.openProject(projectFile, reopen=True) 3233 self.openProject(projectFile, reopen=True)
3094 3234
3095 def saveProject(self): 3235 def saveProject(self):
3096 """ 3236 """
3097 Public slot to save the current project. 3237 Public slot to save the current project.
3098 3238
3099 @return flag indicating success 3239 @return flag indicating success
3100 """ 3240 """
3101 if self.isDirty(): 3241 if self.isDirty():
3102 if len(self.pfile) > 0: 3242 if len(self.pfile) > 0:
3103 if self.pfile.endswith(".e4p"): 3243 if self.pfile.endswith(".e4p"):
3109 else: 3249 else:
3110 ok = True 3250 ok = True
3111 self.sessActGrp.setEnabled(ok) 3251 self.sessActGrp.setEnabled(ok)
3112 self.menuSessionAct.setEnabled(ok) 3252 self.menuSessionAct.setEnabled(ok)
3113 return ok 3253 return ok
3114 3254
3115 def saveProjectAs(self): 3255 def saveProjectAs(self):
3116 """ 3256 """
3117 Public slot to save the current project to a different file. 3257 Public slot to save the current project to a different file.
3118 3258
3119 @return flag indicating success (boolean) 3259 @return flag indicating success (boolean)
3120 """ 3260 """
3121 defaultFilter = self.tr("Project Files (*.epj)") 3261 defaultFilter = self.tr("Project Files (*.epj)")
3122 defaultPath = ( 3262 defaultPath = (
3123 self.ppath 3263 self.ppath
3124 if self.ppath else 3264 if self.ppath
3125 (Preferences.getMultiProject("Workspace") or 3265 else (Preferences.getMultiProject("Workspace") or Utilities.getHomeDir())
3126 Utilities.getHomeDir())
3127 ) 3266 )
3128 fn, selectedFilter = EricFileDialog.getSaveFileNameAndFilter( 3267 fn, selectedFilter = EricFileDialog.getSaveFileNameAndFilter(
3129 self.parent(), 3268 self.parent(),
3130 self.tr("Save Project"), 3269 self.tr("Save Project"),
3131 defaultPath, 3270 defaultPath,
3132 self.tr("Project Files (*.epj)"), 3271 self.tr("Project Files (*.epj)"),
3133 defaultFilter, 3272 defaultFilter,
3134 EricFileDialog.DontConfirmOverwrite) 3273 EricFileDialog.DontConfirmOverwrite,
3135 3274 )
3275
3136 if fn: 3276 if fn:
3137 fpath = pathlib.Path(fn) 3277 fpath = pathlib.Path(fn)
3138 if not fpath.suffix: 3278 if not fpath.suffix:
3139 ex = selectedFilter.split("(*")[1].split(")")[0] 3279 ex = selectedFilter.split("(*")[1].split(")")[0]
3140 if ex: 3280 if ex:
3141 fpath = fpath.with_suffix(ex) 3281 fpath = fpath.with_suffix(ex)
3142 if fpath.exists(): 3282 if fpath.exists():
3143 res = EricMessageBox.yesNo( 3283 res = EricMessageBox.yesNo(
3144 self.ui, 3284 self.ui,
3145 self.tr("Save File"), 3285 self.tr("Save File"),
3146 self.tr("""<p>The file <b>{0}</b> already exists.""" 3286 self.tr(
3147 """ Overwrite it?</p>""").format(fpath), 3287 """<p>The file <b>{0}</b> already exists."""
3148 icon=EricMessageBox.Warning) 3288 """ Overwrite it?</p>"""
3289 ).format(fpath),
3290 icon=EricMessageBox.Warning,
3291 )
3149 if not res: 3292 if not res:
3150 return False 3293 return False
3151 3294
3152 self.name = fpath.stem 3295 self.name = fpath.stem
3153 ok = self.__writeProject(str(fpath)) 3296 ok = self.__writeProject(str(fpath))
3154 3297
3155 if ok: 3298 if ok:
3156 # create management directory if not present 3299 # create management directory if not present
3157 self.createProjectManagementDir() 3300 self.createProjectManagementDir()
3158 3301
3159 # now save the tasks 3302 # now save the tasks
3160 self.writeTasks() 3303 self.writeTasks()
3161 3304
3162 self.sessActGrp.setEnabled(ok) 3305 self.sessActGrp.setEnabled(ok)
3163 self.menuSessionAct.setEnabled(ok) 3306 self.menuSessionAct.setEnabled(ok)
3164 self.projectClosedHooks.emit() 3307 self.projectClosedHooks.emit()
3165 self.projectClosed.emit(False) 3308 self.projectClosed.emit(False)
3166 self.projectOpenedHooks.emit() 3309 self.projectOpenedHooks.emit()
3167 self.projectOpened.emit() 3310 self.projectOpened.emit()
3168 return ok 3311 return ok
3169 else: 3312 else:
3170 return False 3313 return False
3171 3314
3172 def checkDirty(self): 3315 def checkDirty(self):
3173 """ 3316 """
3174 Public method to check dirty status and open a message window. 3317 Public method to check dirty status and open a message window.
3175 3318
3176 @return flag indicating whether this operation was successful (boolean) 3319 @return flag indicating whether this operation was successful (boolean)
3177 """ 3320 """
3178 if self.isDirty(): 3321 if self.isDirty():
3179 res = EricMessageBox.okToClearData( 3322 res = EricMessageBox.okToClearData(
3180 self.parent(), 3323 self.parent(),
3181 self.tr("Close Project"), 3324 self.tr("Close Project"),
3182 self.tr("The current project has unsaved changes."), 3325 self.tr("The current project has unsaved changes."),
3183 self.saveProject) 3326 self.saveProject,
3327 )
3184 if res: 3328 if res:
3185 self.setDirty(False) 3329 self.setDirty(False)
3186 return res 3330 return res
3187 3331
3188 return True 3332 return True
3189 3333
3190 def __closeAllWindows(self): 3334 def __closeAllWindows(self):
3191 """ 3335 """
3192 Private method to close all project related windows. 3336 Private method to close all project related windows.
3193 """ 3337 """
3194 self.codemetrics and self.codemetrics.close() 3338 self.codemetrics and self.codemetrics.close()
3195 self.codecoverage and self.codecoverage.close() 3339 self.codecoverage and self.codecoverage.close()
3196 self.profiledata and self.profiledata.close() 3340 self.profiledata and self.profiledata.close()
3197 self.applicationDiagram and self.applicationDiagram.close() 3341 self.applicationDiagram and self.applicationDiagram.close()
3198 self.loadedDiagram and self.loadedDiagram.close() 3342 self.loadedDiagram and self.loadedDiagram.close()
3199 3343
3200 @pyqtSlot() 3344 @pyqtSlot()
3201 def closeProject(self, reopen=False, noSave=False, shutdown=False): 3345 def closeProject(self, reopen=False, noSave=False, shutdown=False):
3202 """ 3346 """
3203 Public slot to close the current project. 3347 Public slot to close the current project.
3204 3348
3205 @param reopen flag indicating a reopening of the project 3349 @param reopen flag indicating a reopening of the project
3206 @type bool 3350 @type bool
3207 @param noSave flag indicating to not perform save actions 3351 @param noSave flag indicating to not perform save actions
3208 @type bool 3352 @type bool
3209 @param shutdown flag indicating the IDE shutdown 3353 @param shutdown flag indicating the IDE shutdown
3211 @return flag indicating success 3355 @return flag indicating success
3212 @rtype bool 3356 @rtype bool
3213 """ 3357 """
3214 # save the list of recently opened projects 3358 # save the list of recently opened projects
3215 self.__saveRecent() 3359 self.__saveRecent()
3216 3360
3217 if not self.isOpen(): 3361 if not self.isOpen():
3218 return True 3362 return True
3219 3363
3220 if not self.checkDirty(): 3364 if not self.checkDirty():
3221 return False 3365 return False
3222 3366
3223 ericApp().getObject("TaskViewer").stopProjectTaskExtraction() 3367 ericApp().getObject("TaskViewer").stopProjectTaskExtraction()
3224 3368
3225 # save the user project properties 3369 # save the user project properties
3226 if not noSave: 3370 if not noSave:
3227 self.__writeUserProperties() 3371 self.__writeUserProperties()
3228 3372
3229 # save the project session file being quiet about error 3373 # save the project session file being quiet about error
3230 if reopen: 3374 if reopen:
3231 self.__writeSession(quiet=True, indicator="_tmp") 3375 self.__writeSession(quiet=True, indicator="_tmp")
3232 elif Preferences.getProject("AutoSaveSession") and not noSave: 3376 elif Preferences.getProject("AutoSaveSession") and not noSave:
3233 self.__writeSession(quiet=True) 3377 self.__writeSession(quiet=True)
3234 3378
3235 # save the project debugger properties file being quiet about error 3379 # save the project debugger properties file being quiet about error
3236 if ( 3380 if (
3237 Preferences.getProject("AutoSaveDbgProperties") and 3381 Preferences.getProject("AutoSaveDbgProperties")
3238 self.isDebugPropertiesLoaded() and 3382 and self.isDebugPropertiesLoaded()
3239 not noSave and self.debugPropertiesChanged 3383 and not noSave
3384 and self.debugPropertiesChanged
3240 ): 3385 ):
3241 self.__writeDebugProperties(True) 3386 self.__writeDebugProperties(True)
3242 3387
3243 vm = ericApp().getObject("ViewManager") 3388 vm = ericApp().getObject("ViewManager")
3244 3389
3245 # check dirty status of all project files first 3390 # check dirty status of all project files first
3246 for fn in vm.getOpenFilenames(): 3391 for fn in vm.getOpenFilenames():
3247 if self.isProjectFile(fn): 3392 if self.isProjectFile(fn):
3248 reset = vm.checkFileDirty(fn) 3393 reset = vm.checkFileDirty(fn)
3249 if not reset: 3394 if not reset:
3250 # abort shutting down 3395 # abort shutting down
3251 return False 3396 return False
3252 3397
3253 # close all project related editors 3398 # close all project related editors
3254 success = True 3399 success = True
3255 for fn in vm.getOpenFilenames(): 3400 for fn in vm.getOpenFilenames():
3256 if self.isProjectFile(fn): 3401 if self.isProjectFile(fn):
3257 success &= vm.closeWindow(fn, ignoreDirty=True) 3402 success &= vm.closeWindow(fn, ignoreDirty=True)
3258 if not success: 3403 if not success:
3259 return False 3404 return False
3260 3405
3261 # stop the VCS monitor thread 3406 # stop the VCS monitor thread
3262 if self.vcs is not None: 3407 if self.vcs is not None:
3263 self.vcs.stopStatusMonitor() 3408 self.vcs.stopStatusMonitor()
3264 3409
3265 # now save the tasks 3410 # now save the tasks
3266 if not noSave: 3411 if not noSave:
3267 self.writeTasks() 3412 self.writeTasks()
3268 self.ui.taskViewer.clearProjectTasks() 3413 self.ui.taskViewer.clearProjectTasks()
3269 self.ui.taskViewer.setProjectOpen(False) 3414 self.ui.taskViewer.setProjectOpen(False)
3270 3415
3271 # now shutdown the vcs interface 3416 # now shutdown the vcs interface
3272 if self.vcs: 3417 if self.vcs:
3273 self.vcs.vcsShutdown() 3418 self.vcs.vcsShutdown()
3274 self.vcs.deleteLater() 3419 self.vcs.deleteLater()
3275 self.vcs = None 3420 self.vcs = None
3276 ericApp().getObject("PluginManager").deactivateVcsPlugins() 3421 ericApp().getObject("PluginManager").deactivateVcsPlugins()
3277 3422
3278 # now close all project related tool windows 3423 # now close all project related tool windows
3279 self.__closeAllWindows() 3424 self.__closeAllWindows()
3280 3425
3281 self.__initData() 3426 self.__initData()
3282 self.closeAct.setEnabled(False) 3427 self.closeAct.setEnabled(False)
3283 self.saveasAct.setEnabled(False) 3428 self.saveasAct.setEnabled(False)
3284 self.saveAct.setEnabled(False) 3429 self.saveAct.setEnabled(False)
3285 self.actGrp2.setEnabled(False) 3430 self.actGrp2.setEnabled(False)
3299 self.pluginGrp.setEnabled(False) 3444 self.pluginGrp.setEnabled(False)
3300 self.makeGrp.setEnabled(False) 3445 self.makeGrp.setEnabled(False)
3301 self.menuMakeAct.setEnabled(False) 3446 self.menuMakeAct.setEnabled(False)
3302 self.menuOtherToolsAct.setEnabled(False) 3447 self.menuOtherToolsAct.setEnabled(False)
3303 self.menuFormattingAct.setEnabled(False) 3448 self.menuFormattingAct.setEnabled(False)
3304 3449
3305 self.__model.projectClosed() 3450 self.__model.projectClosed()
3306 self.projectClosedHooks.emit() 3451 self.projectClosedHooks.emit()
3307 self.projectClosed.emit(shutdown) 3452 self.projectClosed.emit(shutdown)
3308 3453
3309 return True 3454 return True
3310 3455
3311 def saveAllScripts(self, reportSyntaxErrors=False): 3456 def saveAllScripts(self, reportSyntaxErrors=False):
3312 """ 3457 """
3313 Public method to save all scripts belonging to the project. 3458 Public method to save all scripts belonging to the project.
3314 3459
3315 @param reportSyntaxErrors flag indicating special reporting 3460 @param reportSyntaxErrors flag indicating special reporting
3316 for syntax errors (boolean) 3461 for syntax errors (boolean)
3317 @return flag indicating success (boolean) 3462 @return flag indicating success (boolean)
3318 """ 3463 """
3319 vm = ericApp().getObject("ViewManager") 3464 vm = ericApp().getObject("ViewManager")
3324 if rfn in self.pdata["SOURCES"] or rfn in self.pdata["OTHERS"]: 3469 if rfn in self.pdata["SOURCES"] or rfn in self.pdata["OTHERS"]:
3325 editor = vm.getOpenEditor(fn) 3470 editor = vm.getOpenEditor(fn)
3326 success &= vm.saveEditorEd(editor) 3471 success &= vm.saveEditorEd(editor)
3327 if reportSyntaxErrors and editor.hasSyntaxErrors(): 3472 if reportSyntaxErrors and editor.hasSyntaxErrors():
3328 filesWithSyntaxErrors += 1 3473 filesWithSyntaxErrors += 1
3329 3474
3330 if reportSyntaxErrors and filesWithSyntaxErrors > 0: 3475 if reportSyntaxErrors and filesWithSyntaxErrors > 0:
3331 EricMessageBox.critical( 3476 EricMessageBox.critical(
3332 self.ui, 3477 self.ui,
3333 self.tr("Syntax errors detected"), 3478 self.tr("Syntax errors detected"),
3334 self.tr( 3479 self.tr(
3335 """The project contains %n file(s) with syntax errors.""", 3480 """The project contains %n file(s) with syntax errors.""",
3336 "", filesWithSyntaxErrors) 3481 "",
3482 filesWithSyntaxErrors,
3483 ),
3337 ) 3484 )
3338 return False 3485 return False
3339 else: 3486 else:
3340 return success 3487 return success
3341 3488
3342 def checkAllScriptsDirty(self, reportSyntaxErrors=False): 3489 def checkAllScriptsDirty(self, reportSyntaxErrors=False):
3343 """ 3490 """
3344 Public method to check all scripts belonging to the project for 3491 Public method to check all scripts belonging to the project for
3345 their dirty status. 3492 their dirty status.
3346 3493
3347 @param reportSyntaxErrors flag indicating special reporting 3494 @param reportSyntaxErrors flag indicating special reporting
3348 for syntax errors (boolean) 3495 for syntax errors (boolean)
3349 @return flag indicating success (boolean) 3496 @return flag indicating success (boolean)
3350 """ 3497 """
3351 vm = ericApp().getObject("ViewManager") 3498 vm = ericApp().getObject("ViewManager")
3356 if rfn in self.pdata["SOURCES"] or rfn in self.pdata["OTHERS"]: 3503 if rfn in self.pdata["SOURCES"] or rfn in self.pdata["OTHERS"]:
3357 editor = vm.getOpenEditor(fn) 3504 editor = vm.getOpenEditor(fn)
3358 success &= editor.checkDirty() 3505 success &= editor.checkDirty()
3359 if reportSyntaxErrors and editor.hasSyntaxErrors(): 3506 if reportSyntaxErrors and editor.hasSyntaxErrors():
3360 filesWithSyntaxErrors += 1 3507 filesWithSyntaxErrors += 1
3361 3508
3362 if reportSyntaxErrors and filesWithSyntaxErrors > 0: 3509 if reportSyntaxErrors and filesWithSyntaxErrors > 0:
3363 EricMessageBox.critical( 3510 EricMessageBox.critical(
3364 self.ui, 3511 self.ui,
3365 self.tr("Syntax errors detected"), 3512 self.tr("Syntax errors detected"),
3366 self.tr( 3513 self.tr(
3367 """The project contains %n file(s) with syntax errors.""", 3514 """The project contains %n file(s) with syntax errors.""",
3368 "", filesWithSyntaxErrors) 3515 "",
3516 filesWithSyntaxErrors,
3517 ),
3369 ) 3518 )
3370 return False 3519 return False
3371 else: 3520 else:
3372 return success 3521 return success
3373 3522
3374 def getMainScript(self, normalized=False): 3523 def getMainScript(self, normalized=False):
3375 """ 3524 """
3376 Public method to return the main script filename. 3525 Public method to return the main script filename.
3377 3526
3378 The normalized name is the name of the main script prepended with 3527 The normalized name is the name of the main script prepended with
3379 the project path. 3528 the project path.
3380 3529
3381 @param normalized flag indicating a normalized filename is wanted 3530 @param normalized flag indicating a normalized filename is wanted
3382 @type bool 3531 @type bool
3383 @return filename of the projects main script 3532 @return filename of the projects main script
3384 @rtype str 3533 @rtype str
3385 """ 3534 """
3388 return os.path.join(self.ppath, self.pdata["MAINSCRIPT"]) 3537 return os.path.join(self.ppath, self.pdata["MAINSCRIPT"])
3389 else: 3538 else:
3390 return self.pdata["MAINSCRIPT"] 3539 return self.pdata["MAINSCRIPT"]
3391 else: 3540 else:
3392 return "" 3541 return ""
3393 3542
3394 def getSources(self, normalized=False): 3543 def getSources(self, normalized=False):
3395 """ 3544 """
3396 Public method to return the source script files. 3545 Public method to return the source script files.
3397 3546
3398 @param normalized flag indicating a normalized filename is wanted 3547 @param normalized flag indicating a normalized filename is wanted
3399 @type bool 3548 @type bool
3400 @return list of the projects scripts 3549 @return list of the projects scripts
3401 @rtype list of str 3550 @rtype list of str
3402 """ 3551 """
3403 return self.getProjectFiles("SOURCES", normalized=normalized) 3552 return self.getProjectFiles("SOURCES", normalized=normalized)
3404 3553
3405 def getProjectFiles(self, fileType, normalized=False): 3554 def getProjectFiles(self, fileType, normalized=False):
3406 """ 3555 """
3407 Public method to get the file entries of the given type. 3556 Public method to get the file entries of the given type.
3408 3557
3409 @param fileType project file type (one of SOURCES, FORMS, RESOURCES, 3558 @param fileType project file type (one of SOURCES, FORMS, RESOURCES,
3410 INTERFACES, PROTOCOLS, OTHERS, TRANSLATIONS) 3559 INTERFACES, PROTOCOLS, OTHERS, TRANSLATIONS)
3411 @type str 3560 @type str
3412 @param normalized flag indicating normalized file names are wanted 3561 @param normalized flag indicating normalized file names are wanted
3413 @type boolean 3562 @type boolean
3414 @return list of file names 3563 @return list of file names
3415 @rtype list of str 3564 @rtype list of str
3416 @exception ValueError raised when an unsupported file type is given 3565 @exception ValueError raised when an unsupported file type is given
3417 """ 3566 """
3418 if fileType not in ["SOURCES", "FORMS", "RESOURCES", "INTERFACES", 3567 if fileType not in [
3419 "PROTOCOLS", "OTHERS", "TRANSLATIONS"]: 3568 "SOURCES",
3569 "FORMS",
3570 "RESOURCES",
3571 "INTERFACES",
3572 "PROTOCOLS",
3573 "OTHERS",
3574 "TRANSLATIONS",
3575 ]:
3420 raise ValueError("Given file type has incorrect value.") 3576 raise ValueError("Given file type has incorrect value.")
3421 3577
3422 if normalized: 3578 if normalized:
3423 return [os.path.join(self.ppath, fn) for fn in 3579 return [os.path.join(self.ppath, fn) for fn in self.pdata[fileType]]
3424 self.pdata[fileType]]
3425 else: 3580 else:
3426 return self.pdata[fileType] 3581 return self.pdata[fileType]
3427 3582
3428 def getProjectType(self): 3583 def getProjectType(self):
3429 """ 3584 """
3430 Public method to get the type of the project. 3585 Public method to get the type of the project.
3431 3586
3432 @return UI type of the project (string) 3587 @return UI type of the project (string)
3433 """ 3588 """
3434 return self.pdata["PROJECTTYPE"] 3589 return self.pdata["PROJECTTYPE"]
3435 3590
3436 def getProjectLanguage(self): 3591 def getProjectLanguage(self):
3437 """ 3592 """
3438 Public method to get the project's programming language. 3593 Public method to get the project's programming language.
3439 3594
3440 @return programming language (string) 3595 @return programming language (string)
3441 """ 3596 """
3442 return self.pdata["PROGLANGUAGE"] 3597 return self.pdata["PROGLANGUAGE"]
3443 3598
3444 def isMixedLanguageProject(self): 3599 def isMixedLanguageProject(self):
3445 """ 3600 """
3446 Public method to check, if this is a mixed language project. 3601 Public method to check, if this is a mixed language project.
3447 3602
3448 @return flag indicating a mixed language project 3603 @return flag indicating a mixed language project
3449 @rtype bool 3604 @rtype bool
3450 """ 3605 """
3451 return self.pdata["MIXEDLANGUAGE"] 3606 return self.pdata["MIXEDLANGUAGE"]
3452 3607
3453 def isPythonProject(self): 3608 def isPythonProject(self):
3454 """ 3609 """
3455 Public method to check, if this project is a Python3 or MicroPython 3610 Public method to check, if this project is a Python3 or MicroPython
3456 project. 3611 project.
3457 3612
3458 @return flag indicating a Python project (boolean) 3613 @return flag indicating a Python project (boolean)
3459 """ 3614 """
3460 return self.pdata["PROGLANGUAGE"] in ["Python3", "MicroPython"] 3615 return self.pdata["PROGLANGUAGE"] in ["Python3", "MicroPython"]
3461 3616
3462 def isPy3Project(self): 3617 def isPy3Project(self):
3463 """ 3618 """
3464 Public method to check, if this project is a Python3 project. 3619 Public method to check, if this project is a Python3 project.
3465 3620
3466 @return flag indicating a Python3 project (boolean) 3621 @return flag indicating a Python3 project (boolean)
3467 """ 3622 """
3468 return self.pdata["PROGLANGUAGE"] == "Python3" 3623 return self.pdata["PROGLANGUAGE"] == "Python3"
3469 3624
3470 def isMicroPythonProject(self): 3625 def isMicroPythonProject(self):
3471 """ 3626 """
3472 Public method to check, if this project is a MicroPython project. 3627 Public method to check, if this project is a MicroPython project.
3473 3628
3474 @return flag indicating a MicroPython project 3629 @return flag indicating a MicroPython project
3475 @rtype bool 3630 @rtype bool
3476 """ 3631 """
3477 return self.pdata["PROGLANGUAGE"] == "MicroPython" 3632 return self.pdata["PROGLANGUAGE"] == "MicroPython"
3478 3633
3479 def isRubyProject(self): 3634 def isRubyProject(self):
3480 """ 3635 """
3481 Public method to check, if this project is a Ruby project. 3636 Public method to check, if this project is a Ruby project.
3482 3637
3483 @return flag indicating a Ruby project (boolean) 3638 @return flag indicating a Ruby project (boolean)
3484 """ 3639 """
3485 return self.pdata["PROGLANGUAGE"] == "Ruby" 3640 return self.pdata["PROGLANGUAGE"] == "Ruby"
3486 3641
3487 def isJavaScriptProject(self): 3642 def isJavaScriptProject(self):
3488 """ 3643 """
3489 Public method to check, if this project is a JavaScript project. 3644 Public method to check, if this project is a JavaScript project.
3490 3645
3491 @return flag indicating a JavaScript project (boolean) 3646 @return flag indicating a JavaScript project (boolean)
3492 """ 3647 """
3493 return self.pdata["PROGLANGUAGE"] == "JavaScript" 3648 return self.pdata["PROGLANGUAGE"] == "JavaScript"
3494 3649
3495 def getProjectSpellLanguage(self): 3650 def getProjectSpellLanguage(self):
3496 """ 3651 """
3497 Public method to get the project's programming language. 3652 Public method to get the project's programming language.
3498 3653
3499 @return programming language (string) 3654 @return programming language (string)
3500 """ 3655 """
3501 return self.pdata["SPELLLANGUAGE"] 3656 return self.pdata["SPELLLANGUAGE"]
3502 3657
3503 def getProjectDictionaries(self): 3658 def getProjectDictionaries(self):
3504 """ 3659 """
3505 Public method to get the names of the project specific dictionaries. 3660 Public method to get the names of the project specific dictionaries.
3506 3661
3507 @return tuple of two strings giving the absolute path names of the 3662 @return tuple of two strings giving the absolute path names of the
3508 project specific word and exclude list 3663 project specific word and exclude list
3509 """ 3664 """
3510 pwl = "" 3665 pwl = ""
3511 if self.pdata["SPELLWORDS"]: 3666 if self.pdata["SPELLWORDS"]:
3512 pwl = os.path.join(self.ppath, self.pdata["SPELLWORDS"]) 3667 pwl = os.path.join(self.ppath, self.pdata["SPELLWORDS"])
3513 if not os.path.isfile(pwl): 3668 if not os.path.isfile(pwl):
3514 pwl = "" 3669 pwl = ""
3515 3670
3516 pel = "" 3671 pel = ""
3517 if self.pdata["SPELLEXCLUDES"]: 3672 if self.pdata["SPELLEXCLUDES"]:
3518 pel = os.path.join(self.ppath, self.pdata["SPELLEXCLUDES"]) 3673 pel = os.path.join(self.ppath, self.pdata["SPELLEXCLUDES"])
3519 if not os.path.isfile(pel): 3674 if not os.path.isfile(pel):
3520 pel = "" 3675 pel = ""
3521 3676
3522 return (pwl, pel) 3677 return (pwl, pel)
3523 3678
3524 def getDefaultSourceExtension(self): 3679 def getDefaultSourceExtension(self):
3525 """ 3680 """
3526 Public method to get the default extension for the project's 3681 Public method to get the default extension for the project's
3527 programming language. 3682 programming language.
3528 3683
3529 @return default extension (including the dot) (string) 3684 @return default extension (including the dot) (string)
3530 """ 3685 """
3531 lang = self.pdata["PROGLANGUAGE"] 3686 lang = self.pdata["PROGLANGUAGE"]
3532 if lang in ("", "Python"): 3687 if lang in ("", "Python"):
3533 lang = "Python3" 3688 lang = "Python3"
3534 return self.__sourceExtensions(lang)[0] 3689 return self.__sourceExtensions(lang)[0]
3535 3690
3536 def getProjectPath(self): 3691 def getProjectPath(self):
3537 """ 3692 """
3538 Public method to get the project path. 3693 Public method to get the project path.
3539 3694
3540 @return project path (string) 3695 @return project path (string)
3541 """ 3696 """
3542 return self.ppath 3697 return self.ppath
3543 3698
3544 def startswithProjectPath(self, path): 3699 def startswithProjectPath(self, path):
3545 """ 3700 """
3546 Public method to check, if a path starts with the project path. 3701 Public method to check, if a path starts with the project path.
3547 3702
3548 @param path path to be checked 3703 @param path path to be checked
3549 @type str 3704 @type str
3550 @return flag indicating that the path starts with the project path 3705 @return flag indicating that the path starts with the project path
3551 @rtype bool 3706 @rtype bool
3552 """ 3707 """
3553 return ( 3708 return bool(self.ppath) and (
3554 bool(self.ppath) and 3709 path == self.ppath
3555 (path == self.ppath or 3710 or Utilities.normcasepath(Utilities.toNativeSeparators(path)).startswith(
3556 Utilities.normcasepath(Utilities.toNativeSeparators(path)) 3711 Utilities.normcasepath(Utilities.toNativeSeparators(self.ppath + "/"))
3557 .startswith(Utilities.normcasepath( 3712 )
3558 Utilities.toNativeSeparators(self.ppath + "/"))) 3713 )
3559 ) 3714
3560 )
3561
3562 def getProjectFile(self): 3715 def getProjectFile(self):
3563 """ 3716 """
3564 Public method to get the path of the project file. 3717 Public method to get the path of the project file.
3565 3718
3566 @return path of the project file (string) 3719 @return path of the project file (string)
3567 """ 3720 """
3568 return self.pfile 3721 return self.pfile
3569 3722
3570 def getProjectName(self): 3723 def getProjectName(self):
3571 """ 3724 """
3572 Public method to get the name of the project. 3725 Public method to get the name of the project.
3573 3726
3574 The project name is determined from the name of the project file. 3727 The project name is determined from the name of the project file.
3575 3728
3576 @return name of the project (string) 3729 @return name of the project (string)
3577 """ 3730 """
3578 if self.pfile: 3731 if self.pfile:
3579 name = os.path.splitext(self.pfile)[0] 3732 name = os.path.splitext(self.pfile)[0]
3580 return os.path.basename(name) 3733 return os.path.basename(name)
3581 else: 3734 else:
3582 return "" 3735 return ""
3583 3736
3584 def getProjectManagementDir(self): 3737 def getProjectManagementDir(self):
3585 """ 3738 """
3586 Public method to get the path of the management directory. 3739 Public method to get the path of the management directory.
3587 3740
3588 @return path of the management directory (string) 3741 @return path of the management directory (string)
3589 """ 3742 """
3590 return os.path.join(self.ppath, ".eric7project") 3743 return os.path.join(self.ppath, ".eric7project")
3591 3744
3592 def createProjectManagementDir(self): 3745 def createProjectManagementDir(self):
3593 """ 3746 """
3594 Public method to create the project management directory. 3747 Public method to create the project management directory.
3595 3748
3596 It does nothing, if it already exists. 3749 It does nothing, if it already exists.
3597 """ 3750 """
3598 # create management directory if not present 3751 # create management directory if not present
3599 mgmtDir = self.getProjectManagementDir() 3752 mgmtDir = self.getProjectManagementDir()
3600 if not os.path.exists(mgmtDir): 3753 if not os.path.exists(mgmtDir):
3601 os.makedirs(mgmtDir) 3754 os.makedirs(mgmtDir)
3602 3755
3603 def getHash(self): 3756 def getHash(self):
3604 """ 3757 """
3605 Public method to get the project hash. 3758 Public method to get the project hash.
3606 3759
3607 @return project hash as a hex string (string) 3760 @return project hash as a hex string (string)
3608 """ 3761 """
3609 return self.pdata["HASH"] 3762 return self.pdata["HASH"]
3610 3763
3611 def getRelativePath(self, path): 3764 def getRelativePath(self, path):
3612 """ 3765 """
3613 Public method to convert a file path to a project relative 3766 Public method to convert a file path to a project relative
3614 file path. 3767 file path.
3615 3768
3616 @param path file or directory name to convert (string) 3769 @param path file or directory name to convert (string)
3617 @return project relative path or unchanged path, if path doesn't 3770 @return project relative path or unchanged path, if path doesn't
3618 belong to the project (string) 3771 belong to the project (string)
3619 """ 3772 """
3620 try: 3773 try:
3621 return str(pathlib.Path(path).relative_to(self.ppath)) 3774 return str(pathlib.Path(path).relative_to(self.ppath))
3622 except ValueError: 3775 except ValueError:
3623 return path 3776 return path
3624 3777
3625 def getRelativeUniversalPath(self, path): 3778 def getRelativeUniversalPath(self, path):
3626 """ 3779 """
3627 Public method to convert a file path to a project relative 3780 Public method to convert a file path to a project relative
3628 file path with universal separators. 3781 file path with universal separators.
3629 3782
3630 @param path file or directory name to convert (string) 3783 @param path file or directory name to convert (string)
3631 @return project relative path or unchanged path, if path doesn't 3784 @return project relative path or unchanged path, if path doesn't
3632 belong to the project (string) 3785 belong to the project (string)
3633 """ 3786 """
3634 return Utilities.fromNativeSeparators(self.getRelativePath(path)) 3787 return Utilities.fromNativeSeparators(self.getRelativePath(path))
3635 3788
3636 def getAbsolutePath(self, fn): 3789 def getAbsolutePath(self, fn):
3637 """ 3790 """
3638 Public method to convert a project relative file path to an absolute 3791 Public method to convert a project relative file path to an absolute
3639 file path. 3792 file path.
3640 3793
3641 @param fn file or directory name to convert (string) 3794 @param fn file or directory name to convert (string)
3642 @return absolute path (string) 3795 @return absolute path (string)
3643 """ 3796 """
3644 if not os.path.isabs(fn): 3797 if not os.path.isabs(fn):
3645 fn = os.path.join(self.ppath, fn) 3798 fn = os.path.join(self.ppath, fn)
3646 return fn 3799 return fn
3647 3800
3648 def getAbsoluteUniversalPath(self, fn): 3801 def getAbsoluteUniversalPath(self, fn):
3649 """ 3802 """
3650 Public method to convert a project relative file path with universal 3803 Public method to convert a project relative file path with universal
3651 separators to an absolute file path. 3804 separators to an absolute file path.
3652 3805
3653 @param fn file or directory name to convert (string) 3806 @param fn file or directory name to convert (string)
3654 @return absolute path (string) 3807 @return absolute path (string)
3655 """ 3808 """
3656 if not os.path.isabs(fn): 3809 if not os.path.isabs(fn):
3657 fn = os.path.join(self.ppath, Utilities.toNativeSeparators(fn)) 3810 fn = os.path.join(self.ppath, Utilities.toNativeSeparators(fn))
3658 return fn 3811 return fn
3659 3812
3660 def getEolString(self): 3813 def getEolString(self):
3661 """ 3814 """
3662 Public method to get the EOL-string to be used by the project. 3815 Public method to get the EOL-string to be used by the project.
3663 3816
3664 @return eol string (string) 3817 @return eol string (string)
3665 """ 3818 """
3666 if self.pdata["EOL"] >= 0: 3819 if self.pdata["EOL"] >= 0:
3667 return self.eols[self.pdata["EOL"]] 3820 return self.eols[self.pdata["EOL"]]
3668 else: 3821 else:
3669 eolMode = Preferences.getEditor("EOLMode") 3822 eolMode = Preferences.getEditor("EOLMode")
3670 if eolMode == QsciScintilla.EolMode.EolWindows: 3823 if eolMode == QsciScintilla.EolMode.EolWindows:
3671 eol = '\r\n' 3824 eol = "\r\n"
3672 elif eolMode == QsciScintilla.EolMode.EolUnix: 3825 elif eolMode == QsciScintilla.EolMode.EolUnix:
3673 eol = '\n' 3826 eol = "\n"
3674 elif eolMode == QsciScintilla.EolMode.EolMac: 3827 elif eolMode == QsciScintilla.EolMode.EolMac:
3675 eol = '\r' 3828 eol = "\r"
3676 else: 3829 else:
3677 eol = os.linesep 3830 eol = os.linesep
3678 return eol 3831 return eol
3679 3832
3680 def useSystemEol(self): 3833 def useSystemEol(self):
3681 """ 3834 """
3682 Public method to check, if the project uses the system eol setting. 3835 Public method to check, if the project uses the system eol setting.
3683 3836
3684 @return flag indicating the usage of system eol (boolean) 3837 @return flag indicating the usage of system eol (boolean)
3685 """ 3838 """
3686 return self.pdata["EOL"] == 0 3839 return self.pdata["EOL"] == 0
3687 3840
3688 def getProjectVersion(self): 3841 def getProjectVersion(self):
3689 """ 3842 """
3690 Public mehod to get the version number of the project. 3843 Public mehod to get the version number of the project.
3691 3844
3692 @return version number 3845 @return version number
3693 @rtype str 3846 @rtype str
3694 """ 3847 """
3695 return self.pdata["VERSION"] 3848 return self.pdata["VERSION"]
3696 3849
3697 def getProjectAuthor(self): 3850 def getProjectAuthor(self):
3698 """ 3851 """
3699 Public method to get the author of the project. 3852 Public method to get the author of the project.
3700 3853
3701 @return author name 3854 @return author name
3702 @rtype str 3855 @rtype str
3703 """ 3856 """
3704 return self.pdata["AUTHOR"] 3857 return self.pdata["AUTHOR"]
3705 3858
3706 def getProjectAuthorEmail(self): 3859 def getProjectAuthorEmail(self):
3707 """ 3860 """
3708 Public method to get the email address of the project author. 3861 Public method to get the email address of the project author.
3709 3862
3710 @return project author email 3863 @return project author email
3711 @rtype str 3864 @rtype str
3712 """ 3865 """
3713 return self.pdata["EMAIL"] 3866 return self.pdata["EMAIL"]
3714 3867
3715 def getProjectDescription(self): 3868 def getProjectDescription(self):
3716 """ 3869 """
3717 Public method to get the description of the project. 3870 Public method to get the description of the project.
3718 3871
3719 @return project description 3872 @return project description
3720 @rtype str 3873 @rtype str
3721 """ 3874 """
3722 return self.pdata["DESCRIPTION"] 3875 return self.pdata["DESCRIPTION"]
3723 3876
3724 def getProjectVenv(self, resolveDebugger=True): 3877 def getProjectVenv(self, resolveDebugger=True):
3725 """ 3878 """
3726 Public method to get the name of the virtual environment used by the 3879 Public method to get the name of the virtual environment used by the
3727 project. 3880 project.
3728 3881
3729 @param resolveDebugger flag indicating to resolve the virtual 3882 @param resolveDebugger flag indicating to resolve the virtual
3730 environment name via the debugger settings if none was configured 3883 environment name via the debugger settings if none was configured
3731 @type bool 3884 @type bool
3732 @return name of the project's virtual environment 3885 @return name of the project's virtual environment
3733 @rtype str 3886 @rtype str
3734 """ 3887 """
3735 venvName = self.getDebugProperty("VIRTUALENV") 3888 venvName = self.getDebugProperty("VIRTUALENV")
3736 if ( 3889 if (
3737 not venvName and 3890 not venvName
3738 resolveDebugger and 3891 and resolveDebugger
3739 self.getProjectLanguage() in ("Python3", "MicroPython", "Cython") 3892 and self.getProjectLanguage() in ("Python3", "MicroPython", "Cython")
3740 ): 3893 ):
3741 venvName = Preferences.getDebugger("Python3VirtualEnv") 3894 venvName = Preferences.getDebugger("Python3VirtualEnv")
3742 3895
3743 return venvName 3896 return venvName
3744 3897
3745 def getProjectInterpreter(self, resolveGlobal=True): 3898 def getProjectInterpreter(self, resolveGlobal=True):
3746 """ 3899 """
3747 Public method to get the path of the interpreter used by the project. 3900 Public method to get the path of the interpreter used by the project.
3748 3901
3749 @param resolveGlobal flag indicating to resolve the interpreter using 3902 @param resolveGlobal flag indicating to resolve the interpreter using
3750 the global interpreter if no project of debugger specific 3903 the global interpreter if no project of debugger specific
3751 environment was configured 3904 environment was configured
3752 @type bool 3905 @type bool
3753 @return path of the project's interpreter 3906 @return path of the project's interpreter
3755 """ 3908 """
3756 interpreter = "" 3909 interpreter = ""
3757 venvName = self.getProjectVenv() 3910 venvName = self.getProjectVenv()
3758 if venvName: 3911 if venvName:
3759 interpreter = ( 3912 interpreter = (
3760 ericApp().getObject("VirtualEnvManager") 3913 ericApp()
3914 .getObject("VirtualEnvManager")
3761 .getVirtualenvInterpreter(venvName) 3915 .getVirtualenvInterpreter(venvName)
3762 ) 3916 )
3763 if not interpreter and resolveGlobal: 3917 if not interpreter and resolveGlobal:
3764 interpreter = Globals.getPythonExecutable() 3918 interpreter = Globals.getPythonExecutable()
3765 3919
3766 return interpreter 3920 return interpreter
3767 3921
3768 def getProjectExecPath(self): 3922 def getProjectExecPath(self):
3769 """ 3923 """
3770 Public method to get the executable search path prefix of the project. 3924 Public method to get the executable search path prefix of the project.
3771 3925
3772 @return executable search path prefix 3926 @return executable search path prefix
3773 @rtype str 3927 @rtype str
3774 """ 3928 """
3775 execPath = "" 3929 execPath = ""
3776 venvName = self.getProjectVenv() 3930 venvName = self.getProjectVenv()
3777 if venvName: 3931 if venvName:
3778 execPath = ( 3932 execPath = (
3779 ericApp().getObject("VirtualEnvManager") 3933 ericApp().getObject("VirtualEnvManager").getVirtualenvExecPath(venvName)
3780 .getVirtualenvExecPath(venvName) 3934 )
3781 ) 3935
3782
3783 return execPath 3936 return execPath
3784 3937
3785 def getProjectTestingFramework(self): 3938 def getProjectTestingFramework(self):
3786 """ 3939 """
3787 Public method to get the testing framework name of the project. 3940 Public method to get the testing framework name of the project.
3788 3941
3789 @return testing framework name of the project 3942 @return testing framework name of the project
3790 @rtype str 3943 @rtype str
3791 """ 3944 """
3792 try: 3945 try:
3793 return self.pdata["TESTING_FRAMEWORK"] 3946 return self.pdata["TESTING_FRAMEWORK"]
3794 except KeyError: 3947 except KeyError:
3795 return "" 3948 return ""
3796 3949
3797 def getProjectLicense(self): 3950 def getProjectLicense(self):
3798 """ 3951 """
3799 Public method to get the license type used by the project. 3952 Public method to get the license type used by the project.
3800 3953
3801 @return license type of the project 3954 @return license type of the project
3802 @rtype str 3955 @rtype str
3803 """ 3956 """
3804 try: 3957 try:
3805 return self.pdata["LICENSE"] 3958 return self.pdata["LICENSE"]
3806 except KeyError: 3959 except KeyError:
3807 return "" 3960 return ""
3808 3961
3809 def __isInPdata(self, fn): 3962 def __isInPdata(self, fn):
3810 """ 3963 """
3811 Private method used to check, if the passed in filename is project 3964 Private method used to check, if the passed in filename is project
3812 controlled.. 3965 controlled..
3813 3966
3814 @param fn filename to be checked 3967 @param fn filename to be checked
3815 @type str 3968 @type str
3816 @return flag indicating membership 3969 @return flag indicating membership
3817 @rtype bool 3970 @rtype bool
3818 """ 3971 """
3819 newfn = os.path.abspath(fn) 3972 newfn = os.path.abspath(fn)
3820 newfn = self.getRelativePath(newfn) 3973 newfn = self.getRelativePath(newfn)
3821 return any( 3974 return any(
3822 newfn in self.pdata[group] 3975 newfn in self.pdata[group]
3823 for group in [ 3976 for group in [
3824 "SOURCES", "FORMS", "INTERFACES", "PROTOCOLS", "RESOURCES", 3977 "SOURCES",
3825 "TRANSLATIONS", "OTHERS" 3978 "FORMS",
3979 "INTERFACES",
3980 "PROTOCOLS",
3981 "RESOURCES",
3982 "TRANSLATIONS",
3983 "OTHERS",
3826 ] 3984 ]
3827 ) 3985 )
3828 3986
3829 def isProjectFile(self, fn): 3987 def isProjectFile(self, fn):
3830 """ 3988 """
3831 Public method used to check, if the passed in filename belongs to the 3989 Public method used to check, if the passed in filename belongs to the
3832 project. 3990 project.
3833 3991
3834 @param fn filename to be checked (string) 3992 @param fn filename to be checked (string)
3835 @return flag indicating membership (boolean) 3993 @return flag indicating membership (boolean)
3836 """ 3994 """
3837 return any( 3995 return any(
3838 self.__checkProjectFileGroup(fn, group) 3996 self.__checkProjectFileGroup(fn, group)
3839 for group in [ 3997 for group in [
3840 "SOURCES", "FORMS", "INTERFACES", "PROTOCOLS", "RESOURCES", 3998 "SOURCES",
3841 "TRANSLATIONS", "OTHERS" 3999 "FORMS",
4000 "INTERFACES",
4001 "PROTOCOLS",
4002 "RESOURCES",
4003 "TRANSLATIONS",
4004 "OTHERS",
3842 ] 4005 ]
3843 ) 4006 )
3844 4007
3845 def __checkProjectFileGroup(self, fn, group): 4008 def __checkProjectFileGroup(self, fn, group):
3846 """ 4009 """
3847 Private method to check, if a file is in a specific file group of the 4010 Private method to check, if a file is in a specific file group of the
3848 project. 4011 project.
3849 4012
3850 @param fn filename to be checked (string) 4013 @param fn filename to be checked (string)
3851 @param group group to check (string) 4014 @param group group to check (string)
3852 @return flag indicating membership (boolean) 4015 @return flag indicating membership (boolean)
3853 """ 4016 """
3854 newfn = os.path.abspath(fn) 4017 newfn = os.path.abspath(fn)
3855 newfn = self.getRelativePath(newfn) 4018 newfn = self.getRelativePath(newfn)
3856 if ( 4019 if newfn in self.pdata[group] or (
3857 newfn in self.pdata[group] or 4020 group == "OTHERS"
3858 (group == "OTHERS" and 4021 and any(newfn.startswith(entry) for entry in self.pdata[group])
3859 any(newfn.startswith(entry) for entry in self.pdata[group]))
3860 ): 4022 ):
3861 return True 4023 return True
3862 4024
3863 if Utilities.isWindowsPlatform(): 4025 if Utilities.isWindowsPlatform():
3864 # try the above case-insensitive 4026 # try the above case-insensitive
3865 newfn = newfn.lower() 4027 newfn = newfn.lower()
3866 if any(entry.lower() == newfn for entry in self.pdata[group]): 4028 if any(entry.lower() == newfn for entry in self.pdata[group]):
3867 return True 4029 return True
3868 elif ( 4030 elif group == "OTHERS" and any(
3869 group == "OTHERS" and 4031 newfn.startswith(entry.lower()) for entry in self.pdata[group]
3870 any(newfn.startswith(entry.lower())
3871 for entry in self.pdata[group])
3872 ): 4032 ):
3873 return True 4033 return True
3874 4034
3875 return False 4035 return False
3876 4036
3877 def isProjectSource(self, fn): 4037 def isProjectSource(self, fn):
3878 """ 4038 """
3879 Public method used to check, if the passed in filename belongs to the 4039 Public method used to check, if the passed in filename belongs to the
3880 project sources. 4040 project sources.
3881 4041
3882 @param fn filename to be checked (string) 4042 @param fn filename to be checked (string)
3883 @return flag indicating membership (boolean) 4043 @return flag indicating membership (boolean)
3884 """ 4044 """
3885 return self.__checkProjectFileGroup(fn, "SOURCES") 4045 return self.__checkProjectFileGroup(fn, "SOURCES")
3886 4046
3887 def isProjectForm(self, fn): 4047 def isProjectForm(self, fn):
3888 """ 4048 """
3889 Public method used to check, if the passed in filename belongs to the 4049 Public method used to check, if the passed in filename belongs to the
3890 project forms. 4050 project forms.
3891 4051
3892 @param fn filename to be checked (string) 4052 @param fn filename to be checked (string)
3893 @return flag indicating membership (boolean) 4053 @return flag indicating membership (boolean)
3894 """ 4054 """
3895 return self.__checkProjectFileGroup(fn, "FORMS") 4055 return self.__checkProjectFileGroup(fn, "FORMS")
3896 4056
3897 def isProjectInterface(self, fn): 4057 def isProjectInterface(self, fn):
3898 """ 4058 """
3899 Public method used to check, if the passed in filename belongs to the 4059 Public method used to check, if the passed in filename belongs to the
3900 project interfaces. 4060 project interfaces.
3901 4061
3902 @param fn filename to be checked (string) 4062 @param fn filename to be checked (string)
3903 @return flag indicating membership (boolean) 4063 @return flag indicating membership (boolean)
3904 """ 4064 """
3905 return self.__checkProjectFileGroup(fn, "INTERFACES") 4065 return self.__checkProjectFileGroup(fn, "INTERFACES")
3906 4066
3907 def isProjectProtocol(self, fn): 4067 def isProjectProtocol(self, fn):
3908 """ 4068 """
3909 Public method used to check, if the passed in filename belongs to the 4069 Public method used to check, if the passed in filename belongs to the
3910 project protocols. 4070 project protocols.
3911 4071
3912 @param fn filename to be checked 4072 @param fn filename to be checked
3913 @type str 4073 @type str
3914 @return flag indicating membership 4074 @return flag indicating membership
3915 @rtype bool 4075 @rtype bool
3916 """ 4076 """
3917 return self.__checkProjectFileGroup(fn, "PROTOCOLS") 4077 return self.__checkProjectFileGroup(fn, "PROTOCOLS")
3918 4078
3919 def isProjectResource(self, fn): 4079 def isProjectResource(self, fn):
3920 """ 4080 """
3921 Public method used to check, if the passed in filename belongs to the 4081 Public method used to check, if the passed in filename belongs to the
3922 project resources. 4082 project resources.
3923 4083
3924 @param fn filename to be checked (string) 4084 @param fn filename to be checked (string)
3925 @return flag indicating membership (boolean) 4085 @return flag indicating membership (boolean)
3926 """ 4086 """
3927 return self.__checkProjectFileGroup(fn, "RESOURCES") 4087 return self.__checkProjectFileGroup(fn, "RESOURCES")
3928 4088
3929 def initActions(self): 4089 def initActions(self):
3930 """ 4090 """
3931 Public slot to initialize the project related actions. 4091 Public slot to initialize the project related actions.
3932 """ 4092 """
3933 self.actions = [] 4093 self.actions = []
3934 4094
3935 ################################################################### 4095 ###################################################################
3936 ## Project actions 4096 ## Project actions
3937 ################################################################### 4097 ###################################################################
3938 4098
3939 self.actGrp1 = createActionGroup(self) 4099 self.actGrp1 = createActionGroup(self)
3940 4100
3941 act = EricAction( 4101 act = EricAction(
3942 self.tr('New project'), 4102 self.tr("New project"),
3943 UI.PixmapCache.getIcon("projectNew"), 4103 UI.PixmapCache.getIcon("projectNew"),
3944 self.tr('&New...'), 0, 0, 4104 self.tr("&New..."),
3945 self.actGrp1, 'project_new') 4105 0,
3946 act.setStatusTip(self.tr('Generate a new project')) 4106 0,
3947 act.setWhatsThis(self.tr( 4107 self.actGrp1,
3948 """<b>New...</b>""" 4108 "project_new",
3949 """<p>This opens a dialog for entering the info for a""" 4109 )
3950 """ new project.</p>""" 4110 act.setStatusTip(self.tr("Generate a new project"))
3951 )) 4111 act.setWhatsThis(
4112 self.tr(
4113 """<b>New...</b>"""
4114 """<p>This opens a dialog for entering the info for a"""
4115 """ new project.</p>"""
4116 )
4117 )
3952 act.triggered.connect(self.createNewProject) 4118 act.triggered.connect(self.createNewProject)
3953 self.actions.append(act) 4119 self.actions.append(act)
3954 4120
3955 act = EricAction( 4121 act = EricAction(
3956 self.tr('Open project'), 4122 self.tr("Open project"),
3957 UI.PixmapCache.getIcon("projectOpen"), 4123 UI.PixmapCache.getIcon("projectOpen"),
3958 self.tr('&Open...'), 0, 0, 4124 self.tr("&Open..."),
3959 self.actGrp1, 'project_open') 4125 0,
3960 act.setStatusTip(self.tr('Open an existing project')) 4126 0,
3961 act.setWhatsThis(self.tr( 4127 self.actGrp1,
3962 """<b>Open...</b>""" 4128 "project_open",
3963 """<p>This opens an existing project.</p>""" 4129 )
3964 )) 4130 act.setStatusTip(self.tr("Open an existing project"))
4131 act.setWhatsThis(
4132 self.tr("""<b>Open...</b>""" """<p>This opens an existing project.</p>""")
4133 )
3965 act.triggered.connect(self.openProject) 4134 act.triggered.connect(self.openProject)
3966 self.actions.append(act) 4135 self.actions.append(act)
3967 4136
3968 self.closeAct = EricAction( 4137 self.closeAct = EricAction(
3969 self.tr('Close project'), 4138 self.tr("Close project"),
3970 UI.PixmapCache.getIcon("projectClose"), 4139 UI.PixmapCache.getIcon("projectClose"),
3971 self.tr('&Close'), 0, 0, self, 'project_close') 4140 self.tr("&Close"),
3972 self.closeAct.setStatusTip(self.tr('Close the current project')) 4141 0,
3973 self.closeAct.setWhatsThis(self.tr( 4142 0,
3974 """<b>Close</b>""" 4143 self,
3975 """<p>This closes the current project.</p>""" 4144 "project_close",
3976 )) 4145 )
4146 self.closeAct.setStatusTip(self.tr("Close the current project"))
4147 self.closeAct.setWhatsThis(
4148 self.tr("""<b>Close</b>""" """<p>This closes the current project.</p>""")
4149 )
3977 self.closeAct.triggered.connect(self.closeProject) 4150 self.closeAct.triggered.connect(self.closeProject)
3978 self.actions.append(self.closeAct) 4151 self.actions.append(self.closeAct)
3979 4152
3980 self.saveAct = EricAction( 4153 self.saveAct = EricAction(
3981 self.tr('Save project'), 4154 self.tr("Save project"),
3982 UI.PixmapCache.getIcon("projectSave"), 4155 UI.PixmapCache.getIcon("projectSave"),
3983 self.tr('&Save'), 0, 0, self, 'project_save') 4156 self.tr("&Save"),
3984 self.saveAct.setStatusTip(self.tr('Save the current project')) 4157 0,
3985 self.saveAct.setWhatsThis(self.tr( 4158 0,
3986 """<b>Save</b>""" 4159 self,
3987 """<p>This saves the current project.</p>""" 4160 "project_save",
3988 )) 4161 )
4162 self.saveAct.setStatusTip(self.tr("Save the current project"))
4163 self.saveAct.setWhatsThis(
4164 self.tr("""<b>Save</b>""" """<p>This saves the current project.</p>""")
4165 )
3989 self.saveAct.triggered.connect(self.saveProject) 4166 self.saveAct.triggered.connect(self.saveProject)
3990 self.actions.append(self.saveAct) 4167 self.actions.append(self.saveAct)
3991 4168
3992 self.saveasAct = EricAction( 4169 self.saveasAct = EricAction(
3993 self.tr('Save project as'), 4170 self.tr("Save project as"),
3994 UI.PixmapCache.getIcon("projectSaveAs"), 4171 UI.PixmapCache.getIcon("projectSaveAs"),
3995 self.tr('Save &as...'), 0, 0, self, 'project_save_as') 4172 self.tr("Save &as..."),
3996 self.saveasAct.setStatusTip(self.tr( 4173 0,
3997 'Save the current project to a new file')) 4174 0,
3998 self.saveasAct.setWhatsThis(self.tr( 4175 self,
3999 """<b>Save as</b>""" 4176 "project_save_as",
4000 """<p>This saves the current project to a new file.</p>""" 4177 )
4001 )) 4178 self.saveasAct.setStatusTip(self.tr("Save the current project to a new file"))
4179 self.saveasAct.setWhatsThis(
4180 self.tr(
4181 """<b>Save as</b>"""
4182 """<p>This saves the current project to a new file.</p>"""
4183 )
4184 )
4002 self.saveasAct.triggered.connect(self.saveProjectAs) 4185 self.saveasAct.triggered.connect(self.saveProjectAs)
4003 self.actions.append(self.saveasAct) 4186 self.actions.append(self.saveasAct)
4004 4187
4005 ################################################################### 4188 ###################################################################
4006 ## Project management actions 4189 ## Project management actions
4007 ################################################################### 4190 ###################################################################
4008 4191
4009 self.actGrp2 = createActionGroup(self) 4192 self.actGrp2 = createActionGroup(self)
4010 4193
4011 self.addFilesAct = EricAction( 4194 self.addFilesAct = EricAction(
4012 self.tr('Add files to project'), 4195 self.tr("Add files to project"),
4013 UI.PixmapCache.getIcon("fileMisc"), 4196 UI.PixmapCache.getIcon("fileMisc"),
4014 self.tr('Add &files...'), 0, 0, 4197 self.tr("Add &files..."),
4015 self.actGrp2, 'project_add_file') 4198 0,
4016 self.addFilesAct.setStatusTip(self.tr( 4199 0,
4017 'Add files to the current project')) 4200 self.actGrp2,
4018 self.addFilesAct.setWhatsThis(self.tr( 4201 "project_add_file",
4019 """<b>Add files...</b>""" 4202 )
4020 """<p>This opens a dialog for adding files""" 4203 self.addFilesAct.setStatusTip(self.tr("Add files to the current project"))
4021 """ to the current project. The place to add is""" 4204 self.addFilesAct.setWhatsThis(
4022 """ determined by the file extension.</p>""" 4205 self.tr(
4023 )) 4206 """<b>Add files...</b>"""
4207 """<p>This opens a dialog for adding files"""
4208 """ to the current project. The place to add is"""
4209 """ determined by the file extension.</p>"""
4210 )
4211 )
4024 self.addFilesAct.triggered.connect(self.addFiles) 4212 self.addFilesAct.triggered.connect(self.addFiles)
4025 self.actions.append(self.addFilesAct) 4213 self.actions.append(self.addFilesAct)
4026 4214
4027 self.addDirectoryAct = EricAction( 4215 self.addDirectoryAct = EricAction(
4028 self.tr('Add directory to project'), 4216 self.tr("Add directory to project"),
4029 UI.PixmapCache.getIcon("dirOpen"), 4217 UI.PixmapCache.getIcon("dirOpen"),
4030 self.tr('Add directory...'), 0, 0, 4218 self.tr("Add directory..."),
4031 self.actGrp2, 'project_add_directory') 4219 0,
4220 0,
4221 self.actGrp2,
4222 "project_add_directory",
4223 )
4032 self.addDirectoryAct.setStatusTip( 4224 self.addDirectoryAct.setStatusTip(
4033 self.tr('Add a directory to the current project')) 4225 self.tr("Add a directory to the current project")
4034 self.addDirectoryAct.setWhatsThis(self.tr( 4226 )
4035 """<b>Add directory...</b>""" 4227 self.addDirectoryAct.setWhatsThis(
4036 """<p>This opens a dialog for adding a directory""" 4228 self.tr(
4037 """ to the current project.</p>""" 4229 """<b>Add directory...</b>"""
4038 )) 4230 """<p>This opens a dialog for adding a directory"""
4231 """ to the current project.</p>"""
4232 )
4233 )
4039 self.addDirectoryAct.triggered.connect(self.addDirectory) 4234 self.addDirectoryAct.triggered.connect(self.addDirectory)
4040 self.actions.append(self.addDirectoryAct) 4235 self.actions.append(self.addDirectoryAct)
4041 4236
4042 self.addLanguageAct = EricAction( 4237 self.addLanguageAct = EricAction(
4043 self.tr('Add translation to project'), 4238 self.tr("Add translation to project"),
4044 UI.PixmapCache.getIcon("linguist4"), 4239 UI.PixmapCache.getIcon("linguist4"),
4045 self.tr('Add &translation...'), 0, 0, 4240 self.tr("Add &translation..."),
4046 self.actGrp2, 'project_add_translation') 4241 0,
4242 0,
4243 self.actGrp2,
4244 "project_add_translation",
4245 )
4047 self.addLanguageAct.setStatusTip( 4246 self.addLanguageAct.setStatusTip(
4048 self.tr('Add a translation to the current project')) 4247 self.tr("Add a translation to the current project")
4049 self.addLanguageAct.setWhatsThis(self.tr( 4248 )
4050 """<b>Add translation...</b>""" 4249 self.addLanguageAct.setWhatsThis(
4051 """<p>This opens a dialog for add a translation""" 4250 self.tr(
4052 """ to the current project.</p>""" 4251 """<b>Add translation...</b>"""
4053 )) 4252 """<p>This opens a dialog for add a translation"""
4253 """ to the current project.</p>"""
4254 )
4255 )
4054 self.addLanguageAct.triggered.connect(self.addLanguage) 4256 self.addLanguageAct.triggered.connect(self.addLanguage)
4055 self.actions.append(self.addLanguageAct) 4257 self.actions.append(self.addLanguageAct)
4056 4258
4057 act = EricAction( 4259 act = EricAction(
4058 self.tr('Search new files'), 4260 self.tr("Search new files"),
4059 self.tr('Searc&h new files...'), 0, 0, 4261 self.tr("Searc&h new files..."),
4060 self.actGrp2, 'project_search_new_files') 4262 0,
4061 act.setStatusTip(self.tr( 4263 0,
4062 'Search new files in the project directory.')) 4264 self.actGrp2,
4063 act.setWhatsThis(self.tr( 4265 "project_search_new_files",
4064 """<b>Search new files...</b>""" 4266 )
4065 """<p>This searches for new files (sources, *.ui, *.idl,""" 4267 act.setStatusTip(self.tr("Search new files in the project directory."))
4066 """ *.proto) in the project directory and registered""" 4268 act.setWhatsThis(
4067 """ subdirectories.</p>""" 4269 self.tr(
4068 )) 4270 """<b>Search new files...</b>"""
4271 """<p>This searches for new files (sources, *.ui, *.idl,"""
4272 """ *.proto) in the project directory and registered"""
4273 """ subdirectories.</p>"""
4274 )
4275 )
4069 act.triggered.connect(self.__searchNewFiles) 4276 act.triggered.connect(self.__searchNewFiles)
4070 self.actions.append(act) 4277 self.actions.append(act)
4071 4278
4072 act = EricAction( 4279 act = EricAction(
4073 self.tr('Search Project File'), 4280 self.tr("Search Project File"),
4074 self.tr('Search Project File...'), 4281 self.tr("Search Project File..."),
4075 QKeySequence(self.tr("Alt+Ctrl+P", "Project|Search Project File")), 4282 QKeySequence(self.tr("Alt+Ctrl+P", "Project|Search Project File")),
4076 0, 4283 0,
4077 self.actGrp2, 'project_search_project_file') 4284 self.actGrp2,
4078 act.setStatusTip(self.tr( 4285 "project_search_project_file",
4079 'Search for a file in the project list of files.')) 4286 )
4080 act.setWhatsThis(self.tr( 4287 act.setStatusTip(self.tr("Search for a file in the project list of files."))
4081 """<b>Search Project File</b>""" 4288 act.setWhatsThis(
4082 """<p>This searches for a file in the project list of files.</p>""" 4289 self.tr(
4083 )) 4290 """<b>Search Project File</b>"""
4291 """<p>This searches for a file in the project list of files.</p>"""
4292 )
4293 )
4084 act.triggered.connect(self.__searchProjectFile) 4294 act.triggered.connect(self.__searchProjectFile)
4085 self.actions.append(act) 4295 self.actions.append(act)
4086 4296
4087 self.propsAct = EricAction( 4297 self.propsAct = EricAction(
4088 self.tr('Project properties'), 4298 self.tr("Project properties"),
4089 UI.PixmapCache.getIcon("projectProps"), 4299 UI.PixmapCache.getIcon("projectProps"),
4090 self.tr('&Properties...'), 0, 0, self, 4300 self.tr("&Properties..."),
4091 'project_properties') 4301 0,
4092 self.propsAct.setStatusTip(self.tr('Show the project properties')) 4302 0,
4093 self.propsAct.setWhatsThis(self.tr( 4303 self,
4094 """<b>Properties...</b>""" 4304 "project_properties",
4095 """<p>This shows a dialog to edit the project properties.</p>""" 4305 )
4096 )) 4306 self.propsAct.setStatusTip(self.tr("Show the project properties"))
4307 self.propsAct.setWhatsThis(
4308 self.tr(
4309 """<b>Properties...</b>"""
4310 """<p>This shows a dialog to edit the project properties.</p>"""
4311 )
4312 )
4097 self.propsAct.triggered.connect(self.__showProperties) 4313 self.propsAct.triggered.connect(self.__showProperties)
4098 self.actions.append(self.propsAct) 4314 self.actions.append(self.propsAct)
4099 4315
4100 self.userPropsAct = EricAction( 4316 self.userPropsAct = EricAction(
4101 self.tr('User project properties'), 4317 self.tr("User project properties"),
4102 UI.PixmapCache.getIcon("projectUserProps"), 4318 UI.PixmapCache.getIcon("projectUserProps"),
4103 self.tr('&User Properties...'), 0, 0, self, 4319 self.tr("&User Properties..."),
4104 'project_user_properties') 4320 0,
4105 self.userPropsAct.setStatusTip(self.tr( 4321 0,
4106 'Show the user specific project properties')) 4322 self,
4107 self.userPropsAct.setWhatsThis(self.tr( 4323 "project_user_properties",
4108 """<b>User Properties...</b>""" 4324 )
4109 """<p>This shows a dialog to edit the user specific project""" 4325 self.userPropsAct.setStatusTip(
4110 """ properties.</p>""" 4326 self.tr("Show the user specific project properties")
4111 )) 4327 )
4328 self.userPropsAct.setWhatsThis(
4329 self.tr(
4330 """<b>User Properties...</b>"""
4331 """<p>This shows a dialog to edit the user specific project"""
4332 """ properties.</p>"""
4333 )
4334 )
4112 self.userPropsAct.triggered.connect(self.__showUserProperties) 4335 self.userPropsAct.triggered.connect(self.__showUserProperties)
4113 self.actions.append(self.userPropsAct) 4336 self.actions.append(self.userPropsAct)
4114 4337
4115 self.filetypesAct = EricAction( 4338 self.filetypesAct = EricAction(
4116 self.tr('Filetype Associations'), 4339 self.tr("Filetype Associations"),
4117 self.tr('Filetype Associations...'), 0, 0, 4340 self.tr("Filetype Associations..."),
4118 self, 'project_filetype_associations') 4341 0,
4342 0,
4343 self,
4344 "project_filetype_associations",
4345 )
4119 self.filetypesAct.setStatusTip( 4346 self.filetypesAct.setStatusTip(
4120 self.tr('Show the project file type associations')) 4347 self.tr("Show the project file type associations")
4121 self.filetypesAct.setWhatsThis(self.tr( 4348 )
4122 """<b>Filetype Associations...</b>""" 4349 self.filetypesAct.setWhatsThis(
4123 """<p>This shows a dialog to edit the file type associations of""" 4350 self.tr(
4124 """ the project. These associations determine the type""" 4351 """<b>Filetype Associations...</b>"""
4125 """ (source, form, interface, protocol or others) with a""" 4352 """<p>This shows a dialog to edit the file type associations of"""
4126 """ filename pattern. They are used when adding a file to the""" 4353 """ the project. These associations determine the type"""
4127 """ project and when performing a search for new files.</p>""" 4354 """ (source, form, interface, protocol or others) with a"""
4128 )) 4355 """ filename pattern. They are used when adding a file to the"""
4129 self.filetypesAct.triggered.connect( 4356 """ project and when performing a search for new files.</p>"""
4130 self.__showFiletypeAssociations) 4357 )
4358 )
4359 self.filetypesAct.triggered.connect(self.__showFiletypeAssociations)
4131 self.actions.append(self.filetypesAct) 4360 self.actions.append(self.filetypesAct)
4132 4361
4133 self.lexersAct = EricAction( 4362 self.lexersAct = EricAction(
4134 self.tr('Lexer Associations'), 4363 self.tr("Lexer Associations"),
4135 self.tr('Lexer Associations...'), 0, 0, 4364 self.tr("Lexer Associations..."),
4136 self, 'project_lexer_associations') 4365 0,
4137 self.lexersAct.setStatusTip(self.tr( 4366 0,
4138 'Show the project lexer associations (overriding defaults)')) 4367 self,
4139 self.lexersAct.setWhatsThis(self.tr( 4368 "project_lexer_associations",
4140 """<b>Lexer Associations...</b>""" 4369 )
4141 """<p>This shows a dialog to edit the lexer associations of""" 4370 self.lexersAct.setStatusTip(
4142 """ the project. These associations override the global lexer""" 4371 self.tr("Show the project lexer associations (overriding defaults)")
4143 """ associations. Lexers are used to highlight the editor""" 4372 )
4144 """ text.</p>""" 4373 self.lexersAct.setWhatsThis(
4145 )) 4374 self.tr(
4375 """<b>Lexer Associations...</b>"""
4376 """<p>This shows a dialog to edit the lexer associations of"""
4377 """ the project. These associations override the global lexer"""
4378 """ associations. Lexers are used to highlight the editor"""
4379 """ text.</p>"""
4380 )
4381 )
4146 self.lexersAct.triggered.connect(self.__showLexerAssociations) 4382 self.lexersAct.triggered.connect(self.__showLexerAssociations)
4147 self.actions.append(self.lexersAct) 4383 self.actions.append(self.lexersAct)
4148 4384
4149 ################################################################### 4385 ###################################################################
4150 ## Project debug actions 4386 ## Project debug actions
4151 ################################################################### 4387 ###################################################################
4152 4388
4153 self.dbgActGrp = createActionGroup(self) 4389 self.dbgActGrp = createActionGroup(self)
4154 4390
4155 act = EricAction( 4391 act = EricAction(
4156 self.tr('Debugger Properties'), 4392 self.tr("Debugger Properties"),
4157 self.tr('Debugger &Properties...'), 0, 0, 4393 self.tr("Debugger &Properties..."),
4158 self.dbgActGrp, 'project_debugger_properties') 4394 0,
4159 act.setStatusTip(self.tr('Show the debugger properties')) 4395 0,
4160 act.setWhatsThis(self.tr( 4396 self.dbgActGrp,
4161 """<b>Debugger Properties...</b>""" 4397 "project_debugger_properties",
4162 """<p>This shows a dialog to edit project specific debugger""" 4398 )
4163 """ settings.</p>""" 4399 act.setStatusTip(self.tr("Show the debugger properties"))
4164 )) 4400 act.setWhatsThis(
4401 self.tr(
4402 """<b>Debugger Properties...</b>"""
4403 """<p>This shows a dialog to edit project specific debugger"""
4404 """ settings.</p>"""
4405 )
4406 )
4165 act.triggered.connect(self.__showDebugProperties) 4407 act.triggered.connect(self.__showDebugProperties)
4166 self.actions.append(act) 4408 self.actions.append(act)
4167 4409
4168 act = EricAction( 4410 act = EricAction(
4169 self.tr('Load'), 4411 self.tr("Load"),
4170 self.tr('&Load'), 0, 0, 4412 self.tr("&Load"),
4171 self.dbgActGrp, 'project_debugger_properties_load') 4413 0,
4172 act.setStatusTip(self.tr('Load the debugger properties')) 4414 0,
4173 act.setWhatsThis(self.tr( 4415 self.dbgActGrp,
4174 """<b>Load Debugger Properties</b>""" 4416 "project_debugger_properties_load",
4175 """<p>This loads the project specific debugger settings.</p>""" 4417 )
4176 )) 4418 act.setStatusTip(self.tr("Load the debugger properties"))
4419 act.setWhatsThis(
4420 self.tr(
4421 """<b>Load Debugger Properties</b>"""
4422 """<p>This loads the project specific debugger settings.</p>"""
4423 )
4424 )
4177 act.triggered.connect(self.__readDebugProperties) 4425 act.triggered.connect(self.__readDebugProperties)
4178 self.actions.append(act) 4426 self.actions.append(act)
4179 4427
4180 act = EricAction( 4428 act = EricAction(
4181 self.tr('Save'), 4429 self.tr("Save"),
4182 self.tr('&Save'), 0, 0, 4430 self.tr("&Save"),
4183 self.dbgActGrp, 'project_debugger_properties_save') 4431 0,
4184 act.setStatusTip(self.tr('Save the debugger properties')) 4432 0,
4185 act.setWhatsThis(self.tr( 4433 self.dbgActGrp,
4186 """<b>Save Debugger Properties</b>""" 4434 "project_debugger_properties_save",
4187 """<p>This saves the project specific debugger settings.</p>""" 4435 )
4188 )) 4436 act.setStatusTip(self.tr("Save the debugger properties"))
4437 act.setWhatsThis(
4438 self.tr(
4439 """<b>Save Debugger Properties</b>"""
4440 """<p>This saves the project specific debugger settings.</p>"""
4441 )
4442 )
4189 act.triggered.connect(self.__writeDebugProperties) 4443 act.triggered.connect(self.__writeDebugProperties)
4190 self.actions.append(act) 4444 self.actions.append(act)
4191 4445
4192 act = EricAction( 4446 act = EricAction(
4193 self.tr('Delete'), 4447 self.tr("Delete"),
4194 self.tr('&Delete'), 0, 0, 4448 self.tr("&Delete"),
4195 self.dbgActGrp, 'project_debugger_properties_delete') 4449 0,
4196 act.setStatusTip(self.tr('Delete the debugger properties')) 4450 0,
4197 act.setWhatsThis(self.tr( 4451 self.dbgActGrp,
4198 """<b>Delete Debugger Properties</b>""" 4452 "project_debugger_properties_delete",
4199 """<p>This deletes the file containing the project specific""" 4453 )
4200 """ debugger settings.</p>""" 4454 act.setStatusTip(self.tr("Delete the debugger properties"))
4201 )) 4455 act.setWhatsThis(
4456 self.tr(
4457 """<b>Delete Debugger Properties</b>"""
4458 """<p>This deletes the file containing the project specific"""
4459 """ debugger settings.</p>"""
4460 )
4461 )
4202 act.triggered.connect(self.__deleteDebugProperties) 4462 act.triggered.connect(self.__deleteDebugProperties)
4203 self.actions.append(act) 4463 self.actions.append(act)
4204 4464
4205 act = EricAction( 4465 act = EricAction(
4206 self.tr('Reset'), 4466 self.tr("Reset"),
4207 self.tr('&Reset'), 0, 0, 4467 self.tr("&Reset"),
4208 self.dbgActGrp, 'project_debugger_properties_resets') 4468 0,
4209 act.setStatusTip(self.tr('Reset the debugger properties')) 4469 0,
4210 act.setWhatsThis(self.tr( 4470 self.dbgActGrp,
4211 """<b>Reset Debugger Properties</b>""" 4471 "project_debugger_properties_resets",
4212 """<p>This resets the project specific debugger settings.</p>""" 4472 )
4213 )) 4473 act.setStatusTip(self.tr("Reset the debugger properties"))
4474 act.setWhatsThis(
4475 self.tr(
4476 """<b>Reset Debugger Properties</b>"""
4477 """<p>This resets the project specific debugger settings.</p>"""
4478 )
4479 )
4214 act.triggered.connect(self.__initDebugProperties) 4480 act.triggered.connect(self.__initDebugProperties)
4215 self.actions.append(act) 4481 self.actions.append(act)
4216 4482
4217 ################################################################### 4483 ###################################################################
4218 ## Project session actions 4484 ## Project session actions
4219 ################################################################### 4485 ###################################################################
4220 4486
4221 self.sessActGrp = createActionGroup(self) 4487 self.sessActGrp = createActionGroup(self)
4222 4488
4223 act = EricAction( 4489 act = EricAction(
4224 self.tr('Load session'), 4490 self.tr("Load session"),
4225 self.tr('Load session'), 0, 0, 4491 self.tr("Load session"),
4226 self.sessActGrp, 'project_load_session') 4492 0,
4227 act.setStatusTip(self.tr('Load the projects session file.')) 4493 0,
4228 act.setWhatsThis(self.tr( 4494 self.sessActGrp,
4229 """<b>Load session</b>""" 4495 "project_load_session",
4230 """<p>This loads the projects session file. The session consists""" 4496 )
4231 """ of the following data.<br>""" 4497 act.setStatusTip(self.tr("Load the projects session file."))
4232 """- all open source files<br>""" 4498 act.setWhatsThis(
4233 """- all breakpoint<br>""" 4499 self.tr(
4234 """- the commandline arguments<br>""" 4500 """<b>Load session</b>"""
4235 """- the working directory<br>""" 4501 """<p>This loads the projects session file. The session consists"""
4236 """- the exception reporting flag</p>""" 4502 """ of the following data.<br>"""
4237 )) 4503 """- all open source files<br>"""
4504 """- all breakpoint<br>"""
4505 """- the commandline arguments<br>"""
4506 """- the working directory<br>"""
4507 """- the exception reporting flag</p>"""
4508 )
4509 )
4238 act.triggered.connect(self.__readSession) 4510 act.triggered.connect(self.__readSession)
4239 self.actions.append(act) 4511 self.actions.append(act)
4240 4512
4241 act = EricAction( 4513 act = EricAction(
4242 self.tr('Save session'), 4514 self.tr("Save session"),
4243 self.tr('Save session'), 0, 0, 4515 self.tr("Save session"),
4244 self.sessActGrp, 'project_save_session') 4516 0,
4245 act.setStatusTip(self.tr('Save the projects session file.')) 4517 0,
4246 act.setWhatsThis(self.tr( 4518 self.sessActGrp,
4247 """<b>Save session</b>""" 4519 "project_save_session",
4248 """<p>This saves the projects session file. The session consists""" 4520 )
4249 """ of the following data.<br>""" 4521 act.setStatusTip(self.tr("Save the projects session file."))
4250 """- all open source files<br>""" 4522 act.setWhatsThis(
4251 """- all breakpoint<br>""" 4523 self.tr(
4252 """- the commandline arguments<br>""" 4524 """<b>Save session</b>"""
4253 """- the working directory<br>""" 4525 """<p>This saves the projects session file. The session consists"""
4254 """- the exception reporting flag</p>""" 4526 """ of the following data.<br>"""
4255 )) 4527 """- all open source files<br>"""
4528 """- all breakpoint<br>"""
4529 """- the commandline arguments<br>"""
4530 """- the working directory<br>"""
4531 """- the exception reporting flag</p>"""
4532 )
4533 )
4256 act.triggered.connect(self.__writeSession) 4534 act.triggered.connect(self.__writeSession)
4257 self.actions.append(act) 4535 self.actions.append(act)
4258 4536
4259 act = EricAction( 4537 act = EricAction(
4260 self.tr('Delete session'), 4538 self.tr("Delete session"),
4261 self.tr('Delete session'), 0, 0, 4539 self.tr("Delete session"),
4262 self.sessActGrp, 'project_delete_session') 4540 0,
4263 act.setStatusTip(self.tr('Delete the projects session file.')) 4541 0,
4264 act.setWhatsThis(self.tr( 4542 self.sessActGrp,
4265 """<b>Delete session</b>""" 4543 "project_delete_session",
4266 """<p>This deletes the projects session file</p>""" 4544 )
4267 )) 4545 act.setStatusTip(self.tr("Delete the projects session file."))
4546 act.setWhatsThis(
4547 self.tr(
4548 """<b>Delete session</b>"""
4549 """<p>This deletes the projects session file</p>"""
4550 )
4551 )
4268 act.triggered.connect(self.__deleteSession) 4552 act.triggered.connect(self.__deleteSession)
4269 self.actions.append(act) 4553 self.actions.append(act)
4270 4554
4271 ################################################################### 4555 ###################################################################
4272 ## Project Tools - check actions 4556 ## Project Tools - check actions
4273 ################################################################### 4557 ###################################################################
4274 4558
4275 self.chkGrp = createActionGroup(self) 4559 self.chkGrp = createActionGroup(self)
4276 4560
4277 self.codeMetricsAct = EricAction( 4561 self.codeMetricsAct = EricAction(
4278 self.tr('Code Metrics'), 4562 self.tr("Code Metrics"),
4279 self.tr('&Code Metrics...'), 0, 0, 4563 self.tr("&Code Metrics..."),
4280 self.chkGrp, 'project_code_metrics') 4564 0,
4565 0,
4566 self.chkGrp,
4567 "project_code_metrics",
4568 )
4281 self.codeMetricsAct.setStatusTip( 4569 self.codeMetricsAct.setStatusTip(
4282 self.tr('Show some code metrics for the project.')) 4570 self.tr("Show some code metrics for the project.")
4283 self.codeMetricsAct.setWhatsThis(self.tr( 4571 )
4284 """<b>Code Metrics...</b>""" 4572 self.codeMetricsAct.setWhatsThis(
4285 """<p>This shows some code metrics for all Python files in""" 4573 self.tr(
4286 """ the project.</p>""" 4574 """<b>Code Metrics...</b>"""
4287 )) 4575 """<p>This shows some code metrics for all Python files in"""
4576 """ the project.</p>"""
4577 )
4578 )
4288 self.codeMetricsAct.triggered.connect(self.__showCodeMetrics) 4579 self.codeMetricsAct.triggered.connect(self.__showCodeMetrics)
4289 self.actions.append(self.codeMetricsAct) 4580 self.actions.append(self.codeMetricsAct)
4290 4581
4291 self.codeCoverageAct = EricAction( 4582 self.codeCoverageAct = EricAction(
4292 self.tr('Python Code Coverage'), 4583 self.tr("Python Code Coverage"),
4293 self.tr('Code Co&verage...'), 0, 0, 4584 self.tr("Code Co&verage..."),
4294 self.chkGrp, 'project_code_coverage') 4585 0,
4586 0,
4587 self.chkGrp,
4588 "project_code_coverage",
4589 )
4295 self.codeCoverageAct.setStatusTip( 4590 self.codeCoverageAct.setStatusTip(
4296 self.tr('Show code coverage information for the project.')) 4591 self.tr("Show code coverage information for the project.")
4297 self.codeCoverageAct.setWhatsThis(self.tr( 4592 )
4298 """<b>Code Coverage...</b>""" 4593 self.codeCoverageAct.setWhatsThis(
4299 """<p>This shows the code coverage information for all Python""" 4594 self.tr(
4300 """ files in the project.</p>""" 4595 """<b>Code Coverage...</b>"""
4301 )) 4596 """<p>This shows the code coverage information for all Python"""
4597 """ files in the project.</p>"""
4598 )
4599 )
4302 self.codeCoverageAct.triggered.connect(self.__showCodeCoverage) 4600 self.codeCoverageAct.triggered.connect(self.__showCodeCoverage)
4303 self.actions.append(self.codeCoverageAct) 4601 self.actions.append(self.codeCoverageAct)
4304 4602
4305 self.codeProfileAct = EricAction( 4603 self.codeProfileAct = EricAction(
4306 self.tr('Profile Data'), 4604 self.tr("Profile Data"),
4307 self.tr('&Profile Data...'), 0, 0, 4605 self.tr("&Profile Data..."),
4308 self.chkGrp, 'project_profile_data') 4606 0,
4607 0,
4608 self.chkGrp,
4609 "project_profile_data",
4610 )
4309 self.codeProfileAct.setStatusTip( 4611 self.codeProfileAct.setStatusTip(
4310 self.tr('Show profiling data for the project.')) 4612 self.tr("Show profiling data for the project.")
4311 self.codeProfileAct.setWhatsThis(self.tr( 4613 )
4312 """<b>Profile Data...</b>""" 4614 self.codeProfileAct.setWhatsThis(
4313 """<p>This shows the profiling data for the project.</p>""" 4615 self.tr(
4314 )) 4616 """<b>Profile Data...</b>"""
4617 """<p>This shows the profiling data for the project.</p>"""
4618 )
4619 )
4315 self.codeProfileAct.triggered.connect(self.__showProfileData) 4620 self.codeProfileAct.triggered.connect(self.__showProfileData)
4316 self.actions.append(self.codeProfileAct) 4621 self.actions.append(self.codeProfileAct)
4317 4622
4318 ################################################################### 4623 ###################################################################
4319 ## Project Tools - graphics actions 4624 ## Project Tools - graphics actions
4320 ################################################################### 4625 ###################################################################
4321 4626
4322 self.graphicsGrp = createActionGroup(self) 4627 self.graphicsGrp = createActionGroup(self)
4323 4628
4324 self.applicationDiagramAct = EricAction( 4629 self.applicationDiagramAct = EricAction(
4325 self.tr('Application Diagram'), 4630 self.tr("Application Diagram"),
4326 self.tr('&Application Diagram...'), 0, 0, 4631 self.tr("&Application Diagram..."),
4327 self.graphicsGrp, 'project_application_diagram') 4632 0,
4633 0,
4634 self.graphicsGrp,
4635 "project_application_diagram",
4636 )
4328 self.applicationDiagramAct.setStatusTip( 4637 self.applicationDiagramAct.setStatusTip(
4329 self.tr('Show a diagram of the project.')) 4638 self.tr("Show a diagram of the project.")
4330 self.applicationDiagramAct.setWhatsThis(self.tr( 4639 )
4331 """<b>Application Diagram...</b>""" 4640 self.applicationDiagramAct.setWhatsThis(
4332 """<p>This shows a diagram of the project.</p>""" 4641 self.tr(
4333 )) 4642 """<b>Application Diagram...</b>"""
4334 self.applicationDiagramAct.triggered.connect( 4643 """<p>This shows a diagram of the project.</p>"""
4335 self.handleApplicationDiagram) 4644 )
4645 )
4646 self.applicationDiagramAct.triggered.connect(self.handleApplicationDiagram)
4336 self.actions.append(self.applicationDiagramAct) 4647 self.actions.append(self.applicationDiagramAct)
4337 4648
4338 self.loadDiagramAct = EricAction( 4649 self.loadDiagramAct = EricAction(
4339 self.tr('Load Diagram'), 4650 self.tr("Load Diagram"),
4340 self.tr('&Load Diagram...'), 0, 0, 4651 self.tr("&Load Diagram..."),
4341 self.graphicsGrp, 'project_load_diagram') 4652 0,
4342 self.loadDiagramAct.setStatusTip( 4653 0,
4343 self.tr('Load a diagram from file.')) 4654 self.graphicsGrp,
4344 self.loadDiagramAct.setWhatsThis(self.tr( 4655 "project_load_diagram",
4345 """<b>Load Diagram...</b>""" 4656 )
4346 """<p>This loads a diagram from file.</p>""" 4657 self.loadDiagramAct.setStatusTip(self.tr("Load a diagram from file."))
4347 )) 4658 self.loadDiagramAct.setWhatsThis(
4659 self.tr(
4660 """<b>Load Diagram...</b>"""
4661 """<p>This loads a diagram from file.</p>"""
4662 )
4663 )
4348 self.loadDiagramAct.triggered.connect(self.__loadDiagram) 4664 self.loadDiagramAct.triggered.connect(self.__loadDiagram)
4349 self.actions.append(self.loadDiagramAct) 4665 self.actions.append(self.loadDiagramAct)
4350 4666
4351 ################################################################### 4667 ###################################################################
4352 ## Project Tools - plugin packaging actions 4668 ## Project Tools - plugin packaging actions
4353 ################################################################### 4669 ###################################################################
4354 4670
4355 self.pluginGrp = createActionGroup(self) 4671 self.pluginGrp = createActionGroup(self)
4356 4672
4357 self.pluginPkgListAct = EricAction( 4673 self.pluginPkgListAct = EricAction(
4358 self.tr('Create Package List'), 4674 self.tr("Create Package List"),
4359 UI.PixmapCache.getIcon("pluginArchiveList"), 4675 UI.PixmapCache.getIcon("pluginArchiveList"),
4360 self.tr('Create &Package List'), 0, 0, 4676 self.tr("Create &Package List"),
4361 self.pluginGrp, 'project_plugin_pkglist') 4677 0,
4678 0,
4679 self.pluginGrp,
4680 "project_plugin_pkglist",
4681 )
4362 self.pluginPkgListAct.setStatusTip( 4682 self.pluginPkgListAct.setStatusTip(
4363 self.tr('Create an initial PKGLIST file for an eric plugin.')) 4683 self.tr("Create an initial PKGLIST file for an eric plugin.")
4364 self.pluginPkgListAct.setWhatsThis(self.tr( 4684 )
4365 """<b>Create Package List</b>""" 4685 self.pluginPkgListAct.setWhatsThis(
4366 """<p>This creates an initial list of files to include in an""" 4686 self.tr(
4367 """ eric plugin archive. The list is created from the project""" 4687 """<b>Create Package List</b>"""
4368 """ file.</p>""" 4688 """<p>This creates an initial list of files to include in an"""
4369 )) 4689 """ eric plugin archive. The list is created from the project"""
4690 """ file.</p>"""
4691 )
4692 )
4370 self.pluginPkgListAct.triggered.connect(self.__pluginCreatePkgList) 4693 self.pluginPkgListAct.triggered.connect(self.__pluginCreatePkgList)
4371 self.actions.append(self.pluginPkgListAct) 4694 self.actions.append(self.pluginPkgListAct)
4372 4695
4373 self.pluginArchiveAct = EricAction( 4696 self.pluginArchiveAct = EricAction(
4374 self.tr('Create Plugin Archives'), 4697 self.tr("Create Plugin Archives"),
4375 UI.PixmapCache.getIcon("pluginArchive"), 4698 UI.PixmapCache.getIcon("pluginArchive"),
4376 self.tr('Create Plugin &Archives'), 0, 0, 4699 self.tr("Create Plugin &Archives"),
4377 self.pluginGrp, 'project_plugin_archive') 4700 0,
4378 self.pluginArchiveAct.setStatusTip( 4701 0,
4379 self.tr('Create eric plugin archive files.')) 4702 self.pluginGrp,
4380 self.pluginArchiveAct.setWhatsThis(self.tr( 4703 "project_plugin_archive",
4381 """<b>Create Plugin Archives</b>""" 4704 )
4382 """<p>This creates eric plugin archive files using the list""" 4705 self.pluginArchiveAct.setStatusTip(self.tr("Create eric plugin archive files."))
4383 """ of files given in a PKGLIST* file. The archive name is""" 4706 self.pluginArchiveAct.setWhatsThis(
4384 """ built from the main script name if not designated in""" 4707 self.tr(
4385 """ the package list file.</p>""" 4708 """<b>Create Plugin Archives</b>"""
4386 )) 4709 """<p>This creates eric plugin archive files using the list"""
4710 """ of files given in a PKGLIST* file. The archive name is"""
4711 """ built from the main script name if not designated in"""
4712 """ the package list file.</p>"""
4713 )
4714 )
4387 self.pluginArchiveAct.triggered.connect(self.__pluginCreateArchives) 4715 self.pluginArchiveAct.triggered.connect(self.__pluginCreateArchives)
4388 self.actions.append(self.pluginArchiveAct) 4716 self.actions.append(self.pluginArchiveAct)
4389 4717
4390 self.pluginSArchiveAct = EricAction( 4718 self.pluginSArchiveAct = EricAction(
4391 self.tr('Create Plugin Archives (Snapshot)'), 4719 self.tr("Create Plugin Archives (Snapshot)"),
4392 UI.PixmapCache.getIcon("pluginArchiveSnapshot"), 4720 UI.PixmapCache.getIcon("pluginArchiveSnapshot"),
4393 self.tr('Create Plugin Archives (&Snapshot)'), 0, 0, 4721 self.tr("Create Plugin Archives (&Snapshot)"),
4394 self.pluginGrp, 'project_plugin_sarchive') 4722 0,
4395 self.pluginSArchiveAct.setStatusTip(self.tr( 4723 0,
4396 'Create eric plugin archive files (snapshot releases).')) 4724 self.pluginGrp,
4397 self.pluginSArchiveAct.setWhatsThis(self.tr( 4725 "project_plugin_sarchive",
4398 """<b>Create Plugin Archives (Snapshot)</b>""" 4726 )
4399 """<p>This creates eric plugin archive files using the list""" 4727 self.pluginSArchiveAct.setStatusTip(
4400 """ of files given in the PKGLIST* file. The archive name is""" 4728 self.tr("Create eric plugin archive files (snapshot releases).")
4401 """ built from the main script name if not designated in""" 4729 )
4402 """ the package list file. The version entry of the main script""" 4730 self.pluginSArchiveAct.setWhatsThis(
4403 """ is modified to reflect a snapshot release.</p>""" 4731 self.tr(
4404 )) 4732 """<b>Create Plugin Archives (Snapshot)</b>"""
4405 self.pluginSArchiveAct.triggered.connect( 4733 """<p>This creates eric plugin archive files using the list"""
4406 self.__pluginCreateSnapshotArchives) 4734 """ of files given in the PKGLIST* file. The archive name is"""
4735 """ built from the main script name if not designated in"""
4736 """ the package list file. The version entry of the main script"""
4737 """ is modified to reflect a snapshot release.</p>"""
4738 )
4739 )
4740 self.pluginSArchiveAct.triggered.connect(self.__pluginCreateSnapshotArchives)
4407 self.actions.append(self.pluginSArchiveAct) 4741 self.actions.append(self.pluginSArchiveAct)
4408 4742
4409 ################################################################### 4743 ###################################################################
4410 ## Project Tools - make actions 4744 ## Project Tools - make actions
4411 ################################################################### 4745 ###################################################################
4412 4746
4413 self.makeGrp = createActionGroup(self) 4747 self.makeGrp = createActionGroup(self)
4414 4748
4415 self.makeExecuteAct = EricAction( 4749 self.makeExecuteAct = EricAction(
4416 self.tr('Execute Make'), 4750 self.tr("Execute Make"),
4417 self.tr('&Execute Make'), 0, 0, 4751 self.tr("&Execute Make"),
4418 self.makeGrp, 'project_make_execute') 4752 0,
4419 self.makeExecuteAct.setStatusTip( 4753 0,
4420 self.tr("Perform a 'make' run.")) 4754 self.makeGrp,
4421 self.makeExecuteAct.setWhatsThis(self.tr( 4755 "project_make_execute",
4422 """<b>Execute Make</b>""" 4756 )
4423 """<p>This performs a 'make' run to rebuild the configured""" 4757 self.makeExecuteAct.setStatusTip(self.tr("Perform a 'make' run."))
4424 """ target.</p>""" 4758 self.makeExecuteAct.setWhatsThis(
4425 )) 4759 self.tr(
4760 """<b>Execute Make</b>"""
4761 """<p>This performs a 'make' run to rebuild the configured"""
4762 """ target.</p>"""
4763 )
4764 )
4426 self.makeExecuteAct.triggered.connect(self.__executeMake) 4765 self.makeExecuteAct.triggered.connect(self.__executeMake)
4427 self.actions.append(self.makeExecuteAct) 4766 self.actions.append(self.makeExecuteAct)
4428 4767
4429 self.makeTestAct = EricAction( 4768 self.makeTestAct = EricAction(
4430 self.tr('Test for Changes'), 4769 self.tr("Test for Changes"),
4431 self.tr('&Test for Changes'), 0, 0, 4770 self.tr("&Test for Changes"),
4432 self.makeGrp, 'project_make_test') 4771 0,
4772 0,
4773 self.makeGrp,
4774 "project_make_test",
4775 )
4433 self.makeTestAct.setStatusTip( 4776 self.makeTestAct.setStatusTip(
4434 self.tr("Question 'make', if a rebuild is needed.")) 4777 self.tr("Question 'make', if a rebuild is needed.")
4435 self.makeTestAct.setWhatsThis(self.tr( 4778 )
4436 """<b>Test for Changes</b>""" 4779 self.makeTestAct.setWhatsThis(
4437 """<p>This questions 'make', if a rebuild of the configured""" 4780 self.tr(
4438 """ target is necessary.</p>""" 4781 """<b>Test for Changes</b>"""
4439 )) 4782 """<p>This questions 'make', if a rebuild of the configured"""
4783 """ target is necessary.</p>"""
4784 )
4785 )
4440 self.makeTestAct.triggered.connect( 4786 self.makeTestAct.triggered.connect(
4441 lambda: self.__executeMake(questionOnly=True)) 4787 lambda: self.__executeMake(questionOnly=True)
4788 )
4442 self.actions.append(self.makeTestAct) 4789 self.actions.append(self.makeTestAct)
4443 4790
4444 ################################################################### 4791 ###################################################################
4445 ## Project Tools - other tools actions 4792 ## Project Tools - other tools actions
4446 ################################################################### 4793 ###################################################################
4447 4794
4448 self.othersGrp = createActionGroup(self) 4795 self.othersGrp = createActionGroup(self)
4449 4796
4450 self.createSBOMAct = EricAction( 4797 self.createSBOMAct = EricAction(
4451 self.tr('Create SBOM File'), 4798 self.tr("Create SBOM File"),
4452 self.tr('Create &SBOM File'), 0, 0, 4799 self.tr("Create &SBOM File"),
4453 self.othersGrp, 'project_create_sbom') 4800 0,
4801 0,
4802 self.othersGrp,
4803 "project_create_sbom",
4804 )
4454 self.createSBOMAct.setStatusTip( 4805 self.createSBOMAct.setStatusTip(
4455 self.tr("Create a SBOM file of the project dependencies.")) 4806 self.tr("Create a SBOM file of the project dependencies.")
4456 self.createSBOMAct.setWhatsThis(self.tr( 4807 )
4457 """<b>Create SBOM File</b>""" 4808 self.createSBOMAct.setWhatsThis(
4458 """<p>This allows the creation of a SBOM file of the project""" 4809 self.tr(
4459 """ dependencies. This may be based on various input sources""" 4810 """<b>Create SBOM File</b>"""
4460 """ and will be saved as a CycloneDX SBOM file.</p>""" 4811 """<p>This allows the creation of a SBOM file of the project"""
4461 )) 4812 """ dependencies. This may be based on various input sources"""
4813 """ and will be saved as a CycloneDX SBOM file.</p>"""
4814 )
4815 )
4462 self.createSBOMAct.triggered.connect(self.__createSBOMFile) 4816 self.createSBOMAct.triggered.connect(self.__createSBOMFile)
4463 self.actions.append(self.createSBOMAct) 4817 self.actions.append(self.createSBOMAct)
4464 4818
4465 ################################################################### 4819 ###################################################################
4466 ## Project Tools - code formatting actions 4820 ## Project Tools - code formatting actions
4467 ################################################################### 4821 ###################################################################
4468 4822
4469 self.blackFormattingGrp = createActionGroup(self) 4823 self.blackFormattingGrp = createActionGroup(self)
4470 4824
4471 self.blackAboutAct = EricAction( 4825 self.blackAboutAct = EricAction(
4472 self.tr("About Black"), 4826 self.tr("About Black"),
4473 self.tr("&Black"), 4827 self.tr("&Black"),
4474 0, 0, 4828 0,
4475 self.blackFormattingGrp, "project_black_about" 4829 0,
4476 ) 4830 self.blackFormattingGrp,
4477 self.blackAboutAct.setStatusTip( 4831 "project_black_about",
4478 self.tr("Show some information about 'Black'.") 4832 )
4479 ) 4833 self.blackAboutAct.setStatusTip(self.tr("Show some information about 'Black'."))
4480 self.blackAboutAct.setWhatsThis(self.tr( 4834 self.blackAboutAct.setWhatsThis(
4481 "<b>Black</b>" 4835 self.tr(
4482 "<p>This shows some information about the installed 'Black' tool.</p>" 4836 "<b>Black</b>"
4483 )) 4837 "<p>This shows some information about the installed 'Black' tool.</p>"
4838 )
4839 )
4484 self.blackAboutAct.triggered.connect(self.__aboutBlack) 4840 self.blackAboutAct.triggered.connect(self.__aboutBlack)
4485 self.actions.append(self.blackAboutAct) 4841 self.actions.append(self.blackAboutAct)
4486 font = self.blackAboutAct.font() 4842 font = self.blackAboutAct.font()
4487 font.setBold(True) 4843 font.setBold(True)
4488 self.blackAboutAct.setFont(font) 4844 self.blackAboutAct.setFont(font)
4489 4845
4490 self.blackFormatAct = EricAction( 4846 self.blackFormatAct = EricAction(
4491 self.tr("Format Code"), 4847 self.tr("Format Code"),
4492 self.tr("&Format Code"), 4848 self.tr("&Format Code"),
4493 0, 0, 4849 0,
4494 self.blackFormattingGrp, "project_black_format_code" 4850 0,
4851 self.blackFormattingGrp,
4852 "project_black_format_code",
4495 ) 4853 )
4496 self.blackFormatAct.setStatusTip( 4854 self.blackFormatAct.setStatusTip(
4497 self.tr("Format the project sources with 'Black'.") 4855 self.tr("Format the project sources with 'Black'.")
4498 ) 4856 )
4499 self.blackFormatAct.setWhatsThis(self.tr( 4857 self.blackFormatAct.setWhatsThis(
4500 "<b>Format Code</b>" 4858 self.tr(
4501 "<p>This shows a dialog to enter parameters for the formatting run and" 4859 "<b>Format Code</b>"
4502 " reformats the project sources using 'Black'.</p>" 4860 "<p>This shows a dialog to enter parameters for the formatting run and"
4503 )) 4861 " reformats the project sources using 'Black'.</p>"
4862 )
4863 )
4504 self.blackFormatAct.triggered.connect( 4864 self.blackFormatAct.triggered.connect(
4505 lambda: self.__performFormatWithBlack(BlackFormattingAction.Format) 4865 lambda: self.__performFormatWithBlack(BlackFormattingAction.Format)
4506 ) 4866 )
4507 self.actions.append(self.blackFormatAct) 4867 self.actions.append(self.blackFormatAct)
4508 4868
4509 self.blackCheckFormattingAct = EricAction( 4869 self.blackCheckFormattingAct = EricAction(
4510 self.tr("Check Code Formatting"), 4870 self.tr("Check Code Formatting"),
4511 self.tr("&Check Code Formatting"), 4871 self.tr("&Check Code Formatting"),
4512 0, 0, 4872 0,
4513 self.blackFormattingGrp, "project_black_check_code" 4873 0,
4874 self.blackFormattingGrp,
4875 "project_black_check_code",
4514 ) 4876 )
4515 self.blackCheckFormattingAct.setStatusTip( 4877 self.blackCheckFormattingAct.setStatusTip(
4516 self.tr( 4878 self.tr(
4517 "Check, if the project sources need to be reformatted with 'Black'." 4879 "Check, if the project sources need to be reformatted with 'Black'."
4518 ) 4880 )
4519 ) 4881 )
4520 self.blackCheckFormattingAct.setWhatsThis(self.tr( 4882 self.blackCheckFormattingAct.setWhatsThis(
4521 "<b>Check Code Formatting</b>" 4883 self.tr(
4522 "<p>This shows a dialog to enter parameters for the format check run and" 4884 "<b>Check Code Formatting</b>"
4523 " performs a check, if the project sources need to be reformatted using" 4885 "<p>This shows a dialog to enter parameters for the format check run"
4524 " 'Black'.</p>" 4886 " and performs a check, if the project sources need to be reformatted"
4525 )) 4887 " using Black'.</p>"
4888 )
4889 )
4526 self.blackCheckFormattingAct.triggered.connect( 4890 self.blackCheckFormattingAct.triggered.connect(
4527 lambda: self.__performFormatWithBlack(BlackFormattingAction.Check) 4891 lambda: self.__performFormatWithBlack(BlackFormattingAction.Check)
4528 ) 4892 )
4529 self.actions.append(self.blackCheckFormattingAct) 4893 self.actions.append(self.blackCheckFormattingAct)
4530 4894
4531 self.blackDiffFormattingAct = EricAction( 4895 self.blackDiffFormattingAct = EricAction(
4532 self.tr("Code Formatting Diff"), 4896 self.tr("Code Formatting Diff"),
4533 self.tr("Code Formatting &Diff"), 4897 self.tr("Code Formatting &Diff"),
4534 0, 0, 4898 0,
4535 self.blackFormattingGrp, "project_black_diff_code" 4899 0,
4900 self.blackFormattingGrp,
4901 "project_black_diff_code",
4536 ) 4902 )
4537 self.blackDiffFormattingAct.setStatusTip( 4903 self.blackDiffFormattingAct.setStatusTip(
4538 self.tr( 4904 self.tr(
4539 "Generate a unified diff of potential project source reformatting" 4905 "Generate a unified diff of potential project source reformatting"
4540 " with 'Black'." 4906 " with 'Black'."
4541 ) 4907 )
4542 ) 4908 )
4543 self.blackDiffFormattingAct.setWhatsThis(self.tr( 4909 self.blackDiffFormattingAct.setWhatsThis(
4544 "<b>Diff Code Formatting</b>" 4910 self.tr(
4545 "<p>This shows a dialog to enter parameters for the format diff run and" 4911 "<b>Diff Code Formatting</b>"
4546 " generates a unified diff of potential project source reformatting using" 4912 "<p>This shows a dialog to enter parameters for the format diff run and"
4547 " 'Black'.</p>" 4913 " generates a unified diff of potential project source reformatting"
4548 )) 4914 " using Black'.</p>"
4915 )
4916 )
4549 self.blackDiffFormattingAct.triggered.connect( 4917 self.blackDiffFormattingAct.triggered.connect(
4550 lambda: self.__performFormatWithBlack(BlackFormattingAction.Diff) 4918 lambda: self.__performFormatWithBlack(BlackFormattingAction.Diff)
4551 ) 4919 )
4552 self.actions.append(self.blackDiffFormattingAct) 4920 self.actions.append(self.blackDiffFormattingAct)
4553 4921
4554 self.closeAct.setEnabled(False) 4922 self.closeAct.setEnabled(False)
4555 self.saveAct.setEnabled(False) 4923 self.saveAct.setEnabled(False)
4556 self.saveasAct.setEnabled(False) 4924 self.saveasAct.setEnabled(False)
4557 self.actGrp2.setEnabled(False) 4925 self.actGrp2.setEnabled(False)
4558 self.propsAct.setEnabled(False) 4926 self.propsAct.setEnabled(False)
4560 self.filetypesAct.setEnabled(False) 4928 self.filetypesAct.setEnabled(False)
4561 self.lexersAct.setEnabled(False) 4929 self.lexersAct.setEnabled(False)
4562 self.sessActGrp.setEnabled(False) 4930 self.sessActGrp.setEnabled(False)
4563 self.dbgActGrp.setEnabled(False) 4931 self.dbgActGrp.setEnabled(False)
4564 self.pluginGrp.setEnabled(False) 4932 self.pluginGrp.setEnabled(False)
4565 4933
4566 def initMenus(self): 4934 def initMenus(self):
4567 """ 4935 """
4568 Public slot to initialize the project menus. 4936 Public slot to initialize the project menus.
4569 4937
4570 @return tuple of generated menus 4938 @return tuple of generated menus
4571 @rtype tuple of (QMenu, QMenu) 4939 @rtype tuple of (QMenu, QMenu)
4572 """ 4940 """
4573 menu = QMenu(self.tr('&Project'), self.parent()) 4941 menu = QMenu(self.tr("&Project"), self.parent())
4574 self.recentMenu = QMenu(self.tr('Open &Recent Projects'), menu) 4942 self.recentMenu = QMenu(self.tr("Open &Recent Projects"), menu)
4575 self.sessionMenu = QMenu(self.tr('Session'), menu) 4943 self.sessionMenu = QMenu(self.tr("Session"), menu)
4576 self.debuggerMenu = QMenu(self.tr('Debugger'), menu) 4944 self.debuggerMenu = QMenu(self.tr("Debugger"), menu)
4577 4945
4578 toolsMenu = QMenu(self.tr('Project-T&ools'), self.parent()) 4946 toolsMenu = QMenu(self.tr("Project-T&ools"), self.parent())
4579 self.vcsMenu = QMenu(self.tr('&Version Control'), toolsMenu) 4947 self.vcsMenu = QMenu(self.tr("&Version Control"), toolsMenu)
4580 self.vcsMenu.setTearOffEnabled(True) 4948 self.vcsMenu.setTearOffEnabled(True)
4581 self.vcsProjectHelper.initMenu(self.vcsMenu) 4949 self.vcsProjectHelper.initMenu(self.vcsMenu)
4582 self.vcsMenu.setEnabled(self.vcsSoftwareAvailable()) 4950 self.vcsMenu.setEnabled(self.vcsSoftwareAvailable())
4583 self.checksMenu = QMenu(self.tr('Chec&k'), toolsMenu) 4951 self.checksMenu = QMenu(self.tr("Chec&k"), toolsMenu)
4584 self.checksMenu.setTearOffEnabled(True) 4952 self.checksMenu.setTearOffEnabled(True)
4585 self.formattingMenu = QMenu(self.tr("Code &Formatting"), toolsMenu) 4953 self.formattingMenu = QMenu(self.tr("Code &Formatting"), toolsMenu)
4586 self.formattingMenu.setTearOffEnabled(True) 4954 self.formattingMenu.setTearOffEnabled(True)
4587 self.menuShow = QMenu(self.tr('Sho&w'), toolsMenu) 4955 self.menuShow = QMenu(self.tr("Sho&w"), toolsMenu)
4588 self.graphicsMenu = QMenu(self.tr('&Diagrams'), toolsMenu) 4956 self.graphicsMenu = QMenu(self.tr("&Diagrams"), toolsMenu)
4589 self.packagersMenu = QMenu(self.tr('Pac&kagers'), toolsMenu) 4957 self.packagersMenu = QMenu(self.tr("Pac&kagers"), toolsMenu)
4590 self.apidocMenu = QMenu(self.tr('Source &Documentation'), toolsMenu) 4958 self.apidocMenu = QMenu(self.tr("Source &Documentation"), toolsMenu)
4591 self.apidocMenu.setTearOffEnabled(True) 4959 self.apidocMenu.setTearOffEnabled(True)
4592 self.makeMenu = QMenu(self.tr('Make'), toolsMenu) 4960 self.makeMenu = QMenu(self.tr("Make"), toolsMenu)
4593 self.othersMenu = QMenu(self.tr('Other Tools'), toolsMenu) 4961 self.othersMenu = QMenu(self.tr("Other Tools"), toolsMenu)
4594 4962
4595 self.__menus = { 4963 self.__menus = {
4596 "Main": menu, 4964 "Main": menu,
4597 "Recent": self.recentMenu, 4965 "Recent": self.recentMenu,
4598 "VCS": self.vcsMenu, 4966 "VCS": self.vcsMenu,
4599 "Checks": self.checksMenu, 4967 "Checks": self.checksMenu,
4605 "Packagers": self.packagersMenu, 4973 "Packagers": self.packagersMenu,
4606 "Make": self.makeMenu, 4974 "Make": self.makeMenu,
4607 "OtherTools": self.othersMenu, 4975 "OtherTools": self.othersMenu,
4608 "Formatting": self.formattingMenu, 4976 "Formatting": self.formattingMenu,
4609 } 4977 }
4610 4978
4611 # connect the aboutToShow signals 4979 # connect the aboutToShow signals
4612 self.recentMenu.aboutToShow.connect(self.__showContextMenuRecent) 4980 self.recentMenu.aboutToShow.connect(self.__showContextMenuRecent)
4613 self.recentMenu.triggered.connect(self.__openRecent) 4981 self.recentMenu.triggered.connect(self.__openRecent)
4614 self.vcsMenu.aboutToShow.connect(self.__showContextMenuVCS) 4982 self.vcsMenu.aboutToShow.connect(self.__showContextMenuVCS)
4615 self.checksMenu.aboutToShow.connect(self.__showContextMenuChecks) 4983 self.checksMenu.aboutToShow.connect(self.__showContextMenuChecks)
4621 self.debuggerMenu.aboutToShow.connect(self.__showContextMenuDebugger) 4989 self.debuggerMenu.aboutToShow.connect(self.__showContextMenuDebugger)
4622 self.makeMenu.aboutToShow.connect(self.__showContextMenuMake) 4990 self.makeMenu.aboutToShow.connect(self.__showContextMenuMake)
4623 self.othersMenu.aboutToShow.connect(self.__showContextMenuOthers) 4991 self.othersMenu.aboutToShow.connect(self.__showContextMenuOthers)
4624 self.formattingMenu.aboutToShow.connect(self.__showContextMenuFormat) 4992 self.formattingMenu.aboutToShow.connect(self.__showContextMenuFormat)
4625 menu.aboutToShow.connect(self.__showMenu) 4993 menu.aboutToShow.connect(self.__showMenu)
4626 4994
4627 # build the show menu 4995 # build the show menu
4628 self.menuShow.setTearOffEnabled(True) 4996 self.menuShow.setTearOffEnabled(True)
4629 self.menuShow.addAction(self.codeMetricsAct) 4997 self.menuShow.addAction(self.codeMetricsAct)
4630 self.menuShow.addAction(self.codeCoverageAct) 4998 self.menuShow.addAction(self.codeCoverageAct)
4631 self.menuShow.addAction(self.codeProfileAct) 4999 self.menuShow.addAction(self.codeProfileAct)
4632 5000
4633 # build the diagrams menu 5001 # build the diagrams menu
4634 self.graphicsMenu.setTearOffEnabled(True) 5002 self.graphicsMenu.setTearOffEnabled(True)
4635 self.graphicsMenu.addAction(self.applicationDiagramAct) 5003 self.graphicsMenu.addAction(self.applicationDiagramAct)
4636 self.graphicsMenu.addSeparator() 5004 self.graphicsMenu.addSeparator()
4637 self.graphicsMenu.addAction(self.loadDiagramAct) 5005 self.graphicsMenu.addAction(self.loadDiagramAct)
4638 5006
4639 # build the session menu 5007 # build the session menu
4640 self.sessionMenu.setTearOffEnabled(True) 5008 self.sessionMenu.setTearOffEnabled(True)
4641 self.sessionMenu.addActions(self.sessActGrp.actions()) 5009 self.sessionMenu.addActions(self.sessActGrp.actions())
4642 5010
4643 # build the debugger menu 5011 # build the debugger menu
4644 self.debuggerMenu.setTearOffEnabled(True) 5012 self.debuggerMenu.setTearOffEnabled(True)
4645 self.debuggerMenu.addActions(self.dbgActGrp.actions()) 5013 self.debuggerMenu.addActions(self.dbgActGrp.actions())
4646 5014
4647 # build the packagers menu 5015 # build the packagers menu
4648 self.packagersMenu.setTearOffEnabled(True) 5016 self.packagersMenu.setTearOffEnabled(True)
4649 self.packagersMenu.addActions(self.pluginGrp.actions()) 5017 self.packagersMenu.addActions(self.pluginGrp.actions())
4650 self.packagersMenu.addSeparator() 5018 self.packagersMenu.addSeparator()
4651 5019
4652 # build the make menu 5020 # build the make menu
4653 self.makeMenu.setTearOffEnabled(True) 5021 self.makeMenu.setTearOffEnabled(True)
4654 self.makeMenu.addActions(self.makeGrp.actions()) 5022 self.makeMenu.addActions(self.makeGrp.actions())
4655 self.makeMenu.addSeparator() 5023 self.makeMenu.addSeparator()
4656 5024
4657 # build the 'Other Tools' menu 5025 # build the 'Other Tools' menu
4658 self.othersMenu.setTearOffEnabled(True) 5026 self.othersMenu.setTearOffEnabled(True)
4659 self.othersMenu.addActions(self.othersGrp.actions()) 5027 self.othersMenu.addActions(self.othersGrp.actions())
4660 self.othersMenu.addSeparator() 5028 self.othersMenu.addSeparator()
4661 5029
4662 # build the 'Code Formatting' menu 5030 # build the 'Code Formatting' menu
4663 self.formattingMenu.setTearOffEnabled(True) 5031 self.formattingMenu.setTearOffEnabled(True)
4664 self.formattingMenu.addActions(self.blackFormattingGrp.actions()) 5032 self.formattingMenu.addActions(self.blackFormattingGrp.actions())
4665 self.formattingMenu.addSeparator() 5033 self.formattingMenu.addSeparator()
4666 5034
4667 # build the project main menu 5035 # build the project main menu
4668 menu.setTearOffEnabled(True) 5036 menu.setTearOffEnabled(True)
4669 menu.addActions(self.actGrp1.actions()) 5037 menu.addActions(self.actGrp1.actions())
4670 self.menuRecentAct = menu.addMenu(self.recentMenu) 5038 self.menuRecentAct = menu.addMenu(self.recentMenu)
4671 menu.addSeparator() 5039 menu.addSeparator()
4681 menu.addAction(self.filetypesAct) 5049 menu.addAction(self.filetypesAct)
4682 menu.addAction(self.lexersAct) 5050 menu.addAction(self.lexersAct)
4683 menu.addSeparator() 5051 menu.addSeparator()
4684 self.menuDebuggerAct = menu.addMenu(self.debuggerMenu) 5052 self.menuDebuggerAct = menu.addMenu(self.debuggerMenu)
4685 self.menuSessionAct = menu.addMenu(self.sessionMenu) 5053 self.menuSessionAct = menu.addMenu(self.sessionMenu)
4686 5054
4687 # build the project tools menu 5055 # build the project tools menu
4688 toolsMenu.setTearOffEnabled(True) 5056 toolsMenu.setTearOffEnabled(True)
4689 toolsMenu.addSeparator() 5057 toolsMenu.addSeparator()
4690 toolsMenu.addMenu(self.vcsMenu) 5058 toolsMenu.addMenu(self.vcsMenu)
4691 toolsMenu.addSeparator() 5059 toolsMenu.addSeparator()
4702 self.menuApidocAct = toolsMenu.addMenu(self.apidocMenu) 5070 self.menuApidocAct = toolsMenu.addMenu(self.apidocMenu)
4703 toolsMenu.addSeparator() 5071 toolsMenu.addSeparator()
4704 self.menuPackagersAct = toolsMenu.addMenu(self.packagersMenu) 5072 self.menuPackagersAct = toolsMenu.addMenu(self.packagersMenu)
4705 toolsMenu.addSeparator() 5073 toolsMenu.addSeparator()
4706 self.menuOtherToolsAct = toolsMenu.addMenu(self.othersMenu) 5074 self.menuOtherToolsAct = toolsMenu.addMenu(self.othersMenu)
4707 5075
4708 self.menuCheckAct.setEnabled(False) 5076 self.menuCheckAct.setEnabled(False)
4709 self.menuShowAct.setEnabled(False) 5077 self.menuShowAct.setEnabled(False)
4710 self.menuDiagramAct.setEnabled(False) 5078 self.menuDiagramAct.setEnabled(False)
4711 self.menuSessionAct.setEnabled(False) 5079 self.menuSessionAct.setEnabled(False)
4712 self.menuDebuggerAct.setEnabled(False) 5080 self.menuDebuggerAct.setEnabled(False)
4713 self.menuApidocAct.setEnabled(False) 5081 self.menuApidocAct.setEnabled(False)
4714 self.menuPackagersAct.setEnabled(False) 5082 self.menuPackagersAct.setEnabled(False)
4715 self.menuMakeAct.setEnabled(False) 5083 self.menuMakeAct.setEnabled(False)
4716 self.menuOtherToolsAct.setEnabled(False) 5084 self.menuOtherToolsAct.setEnabled(False)
4717 self.menuFormattingAct.setEnabled(False) 5085 self.menuFormattingAct.setEnabled(False)
4718 5086
4719 self.__menu = menu 5087 self.__menu = menu
4720 self.__toolsMenu = toolsMenu 5088 self.__toolsMenu = toolsMenu
4721 5089
4722 return menu, toolsMenu 5090 return menu, toolsMenu
4723 5091
4724 def initToolbars(self, toolbarManager): 5092 def initToolbars(self, toolbarManager):
4725 """ 5093 """
4726 Public slot to initialize the project toolbar and the basic VCS 5094 Public slot to initialize the project toolbar and the basic VCS
4727 toolbar. 5095 toolbar.
4728 5096
4729 @param toolbarManager reference to a toolbar manager object 5097 @param toolbarManager reference to a toolbar manager object
4730 (EricToolBarManager) 5098 (EricToolBarManager)
4731 @return tuple of the generated toolbars (tuple of two QToolBar) 5099 @return tuple of the generated toolbars (tuple of two QToolBar)
4732 """ 5100 """
4733 tb = QToolBar(self.tr("Project"), self.ui) 5101 tb = QToolBar(self.tr("Project"), self.ui)
4734 tb.setIconSize(UI.Config.ToolBarIconSize) 5102 tb.setIconSize(UI.Config.ToolBarIconSize)
4735 tb.setObjectName("ProjectToolbar") 5103 tb.setObjectName("ProjectToolbar")
4736 tb.setToolTip(self.tr('Project')) 5104 tb.setToolTip(self.tr("Project"))
4737 5105
4738 tb.addActions(self.actGrp1.actions()) 5106 tb.addActions(self.actGrp1.actions())
4739 tb.addAction(self.closeAct) 5107 tb.addAction(self.closeAct)
4740 tb.addSeparator() 5108 tb.addSeparator()
4741 tb.addAction(self.saveAct) 5109 tb.addAction(self.saveAct)
4742 tb.addAction(self.saveasAct) 5110 tb.addAction(self.saveasAct)
4743 5111
4744 toolbarManager.addToolBar(tb, tb.windowTitle()) 5112 toolbarManager.addToolBar(tb, tb.windowTitle())
4745 toolbarManager.addAction(self.addFilesAct, tb.windowTitle()) 5113 toolbarManager.addAction(self.addFilesAct, tb.windowTitle())
4746 toolbarManager.addAction(self.addDirectoryAct, tb.windowTitle()) 5114 toolbarManager.addAction(self.addDirectoryAct, tb.windowTitle())
4747 toolbarManager.addAction(self.addLanguageAct, tb.windowTitle()) 5115 toolbarManager.addAction(self.addLanguageAct, tb.windowTitle())
4748 toolbarManager.addAction(self.propsAct, tb.windowTitle()) 5116 toolbarManager.addAction(self.propsAct, tb.windowTitle())
4749 toolbarManager.addAction(self.userPropsAct, tb.windowTitle()) 5117 toolbarManager.addAction(self.userPropsAct, tb.windowTitle())
4750 5118
4751 import VCS 5119 import VCS
4752 vcstb = VCS.getBasicHelper(self).initBasicToolbar( 5120
4753 self.ui, toolbarManager) 5121 vcstb = VCS.getBasicHelper(self).initBasicToolbar(self.ui, toolbarManager)
4754 5122
4755 return tb, vcstb 5123 return tb, vcstb
4756 5124
4757 def __showMenu(self): 5125 def __showMenu(self):
4758 """ 5126 """
4759 Private method to set up the project menu. 5127 Private method to set up the project menu.
4760 """ 5128 """
4761 self.menuRecentAct.setEnabled(len(self.recent) > 0) 5129 self.menuRecentAct.setEnabled(len(self.recent) > 0)
4762 5130
4763 self.showMenu.emit("Main", self.__menus["Main"]) 5131 self.showMenu.emit("Main", self.__menus["Main"])
4764 5132
4765 def __syncRecent(self): 5133 def __syncRecent(self):
4766 """ 5134 """
4767 Private method to synchronize the list of recently opened projects 5135 Private method to synchronize the list of recently opened projects
4768 with the central store. 5136 with the central store.
4769 """ 5137 """
4773 self.recent.insert(0, self.pfile) 5141 self.recent.insert(0, self.pfile)
4774 maxRecent = Preferences.getProject("RecentNumber") 5142 maxRecent = Preferences.getProject("RecentNumber")
4775 if len(self.recent) > maxRecent: 5143 if len(self.recent) > maxRecent:
4776 self.recent = self.recent[:maxRecent] 5144 self.recent = self.recent[:maxRecent]
4777 self.__saveRecent() 5145 self.__saveRecent()
4778 5146
4779 def __showContextMenuRecent(self): 5147 def __showContextMenuRecent(self):
4780 """ 5148 """
4781 Private method to set up the recent projects menu. 5149 Private method to set up the recent projects menu.
4782 """ 5150 """
4783 self.__loadRecent() 5151 self.__loadRecent()
4784 5152
4785 self.recentMenu.clear() 5153 self.recentMenu.clear()
4786 5154
4787 for idx, rp in enumerate(self.recent, start=1): 5155 for idx, rp in enumerate(self.recent, start=1):
4788 formatStr = '&{0:d}. {1}' if idx < 10 else '{0:d}. {1}' 5156 formatStr = "&{0:d}. {1}" if idx < 10 else "{0:d}. {1}"
4789 act = self.recentMenu.addAction( 5157 act = self.recentMenu.addAction(
4790 formatStr.format( 5158 formatStr.format(
4791 idx, 5159 idx, Utilities.compactPath(rp, self.ui.maxMenuFilePathLen)
4792 Utilities.compactPath(rp, self.ui.maxMenuFilePathLen))) 5160 )
5161 )
4793 act.setData(rp) 5162 act.setData(rp)
4794 act.setEnabled(pathlib.Path(rp).exists()) 5163 act.setEnabled(pathlib.Path(rp).exists())
4795 5164
4796 self.recentMenu.addSeparator() 5165 self.recentMenu.addSeparator()
4797 self.recentMenu.addAction(self.tr('&Clear'), self.clearRecent) 5166 self.recentMenu.addAction(self.tr("&Clear"), self.clearRecent)
4798 5167
4799 def __openRecent(self, act): 5168 def __openRecent(self, act):
4800 """ 5169 """
4801 Private method to open a project from the list of rencently opened 5170 Private method to open a project from the list of rencently opened
4802 projects. 5171 projects.
4803 5172
4804 @param act reference to the action that triggered (QAction) 5173 @param act reference to the action that triggered (QAction)
4805 """ 5174 """
4806 file = act.data() 5175 file = act.data()
4807 if file: 5176 if file:
4808 self.openProject(file) 5177 self.openProject(file)
4809 5178
4810 def clearRecent(self): 5179 def clearRecent(self):
4811 """ 5180 """
4812 Public method to clear the recent projects menu. 5181 Public method to clear the recent projects menu.
4813 """ 5182 """
4814 self.recent = [] 5183 self.recent = []
4815 self.__saveRecent() 5184 self.__saveRecent()
4816 5185
4817 def clearHistories(self): 5186 def clearHistories(self):
4818 """ 5187 """
4819 Public method to clear the project related histories. 5188 Public method to clear the project related histories.
4820 """ 5189 """
4821 self.clearRecent() 5190 self.clearRecent()
4822 5191
4823 for key in ["DebugClientsHistory", "DebuggerInterpreterHistory"]: 5192 for key in ["DebugClientsHistory", "DebuggerInterpreterHistory"]:
4824 Preferences.setProject(key, []) 5193 Preferences.setProject(key, [])
4825 Preferences.syncPreferences() 5194 Preferences.syncPreferences()
4826 5195
4827 def __searchNewFiles(self): 5196 def __searchNewFiles(self):
4828 """ 5197 """
4829 Private slot used to handle the search new files action. 5198 Private slot used to handle the search new files action.
4830 """ 5199 """
4831 self.__doSearchNewFiles(False, True) 5200 self.__doSearchNewFiles(False, True)
4832 5201
4833 def __searchProjectFile(self): 5202 def __searchProjectFile(self):
4834 """ 5203 """
4835 Private slot to show the Find Project File dialog. 5204 Private slot to show the Find Project File dialog.
4836 """ 5205 """
4837 if self.__findProjectFileDialog is None: 5206 if self.__findProjectFileDialog is None:
4838 from .QuickFindFileDialog import QuickFindFileDialog 5207 from .QuickFindFileDialog import QuickFindFileDialog
5208
4839 self.__findProjectFileDialog = QuickFindFileDialog(self) 5209 self.__findProjectFileDialog = QuickFindFileDialog(self)
4840 self.__findProjectFileDialog.sourceFile.connect( 5210 self.__findProjectFileDialog.sourceFile.connect(self.sourceFile)
4841 self.sourceFile) 5211 self.__findProjectFileDialog.designerFile.connect(self.designerFile)
4842 self.__findProjectFileDialog.designerFile.connect( 5212 self.__findProjectFileDialog.linguistFile.connect(self.linguistFile)
4843 self.designerFile)
4844 self.__findProjectFileDialog.linguistFile.connect(
4845 self.linguistFile)
4846 self.__findProjectFileDialog.show() 5213 self.__findProjectFileDialog.show()
4847 self.__findProjectFileDialog.raise_() 5214 self.__findProjectFileDialog.raise_()
4848 self.__findProjectFileDialog.activateWindow() 5215 self.__findProjectFileDialog.activateWindow()
4849 5216
4850 def __doSearchNewFiles(self, AI=True, onUserDemand=False): 5217 def __doSearchNewFiles(self, AI=True, onUserDemand=False):
4851 """ 5218 """
4852 Private method to search for new files in the project directory. 5219 Private method to search for new files in the project directory.
4853 5220
4854 If new files were found, it shows a dialog listing these files and 5221 If new files were found, it shows a dialog listing these files and
4855 gives the user the opportunity to select the ones he wants to 5222 gives the user the opportunity to select the ones he wants to
4856 include. If 'Automatic Inclusion' is enabled, the new files are 5223 include. If 'Automatic Inclusion' is enabled, the new files are
4857 automatically added to the project. 5224 automatically added to the project.
4858 5225
4859 @param AI flag indicating whether the automatic inclusion should 5226 @param AI flag indicating whether the automatic inclusion should
4860 be honoured (boolean) 5227 be honoured (boolean)
4861 @param onUserDemand flag indicating whether this method was 5228 @param onUserDemand flag indicating whether this method was
4862 requested by the user via a menu action (boolean) 5229 requested by the user via a menu action (boolean)
4863 """ 5230 """
4864 autoInclude = Preferences.getProject("AutoIncludeNewFiles") 5231 autoInclude = Preferences.getProject("AutoIncludeNewFiles")
4865 recursiveSearch = Preferences.getProject("SearchNewFilesRecursively") 5232 recursiveSearch = Preferences.getProject("SearchNewFilesRecursively")
4866 newFiles = [] 5233 newFiles = []
4867 5234
4868 ignore_patterns = [pattern for pattern, filetype in 5235 ignore_patterns = [
4869 self.pdata["FILETYPES"].items() 5236 pattern
4870 if filetype == '__IGNORE__'] 5237 for pattern, filetype in self.pdata["FILETYPES"].items()
4871 5238 if filetype == "__IGNORE__"
5239 ]
5240
4872 dirs = self.subdirs[:] 5241 dirs = self.subdirs[:]
4873 for directory in dirs: 5242 for directory in dirs:
4874 skip = False 5243 skip = False
4875 for ignore_pattern in ignore_patterns: 5244 for ignore_pattern in ignore_patterns:
4876 if fnmatch.fnmatch(directory, ignore_pattern): 5245 if fnmatch.fnmatch(directory, ignore_pattern):
4877 skip = True 5246 skip = True
4878 break 5247 break
4879 if skip: 5248 if skip:
4880 continue 5249 continue
4881 5250
4882 curpath = os.path.join(self.ppath, directory) 5251 curpath = os.path.join(self.ppath, directory)
4883 try: 5252 try:
4884 newSources = os.listdir(curpath) 5253 newSources = os.listdir(curpath)
4885 except OSError: 5254 except OSError:
4886 newSources = [] 5255 newSources = []
4887 pattern = ( 5256 pattern = (
4888 self.pdata["TRANSLATIONPATTERN"].replace("%language%", "*") 5257 self.pdata["TRANSLATIONPATTERN"].replace("%language%", "*")
4889 if self.pdata["TRANSLATIONPATTERN"] else 5258 if self.pdata["TRANSLATIONPATTERN"]
4890 "*.ts" 5259 else "*.ts"
4891 ) 5260 )
4892 binpattern = self.__binaryTranslationFile(pattern) 5261 binpattern = self.__binaryTranslationFile(pattern)
4893 for ns in newSources: 5262 for ns in newSources:
4894 # ignore hidden files and directories 5263 # ignore hidden files and directories
4895 if ns.startswith('.'): 5264 if ns.startswith("."):
4896 continue 5265 continue
4897 if ( 5266 if (
4898 Utilities.isWindowsPlatform() and 5267 Utilities.isWindowsPlatform()
4899 os.path.isdir(os.path.join(curpath, ns)) and 5268 and os.path.isdir(os.path.join(curpath, ns))
4900 ns.startswith('_') 5269 and ns.startswith("_")
4901 ): 5270 ):
4902 # dot net hack 5271 # dot net hack
4903 continue 5272 continue
4904 5273
4905 # set fn to project relative name 5274 # set fn to project relative name
4906 # then reset ns to fully qualified name for insertion, 5275 # then reset ns to fully qualified name for insertion,
4907 # possibly. 5276 # possibly.
4908 fn = os.path.join(directory, ns) if directory else ns 5277 fn = os.path.join(directory, ns) if directory else ns
4909 ns = os.path.abspath(os.path.join(curpath, ns)) 5278 ns = os.path.abspath(os.path.join(curpath, ns))
4910 5279
4911 # do not bother with dirs here... 5280 # do not bother with dirs here...
4912 if os.path.isdir(ns): 5281 if os.path.isdir(ns):
4913 if recursiveSearch: 5282 if recursiveSearch:
4914 d = self.getRelativePath(ns) 5283 d = self.getRelativePath(ns)
4915 if d not in dirs: 5284 if d not in dirs:
4916 dirs.append(d) 5285 dirs.append(d)
4917 continue 5286 continue
4918 5287
4919 filetype = "" 5288 filetype = ""
4920 bfn = os.path.basename(fn) 5289 bfn = os.path.basename(fn)
4921 for pattern in sorted(self.pdata["FILETYPES"].keys(), 5290 for pattern in sorted(self.pdata["FILETYPES"].keys(), reverse=True):
4922 reverse=True):
4923 if fnmatch.fnmatch(bfn, pattern): 5291 if fnmatch.fnmatch(bfn, pattern):
4924 filetype = self.pdata["FILETYPES"][pattern] 5292 filetype = self.pdata["FILETYPES"][pattern]
4925 break 5293 break
4926 5294
4927 if ( 5295 if (
4928 (filetype == "SOURCES" and 5296 (filetype == "SOURCES" and fn not in self.pdata["SOURCES"])
4929 fn not in self.pdata["SOURCES"]) or 5297 or (filetype == "FORMS" and fn not in self.pdata["FORMS"])
4930 (filetype == "FORMS" and 5298 or (filetype == "INTERFACES" and fn not in self.pdata["INTERFACES"])
4931 fn not in self.pdata["FORMS"]) or 5299 or (filetype == "PROTOCOLS" and fn not in self.pdata["PROTOCOLS"])
4932 (filetype == "INTERFACES" and 5300 or (filetype == "RESOURCES" and fn not in self.pdata["RESOURCES"])
4933 fn not in self.pdata["INTERFACES"]) or 5301 or (filetype == "OTHERS" and fn not in self.pdata["OTHERS"])
4934 (filetype == "PROTOCOLS" and 5302 or (
4935 fn not in self.pdata["PROTOCOLS"]) or 5303 filetype == "TRANSLATIONS"
4936 (filetype == "RESOURCES" and 5304 and fn not in self.pdata["TRANSLATIONS"]
4937 fn not in self.pdata["RESOURCES"]) or 5305 and (
4938 (filetype == "OTHERS" and 5306 fnmatch.fnmatch(ns, pattern)
4939 fn not in self.pdata["OTHERS"]) or 5307 or fnmatch.fnmatch(ns, binpattern)
4940 (filetype == "TRANSLATIONS" and 5308 )
4941 fn not in self.pdata["TRANSLATIONS"] and 5309 )
4942 (fnmatch.fnmatch(ns, pattern) or
4943 fnmatch.fnmatch(ns, binpattern)))
4944 ): 5310 ):
4945 if autoInclude and AI: 5311 if autoInclude and AI:
4946 self.appendFile(ns) 5312 self.appendFile(ns)
4947 else: 5313 else:
4948 newFiles.append(ns) 5314 newFiles.append(ns)
4949 5315
4950 # if autoInclude is set there is no more work left 5316 # if autoInclude is set there is no more work left
4951 if (autoInclude and AI): 5317 if autoInclude and AI:
4952 return 5318 return
4953 5319
4954 # if newfiles is empty, put up message box informing user nothing found 5320 # if newfiles is empty, put up message box informing user nothing found
4955 if not newFiles: 5321 if not newFiles:
4956 if onUserDemand: 5322 if onUserDemand:
4957 EricMessageBox.information( 5323 EricMessageBox.information(
4958 self.ui, 5324 self.ui,
4959 self.tr("Search New Files"), 5325 self.tr("Search New Files"),
4960 self.tr("There were no new files found to be added.")) 5326 self.tr("There were no new files found to be added."),
5327 )
4961 return 5328 return
4962 5329
4963 # autoInclude is not set, show a dialog 5330 # autoInclude is not set, show a dialog
4964 from .AddFoundFilesDialog import AddFoundFilesDialog 5331 from .AddFoundFilesDialog import AddFoundFilesDialog
5332
4965 dlg = AddFoundFilesDialog(newFiles, self.parent(), None) 5333 dlg = AddFoundFilesDialog(newFiles, self.parent(), None)
4966 res = dlg.exec() 5334 res = dlg.exec()
4967 5335
4968 # the 'Add All' button was pressed 5336 # the 'Add All' button was pressed
4969 if res == 1: 5337 if res == 1:
4970 for file in newFiles: 5338 for file in newFiles:
4971 self.appendFile(file) 5339 self.appendFile(file)
4972 5340
4973 # the 'Add Selected' button was pressed 5341 # the 'Add Selected' button was pressed
4974 elif res == 2: 5342 elif res == 2:
4975 files = dlg.getSelection() 5343 files = dlg.getSelection()
4976 for file in files: 5344 for file in files:
4977 self.appendFile(file) 5345 self.appendFile(file)
4978 5346
4979 def othersAdded(self, fn, updateModel=True): 5347 def othersAdded(self, fn, updateModel=True):
4980 """ 5348 """
4981 Public slot to be called, if something was added to the OTHERS project 5349 Public slot to be called, if something was added to the OTHERS project
4982 data area. 5350 data area.
4983 5351
4984 @param fn filename or directory name added (string) 5352 @param fn filename or directory name added (string)
4985 @param updateModel flag indicating an update of the model is requested 5353 @param updateModel flag indicating an update of the model is requested
4986 (boolean) 5354 (boolean)
4987 """ 5355 """
4988 self.projectOthersAdded.emit(fn) 5356 self.projectOthersAdded.emit(fn)
4989 updateModel and self.__model.addNewItem("OTHERS", fn) 5357 updateModel and self.__model.addNewItem("OTHERS", fn)
4990 5358
4991 def getActions(self): 5359 def getActions(self):
4992 """ 5360 """
4993 Public method to get a list of all actions. 5361 Public method to get a list of all actions.
4994 5362
4995 @return list of all actions (list of EricAction) 5363 @return list of all actions (list of EricAction)
4996 """ 5364 """
4997 return self.actions[:] 5365 return self.actions[:]
4998 5366
4999 def addEricActions(self, actions): 5367 def addEricActions(self, actions):
5000 """ 5368 """
5001 Public method to add actions to the list of actions. 5369 Public method to add actions to the list of actions.
5002 5370
5003 @param actions list of actions (list of EricAction) 5371 @param actions list of actions (list of EricAction)
5004 """ 5372 """
5005 self.actions.extend(actions) 5373 self.actions.extend(actions)
5006 5374
5007 def removeEricActions(self, actions): 5375 def removeEricActions(self, actions):
5008 """ 5376 """
5009 Public method to remove actions from the list of actions. 5377 Public method to remove actions from the list of actions.
5010 5378
5011 @param actions list of actions (list of EricAction) 5379 @param actions list of actions (list of EricAction)
5012 """ 5380 """
5013 for act in actions: 5381 for act in actions:
5014 with contextlib.suppress(ValueError): 5382 with contextlib.suppress(ValueError):
5015 self.actions.remove(act) 5383 self.actions.remove(act)
5016 5384
5017 def getMenu(self, menuName): 5385 def getMenu(self, menuName):
5018 """ 5386 """
5019 Public method to get a reference to the main menu or a submenu. 5387 Public method to get a reference to the main menu or a submenu.
5020 5388
5021 @param menuName name of the menu (string) 5389 @param menuName name of the menu (string)
5022 @return reference to the requested menu (QMenu) or None 5390 @return reference to the requested menu (QMenu) or None
5023 """ 5391 """
5024 try: 5392 try:
5025 return self.__menus[menuName] 5393 return self.__menus[menuName]
5026 except KeyError: 5394 except KeyError:
5027 return None 5395 return None
5028 5396
5029 def repopulateItem(self, fullname): 5397 def repopulateItem(self, fullname):
5030 """ 5398 """
5031 Public slot to repopulate a named item. 5399 Public slot to repopulate a named item.
5032 5400
5033 @param fullname full name of the item to repopulate (string) 5401 @param fullname full name of the item to repopulate (string)
5034 """ 5402 """
5035 if not self.isOpen(): 5403 if not self.isOpen():
5036 return 5404 return
5037 5405
5038 with EricOverrideCursor(): 5406 with EricOverrideCursor():
5039 name = self.getRelativePath(fullname) 5407 name = self.getRelativePath(fullname)
5040 self.prepareRepopulateItem.emit(name) 5408 self.prepareRepopulateItem.emit(name)
5041 self.__model.repopulateItem(name) 5409 self.__model.repopulateItem(name)
5042 self.completeRepopulateItem.emit(name) 5410 self.completeRepopulateItem.emit(name)
5043 5411
5044 ############################################################## 5412 ##############################################################
5045 ## Below is the VCS interface 5413 ## Below is the VCS interface
5046 ############################################################## 5414 ##############################################################
5047 5415
5048 def initVCS(self, vcsSystem=None, nooverride=False): 5416 def initVCS(self, vcsSystem=None, nooverride=False):
5049 """ 5417 """
5050 Public method used to instantiate a vcs system. 5418 Public method used to instantiate a vcs system.
5051 5419
5052 @param vcsSystem type of VCS to be used (string) 5420 @param vcsSystem type of VCS to be used (string)
5053 @param nooverride flag indicating to ignore an override request 5421 @param nooverride flag indicating to ignore an override request
5054 (boolean) 5422 (boolean)
5055 @return a reference to the vcs object 5423 @return a reference to the vcs object
5056 """ 5424 """
5057 vcs = None 5425 vcs = None
5058 forProject = True 5426 forProject = True
5059 override = False 5427 override = False
5060 5428
5061 if vcsSystem is None: 5429 if vcsSystem is None:
5062 if self.pdata["VCS"] and self.pdata["VCS"] != 'None': 5430 if self.pdata["VCS"] and self.pdata["VCS"] != "None":
5063 vcsSystem = self.pdata["VCS"] 5431 vcsSystem = self.pdata["VCS"]
5064 else: 5432 else:
5065 forProject = False 5433 forProject = False
5066 5434
5067 if ( 5435 if (
5068 forProject and 5436 forProject
5069 self.pdata["VCS"] and 5437 and self.pdata["VCS"]
5070 self.pdata["VCS"] != 'None' and 5438 and self.pdata["VCS"] != "None"
5071 self.pudata["VCSOVERRIDE"] and 5439 and self.pudata["VCSOVERRIDE"]
5072 not nooverride 5440 and not nooverride
5073 ): 5441 ):
5074 vcsSystem = self.pudata["VCSOVERRIDE"] 5442 vcsSystem = self.pudata["VCSOVERRIDE"]
5075 override = True 5443 override = True
5076 5444
5077 if vcsSystem is not None: 5445 if vcsSystem is not None:
5078 import VCS 5446 import VCS
5447
5079 try: 5448 try:
5080 vcs = VCS.factory(vcsSystem) 5449 vcs = VCS.factory(vcsSystem)
5081 except ImportError: 5450 except ImportError:
5082 if override: 5451 if override:
5083 # override failed, revert to original 5452 # override failed, revert to original
5084 self.pudata["VCSOVERRIDE"] = "" 5453 self.pudata["VCSOVERRIDE"] = ""
5085 return self.initVCS(nooverride=True) 5454 return self.initVCS(nooverride=True)
5086 5455
5087 if vcs: 5456 if vcs:
5088 vcsExists, msg = vcs.vcsExists() 5457 vcsExists, msg = vcs.vcsExists()
5089 if not vcsExists: 5458 if not vcsExists:
5090 if override: 5459 if override:
5091 # override failed, revert to original 5460 # override failed, revert to original
5094 self.ui, 5463 self.ui,
5095 self.tr("Version Control System"), 5464 self.tr("Version Control System"),
5096 self.tr( 5465 self.tr(
5097 "<p>The selected VCS <b>{0}</b> could not be" 5466 "<p>The selected VCS <b>{0}</b> could not be"
5098 " found. <br/>Reverting override.</p><p>{1}" 5467 " found. <br/>Reverting override.</p><p>{1}"
5099 "</p>") 5468 "</p>"
5100 .format(vcsSystem, msg)) 5469 ).format(vcsSystem, msg),
5470 )
5101 self.pudata["VCSOVERRIDE"] = "" 5471 self.pudata["VCSOVERRIDE"] = ""
5102 return self.initVCS(nooverride=True) 5472 return self.initVCS(nooverride=True)
5103 5473
5104 with EricOverridenCursor(): 5474 with EricOverridenCursor():
5105 EricMessageBox.critical( 5475 EricMessageBox.critical(
5106 self.ui, 5476 self.ui,
5107 self.tr("Version Control System"), 5477 self.tr("Version Control System"),
5108 self.tr( 5478 self.tr(
5109 "<p>The selected VCS <b>{0}</b> could not be" 5479 "<p>The selected VCS <b>{0}</b> could not be"
5110 " found.<br/>Disabling version control.</p>" 5480 " found.<br/>Disabling version control.</p>"
5111 "<p>{1}</p>").format(vcsSystem, msg)) 5481 "<p>{1}</p>"
5482 ).format(vcsSystem, msg),
5483 )
5112 vcs = None 5484 vcs = None
5113 if forProject: 5485 if forProject:
5114 self.pdata["VCS"] = 'None' 5486 self.pdata["VCS"] = "None"
5115 self.setDirty(True) 5487 self.setDirty(True)
5116 else: 5488 else:
5117 vcs.vcsInitConfig(self) 5489 vcs.vcsInitConfig(self)
5118 5490
5119 if vcs and forProject: 5491 if vcs and forProject:
5120 # set the vcs options 5492 # set the vcs options
5121 if vcs.vcsSupportCommandOptions(): 5493 if vcs.vcsSupportCommandOptions():
5122 with contextlib.suppress(LookupError): 5494 with contextlib.suppress(LookupError):
5123 vcsopt = copy.deepcopy(self.pdata["VCSOPTIONS"]) 5495 vcsopt = copy.deepcopy(self.pdata["VCSOPTIONS"])
5124 vcs.vcsSetOptions(vcsopt) 5496 vcs.vcsSetOptions(vcsopt)
5125 # set vcs specific data 5497 # set vcs specific data
5126 with contextlib.suppress(LookupError): 5498 with contextlib.suppress(LookupError):
5127 vcsother = copy.deepcopy(self.pdata["VCSOTHERDATA"]) 5499 vcsother = copy.deepcopy(self.pdata["VCSOTHERDATA"])
5128 vcs.vcsSetOtherData(vcsother) 5500 vcs.vcsSetOtherData(vcsother)
5129 5501
5130 if forProject: 5502 if forProject:
5131 if vcs is None: 5503 if vcs is None:
5132 import VCS 5504 import VCS
5505
5133 self.vcsProjectHelper = VCS.getBasicHelper(self) 5506 self.vcsProjectHelper = VCS.getBasicHelper(self)
5134 self.vcsBasicHelper = True 5507 self.vcsBasicHelper = True
5135 else: 5508 else:
5136 self.vcsProjectHelper = vcs.vcsGetProjectHelper(self) 5509 self.vcsProjectHelper = vcs.vcsGetProjectHelper(self)
5137 self.vcsBasicHelper = False 5510 self.vcsBasicHelper = False
5138 if self.vcsMenu is not None: 5511 if self.vcsMenu is not None:
5139 self.vcsProjectHelper.initMenu(self.vcsMenu) 5512 self.vcsProjectHelper.initMenu(self.vcsMenu)
5140 self.vcsMenu.setEnabled(self.vcsSoftwareAvailable()) 5513 self.vcsMenu.setEnabled(self.vcsSoftwareAvailable())
5141 5514
5142 return vcs 5515 return vcs
5143 5516
5144 def resetVCS(self): 5517 def resetVCS(self):
5145 """ 5518 """
5146 Public method to reset the VCS. 5519 Public method to reset the VCS.
5147 """ 5520 """
5148 self.pdata["VCS"] = 'None' 5521 self.pdata["VCS"] = "None"
5149 self.vcs = self.initVCS() 5522 self.vcs = self.initVCS()
5150 ericApp().getObject("PluginManager").deactivateVcsPlugins() 5523 ericApp().getObject("PluginManager").deactivateVcsPlugins()
5151 5524
5152 def __showContextMenuVCS(self): 5525 def __showContextMenuVCS(self):
5153 """ 5526 """
5154 Private slot called before the vcs menu is shown. 5527 Private slot called before the vcs menu is shown.
5155 """ 5528 """
5156 self.vcsProjectHelper.showMenu() 5529 self.vcsProjectHelper.showMenu()
5157 if self.vcsBasicHelper: 5530 if self.vcsBasicHelper:
5158 self.showMenu.emit("VCS", self.vcsMenu) 5531 self.showMenu.emit("VCS", self.vcsMenu)
5159 5532
5160 def vcsSoftwareAvailable(self): 5533 def vcsSoftwareAvailable(self):
5161 """ 5534 """
5162 Public method to check, if some supported VCS software is available 5535 Public method to check, if some supported VCS software is available
5163 to the IDE. 5536 to the IDE.
5164 5537
5165 @return flag indicating availability of VCS software (boolean) 5538 @return flag indicating availability of VCS software (boolean)
5166 """ 5539 """
5167 vcsSystemsDict = ( 5540 vcsSystemsDict = (
5168 ericApp().getObject("PluginManager") 5541 ericApp()
5542 .getObject("PluginManager")
5169 .getPluginDisplayStrings("version_control") 5543 .getPluginDisplayStrings("version_control")
5170 ) 5544 )
5171 return len(vcsSystemsDict) != 0 5545 return len(vcsSystemsDict) != 0
5172 5546
5173 def __vcsStatusChanged(self): 5547 def __vcsStatusChanged(self):
5174 """ 5548 """
5175 Private slot to handle a change of the overall VCS status. 5549 Private slot to handle a change of the overall VCS status.
5176 """ 5550 """
5177 self.projectChanged.emit() 5551 self.projectChanged.emit()
5178 5552
5179 def __vcsConnectStatusMonitor(self): 5553 def __vcsConnectStatusMonitor(self):
5180 """ 5554 """
5181 Private method to start the VCS monitor and connect its signals. 5555 Private method to start the VCS monitor and connect its signals.
5182 """ 5556 """
5183 if self.vcs is not None: 5557 if self.vcs is not None:
5184 self.vcs.committed.connect(self.vcsCommitted) 5558 self.vcs.committed.connect(self.vcsCommitted)
5185 5559
5186 self.vcs.startStatusMonitor(self) 5560 self.vcs.startStatusMonitor(self)
5187 self.vcs.vcsStatusMonitorData.connect( 5561 self.vcs.vcsStatusMonitorData.connect(self.__model.changeVCSStates)
5188 self.__model.changeVCSStates) 5562 self.vcs.vcsStatusMonitorData.connect(self.vcsStatusMonitorData)
5189 self.vcs.vcsStatusMonitorData.connect( 5563 self.vcs.vcsStatusMonitorAllData.connect(self.vcsStatusMonitorAllData)
5190 self.vcsStatusMonitorData) 5564 self.vcs.vcsStatusMonitorStatus.connect(self.vcsStatusMonitorStatus)
5191 self.vcs.vcsStatusMonitorAllData.connect( 5565 self.vcs.vcsStatusMonitorInfo.connect(self.vcsStatusMonitorInfo)
5192 self.vcsStatusMonitorAllData) 5566 self.vcs.vcsStatusChanged.connect(self.__vcsStatusChanged)
5193 self.vcs.vcsStatusMonitorStatus.connect( 5567
5194 self.vcsStatusMonitorStatus)
5195 self.vcs.vcsStatusMonitorInfo.connect(
5196 self.vcsStatusMonitorInfo)
5197 self.vcs.vcsStatusChanged.connect(
5198 self.__vcsStatusChanged)
5199
5200 ######################################################################### 5568 #########################################################################
5201 ## Below is the interface to the checker tools 5569 ## Below is the interface to the checker tools
5202 ######################################################################### 5570 #########################################################################
5203 5571
5204 def __showContextMenuChecks(self): 5572 def __showContextMenuChecks(self):
5205 """ 5573 """
5206 Private slot called before the checks menu is shown. 5574 Private slot called before the checks menu is shown.
5207 """ 5575 """
5208 self.showMenu.emit("Checks", self.checksMenu) 5576 self.showMenu.emit("Checks", self.checksMenu)
5209 5577
5210 ######################################################################### 5578 #########################################################################
5211 ## Below is the interface to the packagers tools 5579 ## Below is the interface to the packagers tools
5212 ######################################################################### 5580 #########################################################################
5213 5581
5214 def __showContextMenuPackagers(self): 5582 def __showContextMenuPackagers(self):
5215 """ 5583 """
5216 Private slot called before the packagers menu is shown. 5584 Private slot called before the packagers menu is shown.
5217 """ 5585 """
5218 self.showMenu.emit("Packagers", self.packagersMenu) 5586 self.showMenu.emit("Packagers", self.packagersMenu)
5219 5587
5220 ######################################################################### 5588 #########################################################################
5221 ## Below is the interface to the apidoc tools 5589 ## Below is the interface to the apidoc tools
5222 ######################################################################### 5590 #########################################################################
5223 5591
5224 def __showContextMenuApiDoc(self): 5592 def __showContextMenuApiDoc(self):
5225 """ 5593 """
5226 Private slot called before the apidoc menu is shown. 5594 Private slot called before the apidoc menu is shown.
5227 """ 5595 """
5228 self.showMenu.emit("Apidoc", self.apidocMenu) 5596 self.showMenu.emit("Apidoc", self.apidocMenu)
5229 5597
5230 ######################################################################### 5598 #########################################################################
5231 ## Below is the interface to the show tools 5599 ## Below is the interface to the show tools
5232 ######################################################################### 5600 #########################################################################
5233 5601
5234 def __showCodeMetrics(self): 5602 def __showCodeMetrics(self):
5235 """ 5603 """
5236 Private slot used to calculate some code metrics for the project files. 5604 Private slot used to calculate some code metrics for the project files.
5237 """ 5605 """
5238 files = [os.path.join(self.ppath, file) 5606 files = [
5239 for file in self.pdata["SOURCES"] if file.endswith(".py")] 5607 os.path.join(self.ppath, file)
5608 for file in self.pdata["SOURCES"]
5609 if file.endswith(".py")
5610 ]
5240 from DataViews.CodeMetricsDialog import CodeMetricsDialog 5611 from DataViews.CodeMetricsDialog import CodeMetricsDialog
5612
5241 self.codemetrics = CodeMetricsDialog() 5613 self.codemetrics = CodeMetricsDialog()
5242 self.codemetrics.show() 5614 self.codemetrics.show()
5243 self.codemetrics.prepare(files) 5615 self.codemetrics.prepare(files)
5244 5616
5245 def __showCodeCoverage(self): 5617 def __showCodeCoverage(self):
5252 EricMessageBox.critical( 5624 EricMessageBox.critical(
5253 self.ui, 5625 self.ui,
5254 self.tr("Coverage Data"), 5626 self.tr("Coverage Data"),
5255 self.tr( 5627 self.tr(
5256 "There is no main script defined for the" 5628 "There is no main script defined for the"
5257 " current project. Aborting")) 5629 " current project. Aborting"
5630 ),
5631 )
5258 return 5632 return
5259 5633
5260 files = Utilities.getCoverageFileNames(fn) 5634 files = Utilities.getCoverageFileNames(fn)
5261 if files: 5635 if files:
5262 if len(files) > 1: 5636 if len(files) > 1:
5263 fn, ok = QInputDialog.getItem( 5637 fn, ok = QInputDialog.getItem(
5264 None, 5638 None,
5265 self.tr("Code Coverage"), 5639 self.tr("Code Coverage"),
5266 self.tr("Please select a coverage file"), 5640 self.tr("Please select a coverage file"),
5267 files, 5641 files,
5268 0, False) 5642 0,
5643 False,
5644 )
5269 if not ok: 5645 if not ok:
5270 return 5646 return
5271 else: 5647 else:
5272 fn = files[0] 5648 fn = files[0]
5273 else: 5649 else:
5274 return 5650 return
5275 5651
5276 files = [os.path.join(self.ppath, file) 5652 files = [
5277 for file in self.pdata["SOURCES"] 5653 os.path.join(self.ppath, file)
5278 if os.path.splitext(file)[1].startswith(".py")] 5654 for file in self.pdata["SOURCES"]
5655 if os.path.splitext(file)[1].startswith(".py")
5656 ]
5279 from DataViews.PyCoverageDialog import PyCoverageDialog 5657 from DataViews.PyCoverageDialog import PyCoverageDialog
5658
5280 self.codecoverage = PyCoverageDialog() 5659 self.codecoverage = PyCoverageDialog()
5281 self.codecoverage.show() 5660 self.codecoverage.show()
5282 self.codecoverage.start(fn, files) 5661 self.codecoverage.start(fn, files)
5283 5662
5284 def __showProfileData(self): 5663 def __showProfileData(self):
5290 EricMessageBox.critical( 5669 EricMessageBox.critical(
5291 self.ui, 5670 self.ui,
5292 self.tr("Profile Data"), 5671 self.tr("Profile Data"),
5293 self.tr( 5672 self.tr(
5294 "There is no main script defined for the" 5673 "There is no main script defined for the"
5295 " current project. Aborting")) 5674 " current project. Aborting"
5675 ),
5676 )
5296 return 5677 return
5297 5678
5298 files = Utilities.getProfileFileNames(fn) 5679 files = Utilities.getProfileFileNames(fn)
5299 if files: 5680 if files:
5300 if len(files) > 1: 5681 if len(files) > 1:
5301 fn, ok = QInputDialog.getItem( 5682 fn, ok = QInputDialog.getItem(
5302 None, 5683 None,
5303 self.tr("Profile Data"), 5684 self.tr("Profile Data"),
5304 self.tr("Please select a profile file"), 5685 self.tr("Please select a profile file"),
5305 files, 5686 files,
5306 0, False) 5687 0,
5688 False,
5689 )
5307 if not ok: 5690 if not ok:
5308 return 5691 return
5309 else: 5692 else:
5310 fn = files[0] 5693 fn = files[0]
5311 else: 5694 else:
5312 return 5695 return
5313 5696
5314 from DataViews.PyProfileDialog import PyProfileDialog 5697 from DataViews.PyProfileDialog import PyProfileDialog
5698
5315 self.profiledata = PyProfileDialog() 5699 self.profiledata = PyProfileDialog()
5316 self.profiledata.show() 5700 self.profiledata.show()
5317 self.profiledata.start(fn) 5701 self.profiledata.start(fn)
5318 5702
5319 def __showContextMenuShow(self): 5703 def __showContextMenuShow(self):
5320 """ 5704 """
5321 Private slot called before the show menu is shown. 5705 Private slot called before the show menu is shown.
5322 """ 5706 """
5323 fn = self.getMainScript(True) 5707 fn = self.getMainScript(True)
5324 if not fn: 5708 if not fn:
5325 fn = self.getProjectPath() 5709 fn = self.getProjectPath()
5326 5710
5327 self.codeProfileAct.setEnabled( 5711 self.codeProfileAct.setEnabled(
5328 self.isPy3Project() and 5712 self.isPy3Project() and bool(Utilities.getProfileFileName(fn))
5329 bool(Utilities.getProfileFileName(fn))
5330 ) 5713 )
5331 self.codeCoverageAct.setEnabled( 5714 self.codeCoverageAct.setEnabled(
5332 self.isPy3Project() and 5715 self.isPy3Project() and bool(Utilities.getCoverageFileNames(fn))
5333 bool(Utilities.getCoverageFileNames(fn)) 5716 )
5334 ) 5717
5335
5336 self.showMenu.emit("Show", self.menuShow) 5718 self.showMenu.emit("Show", self.menuShow)
5337 5719
5338 ######################################################################### 5720 #########################################################################
5339 ## Below is the interface to the diagrams 5721 ## Below is the interface to the diagrams
5340 ######################################################################### 5722 #########################################################################
5341 5723
5342 def __showContextMenuGraphics(self): 5724 def __showContextMenuGraphics(self):
5343 """ 5725 """
5344 Private slot called before the graphics menu is shown. 5726 Private slot called before the graphics menu is shown.
5345 """ 5727 """
5346 self.showMenu.emit("Graphics", self.graphicsMenu) 5728 self.showMenu.emit("Graphics", self.graphicsMenu)
5347 5729
5348 def handleApplicationDiagram(self): 5730 def handleApplicationDiagram(self):
5349 """ 5731 """
5350 Public method to handle the application diagram context menu action. 5732 Public method to handle the application diagram context menu action.
5351 """ 5733 """
5352 res = EricMessageBox.yesNo( 5734 res = EricMessageBox.yesNo(
5353 self.ui, 5735 self.ui,
5354 self.tr("Application Diagram"), 5736 self.tr("Application Diagram"),
5355 self.tr("""Include module names?"""), 5737 self.tr("""Include module names?"""),
5356 yesDefault=True) 5738 yesDefault=True,
5357 5739 )
5740
5358 from Graphics.UMLDialog import UMLDialog, UMLDialogType 5741 from Graphics.UMLDialog import UMLDialog, UMLDialogType
5742
5359 self.applicationDiagram = UMLDialog( 5743 self.applicationDiagram = UMLDialog(
5360 UMLDialogType.APPLICATION_DIAGRAM, self, self.parent(), 5744 UMLDialogType.APPLICATION_DIAGRAM, self, self.parent(), noModules=not res
5361 noModules=not res) 5745 )
5362 self.applicationDiagram.show() 5746 self.applicationDiagram.show()
5363 5747
5364 def __loadDiagram(self): 5748 def __loadDiagram(self):
5365 """ 5749 """
5366 Private slot to load a diagram from file. 5750 Private slot to load a diagram from file.
5367 """ 5751 """
5368 from Graphics.UMLDialog import UMLDialog, UMLDialogType 5752 from Graphics.UMLDialog import UMLDialog, UMLDialogType
5753
5369 self.loadedDiagram = None 5754 self.loadedDiagram = None
5370 loadedDiagram = UMLDialog(UMLDialogType.NO_DIAGRAM, 5755 loadedDiagram = UMLDialog(UMLDialogType.NO_DIAGRAM, self, parent=self.parent())
5371 self, parent=self.parent())
5372 if loadedDiagram.load(): 5756 if loadedDiagram.load():
5373 self.loadedDiagram = loadedDiagram 5757 self.loadedDiagram = loadedDiagram
5374 self.loadedDiagram.show(fromFile=True) 5758 self.loadedDiagram.show(fromFile=True)
5375 5759
5376 ######################################################################### 5760 #########################################################################
5377 ## Below is the interface to the VCS monitor thread 5761 ## Below is the interface to the VCS monitor thread
5378 ######################################################################### 5762 #########################################################################
5379 5763
5380 def setStatusMonitorInterval(self, interval): 5764 def setStatusMonitorInterval(self, interval):
5381 """ 5765 """
5382 Public method to se the interval of the VCS status monitor thread. 5766 Public method to se the interval of the VCS status monitor thread.
5383 5767
5384 @param interval status monitor interval in seconds (integer) 5768 @param interval status monitor interval in seconds (integer)
5385 """ 5769 """
5386 if self.vcs is not None: 5770 if self.vcs is not None:
5387 self.vcs.setStatusMonitorInterval(interval, self) 5771 self.vcs.setStatusMonitorInterval(interval, self)
5388 5772
5389 def getStatusMonitorInterval(self): 5773 def getStatusMonitorInterval(self):
5390 """ 5774 """
5391 Public method to get the monitor interval. 5775 Public method to get the monitor interval.
5392 5776
5393 @return interval in seconds (integer) 5777 @return interval in seconds (integer)
5394 """ 5778 """
5395 if self.vcs is not None: 5779 if self.vcs is not None:
5396 return self.vcs.getStatusMonitorInterval() 5780 return self.vcs.getStatusMonitorInterval()
5397 else: 5781 else:
5398 return 0 5782 return 0
5399 5783
5400 def setStatusMonitorAutoUpdate(self, auto): 5784 def setStatusMonitorAutoUpdate(self, auto):
5401 """ 5785 """
5402 Public method to enable the auto update function. 5786 Public method to enable the auto update function.
5403 5787
5404 @param auto status of the auto update function (boolean) 5788 @param auto status of the auto update function (boolean)
5405 """ 5789 """
5406 if self.vcs is not None: 5790 if self.vcs is not None:
5407 self.vcs.setStatusMonitorAutoUpdate(auto) 5791 self.vcs.setStatusMonitorAutoUpdate(auto)
5408 5792
5409 def getStatusMonitorAutoUpdate(self): 5793 def getStatusMonitorAutoUpdate(self):
5410 """ 5794 """
5411 Public method to retrieve the status of the auto update function. 5795 Public method to retrieve the status of the auto update function.
5412 5796
5413 @return status of the auto update function (boolean) 5797 @return status of the auto update function (boolean)
5414 """ 5798 """
5415 if self.vcs is not None: 5799 if self.vcs is not None:
5416 return self.vcs.getStatusMonitorAutoUpdate() 5800 return self.vcs.getStatusMonitorAutoUpdate()
5417 else: 5801 else:
5418 return False 5802 return False
5419 5803
5420 def checkVCSStatus(self): 5804 def checkVCSStatus(self):
5421 """ 5805 """
5422 Public method to wake up the VCS status monitor thread. 5806 Public method to wake up the VCS status monitor thread.
5423 """ 5807 """
5424 if self.vcs is not None: 5808 if self.vcs is not None:
5425 self.vcs.checkVCSStatus() 5809 self.vcs.checkVCSStatus()
5426 5810
5427 def clearStatusMonitorCachedState(self, name): 5811 def clearStatusMonitorCachedState(self, name):
5428 """ 5812 """
5429 Public method to clear the cached VCS state of a file/directory. 5813 Public method to clear the cached VCS state of a file/directory.
5430 5814
5431 @param name name of the entry to be cleared (string) 5815 @param name name of the entry to be cleared (string)
5432 """ 5816 """
5433 if self.vcs is not None: 5817 if self.vcs is not None:
5434 self.vcs.clearStatusMonitorCachedState(name) 5818 self.vcs.clearStatusMonitorCachedState(name)
5435 5819
5436 def startStatusMonitor(self): 5820 def startStatusMonitor(self):
5437 """ 5821 """
5438 Public method to start the VCS status monitor thread. 5822 Public method to start the VCS status monitor thread.
5439 """ 5823 """
5440 if self.vcs is not None: 5824 if self.vcs is not None:
5441 self.vcs.startStatusMonitor(self) 5825 self.vcs.startStatusMonitor(self)
5442 5826
5443 def stopStatusMonitor(self): 5827 def stopStatusMonitor(self):
5444 """ 5828 """
5445 Public method to stop the VCS status monitor thread. 5829 Public method to stop the VCS status monitor thread.
5446 """ 5830 """
5447 if self.vcs is not None: 5831 if self.vcs is not None:
5448 self.vcs.stopStatusMonitor() 5832 self.vcs.stopStatusMonitor()
5449 5833
5450 ######################################################################### 5834 #########################################################################
5451 ## Below are the plugin development related methods 5835 ## Below are the plugin development related methods
5452 ######################################################################### 5836 #########################################################################
5453 5837
5454 def __pluginVersionToTuple(self, versionStr): 5838 def __pluginVersionToTuple(self, versionStr):
5455 """ 5839 """
5456 Private method to convert a plug-in version string into a version 5840 Private method to convert a plug-in version string into a version
5457 tuple. 5841 tuple.
5458 5842
5459 @param versionStr version string to be converted 5843 @param versionStr version string to be converted
5460 @type str 5844 @type str
5461 @return version info as a tuple 5845 @return version info as a tuple
5462 @rtype tuple of int and str 5846 @rtype tuple of int and str
5463 """ 5847 """
5469 for part in versionStr.split("."): 5853 for part in versionStr.split("."):
5470 try: 5854 try:
5471 vParts.append(int(part)) 5855 vParts.append(int(part))
5472 except ValueError: 5856 except ValueError:
5473 vParts.append(part) 5857 vParts.append(part)
5474 5858
5475 if additional: 5859 if additional:
5476 vParts.append(additional) 5860 vParts.append(additional)
5477 5861
5478 return tuple(vParts) 5862 return tuple(vParts)
5479 5863
5480 def __pluginCreatePkgList(self): 5864 def __pluginCreatePkgList(self):
5481 """ 5865 """
5482 Private slot to create a PKGLIST file needed for archive file creation. 5866 Private slot to create a PKGLIST file needed for archive file creation.
5483 """ 5867 """
5484 pkglist = os.path.join(self.ppath, "PKGLIST") 5868 pkglist = os.path.join(self.ppath, "PKGLIST")
5486 res = EricMessageBox.yesNo( 5870 res = EricMessageBox.yesNo(
5487 self.ui, 5871 self.ui,
5488 self.tr("Create Package List"), 5872 self.tr("Create Package List"),
5489 self.tr( 5873 self.tr(
5490 "<p>The file <b>PKGLIST</b> already" 5874 "<p>The file <b>PKGLIST</b> already"
5491 " exists.</p><p>Overwrite it?</p>"), 5875 " exists.</p><p>Overwrite it?</p>"
5492 icon=EricMessageBox.Warning) 5876 ),
5877 icon=EricMessageBox.Warning,
5878 )
5493 if not res: 5879 if not res:
5494 return # don't overwrite 5880 return # don't overwrite
5495 5881
5496 # build the list of entries 5882 # build the list of entries
5497 lst_ = [] 5883 lst_ = []
5498 for key in ["SOURCES", "FORMS", "RESOURCES", "TRANSLATIONS", 5884 for key in [
5499 "INTERFACES", "PROTOCOLS", "OTHERS"]: 5885 "SOURCES",
5886 "FORMS",
5887 "RESOURCES",
5888 "TRANSLATIONS",
5889 "INTERFACES",
5890 "PROTOCOLS",
5891 "OTHERS",
5892 ]:
5500 lst_.extend(self.pdata[key]) 5893 lst_.extend(self.pdata[key])
5501 lst = [] 5894 lst = []
5502 for entry in lst_: 5895 for entry in lst_:
5503 if os.path.isdir(self.getAbsolutePath(entry)): 5896 if os.path.isdir(self.getAbsolutePath(entry)):
5504 lst.extend( 5897 lst.extend(
5505 [self.getRelativePath(p) for p in 5898 [
5506 Utilities.direntries(self.getAbsolutePath(entry), True)]) 5899 self.getRelativePath(p)
5900 for p in Utilities.direntries(self.getAbsolutePath(entry), True)
5901 ]
5902 )
5507 continue 5903 continue
5508 else: 5904 else:
5509 lst.append(entry) 5905 lst.append(entry)
5510 lst.sort() 5906 lst.sort()
5511 if "PKGLIST" in lst: 5907 if "PKGLIST" in lst:
5512 lst.remove("PKGLIST") 5908 lst.remove("PKGLIST")
5513 5909
5514 # build the header to indicate a freshly generated list 5910 # build the header to indicate a freshly generated list
5515 header = [ 5911 header = [
5516 ";", 5912 ";",
5517 "; initial_list (REMOVE THIS LINE WHEN DONE)", 5913 "; initial_list (REMOVE THIS LINE WHEN DONE)",
5518 ";", 5914 ";",
5519 " ", 5915 " ",
5520 ] 5916 ]
5521 5917
5522 # write the file 5918 # write the file
5523 try: 5919 try:
5524 newline = None if self.pdata["EOL"] == 0 else self.getEolString() 5920 newline = None if self.pdata["EOL"] == 0 else self.getEolString()
5525 with open(pkglist, "w", encoding="utf-8", 5921 with open(pkglist, "w", encoding="utf-8", newline=newline) as pkglistFile:
5526 newline=newline) as pkglistFile:
5527 pkglistFile.write("\n".join(header) + "\n") 5922 pkglistFile.write("\n".join(header) + "\n")
5528 pkglistFile.write( 5923 pkglistFile.write(
5529 "\n".join([Utilities.fromNativeSeparators(f) 5924 "\n".join([Utilities.fromNativeSeparators(f) for f in lst])
5530 for f in lst])) 5925 )
5531 pkglistFile.write("\n") 5926 pkglistFile.write("\n")
5532 # ensure the file ends with an empty line 5927 # ensure the file ends with an empty line
5533 except OSError as why: 5928 except OSError as why:
5534 EricMessageBox.critical( 5929 EricMessageBox.critical(
5535 self.ui, 5930 self.ui,
5536 self.tr("Create Package List"), 5931 self.tr("Create Package List"),
5537 self.tr( 5932 self.tr(
5538 """<p>The file <b>PKGLIST</b> could not be created.</p>""" 5933 """<p>The file <b>PKGLIST</b> could not be created.</p>"""
5539 """<p>Reason: {0}</p>""").format(str(why))) 5934 """<p>Reason: {0}</p>"""
5935 ).format(str(why)),
5936 )
5540 return 5937 return
5541 5938
5542 if "PKGLIST" not in self.pdata["OTHERS"]: 5939 if "PKGLIST" not in self.pdata["OTHERS"]:
5543 self.appendFile("PKGLIST") 5940 self.appendFile("PKGLIST")
5544 5941
5545 @pyqtSlot() 5942 @pyqtSlot()
5546 def __pluginCreateArchives(self, snapshot=False): 5943 def __pluginCreateArchives(self, snapshot=False):
5547 """ 5944 """
5548 Private slot to create eric plugin archives. 5945 Private slot to create eric plugin archives.
5549 5946
5550 @param snapshot flag indicating snapshot archives (boolean) 5947 @param snapshot flag indicating snapshot archives (boolean)
5551 """ 5948 """
5552 if not self.pdata["MAINSCRIPT"]: 5949 if not self.pdata["MAINSCRIPT"]:
5553 EricMessageBox.critical( 5950 EricMessageBox.critical(
5554 self.ui, 5951 self.ui,
5555 self.tr("Create Plugin Archive"), 5952 self.tr("Create Plugin Archive"),
5556 self.tr( 5953 self.tr(
5557 """The project does not have a main script defined. """ 5954 """The project does not have a main script defined. """
5558 """Aborting...""")) 5955 """Aborting..."""
5956 ),
5957 )
5559 return 5958 return
5560 5959
5561 selectedLists = [] 5960 selectedLists = []
5562 pkglists = [os.path.basename(f) for f in 5961 pkglists = [
5563 glob.glob(os.path.join(self.ppath, "PKGLIST*"))] 5962 os.path.basename(f) for f in glob.glob(os.path.join(self.ppath, "PKGLIST*"))
5963 ]
5564 if len(pkglists) == 1: 5964 if len(pkglists) == 1:
5565 selectedLists = [os.path.join(self.ppath, pkglists[0])] 5965 selectedLists = [os.path.join(self.ppath, pkglists[0])]
5566 elif len(pkglists) > 1: 5966 elif len(pkglists) > 1:
5567 dlg = EricListSelectionDialog( 5967 dlg = EricListSelectionDialog(
5568 sorted(pkglists), title=self.tr("Create Plugin Archive"), 5968 sorted(pkglists),
5969 title=self.tr("Create Plugin Archive"),
5569 message=self.tr("Select package lists:"), 5970 message=self.tr("Select package lists:"),
5570 checkBoxSelection=True) 5971 checkBoxSelection=True,
5972 )
5571 if dlg.exec() == QDialog.DialogCode.Accepted: 5973 if dlg.exec() == QDialog.DialogCode.Accepted:
5572 selectedLists = [os.path.join(self.ppath, s) 5974 selectedLists = [
5573 for s in dlg.getSelection()] 5975 os.path.join(self.ppath, s) for s in dlg.getSelection()
5976 ]
5574 else: 5977 else:
5575 return 5978 return
5576 5979
5577 if not selectedLists: 5980 if not selectedLists:
5578 EricMessageBox.critical( 5981 EricMessageBox.critical(
5579 self.ui, 5982 self.ui,
5580 self.tr("Create Plugin Archive"), 5983 self.tr("Create Plugin Archive"),
5581 self.tr("""<p>No package list files (PKGLIST*) available or""" 5984 self.tr(
5582 """ selected. Aborting...</p>""")) 5985 """<p>No package list files (PKGLIST*) available or"""
5986 """ selected. Aborting...</p>"""
5987 ),
5988 )
5583 return 5989 return
5584 5990
5585 progress = EricProgressDialog( 5991 progress = EricProgressDialog(
5586 self.tr("Creating plugin archives..."), self.tr("Abort"), 5992 self.tr("Creating plugin archives..."),
5587 0, len(selectedLists), self.tr("%v/%m Archives"), self.ui) 5993 self.tr("Abort"),
5994 0,
5995 len(selectedLists),
5996 self.tr("%v/%m Archives"),
5997 self.ui,
5998 )
5588 progress.setMinimumDuration(0) 5999 progress.setMinimumDuration(0)
5589 progress.setWindowTitle(self.tr("Create Plugin Archives")) 6000 progress.setWindowTitle(self.tr("Create Plugin Archives"))
5590 errors = 0 6001 errors = 0
5591 for count, pkglist in enumerate(selectedLists): 6002 for count, pkglist in enumerate(selectedLists):
5592 progress.setValue(count) 6003 progress.setValue(count)
5593 if progress.wasCanceled(): 6004 if progress.wasCanceled():
5594 break 6005 break
5595 6006
5596 try: 6007 try:
5597 with open(pkglist, "r", encoding="utf-8") as pkglistFile: 6008 with open(pkglist, "r", encoding="utf-8") as pkglistFile:
5598 names = pkglistFile.read() 6009 names = pkglistFile.read()
5599 except OSError as why: 6010 except OSError as why:
5600 EricMessageBox.critical( 6011 EricMessageBox.critical(
5601 self.ui, 6012 self.ui,
5602 self.tr("Create Plugin Archive"), 6013 self.tr("Create Plugin Archive"),
5603 self.tr( 6014 self.tr(
5604 """<p>The file <b>{0}</b> could not be read.</p>""" 6015 """<p>The file <b>{0}</b> could not be read.</p>"""
5605 """<p>Reason: {1}</p>""").format( 6016 """<p>Reason: {1}</p>"""
5606 os.path.basename(pkglist), str(why))) 6017 ).format(os.path.basename(pkglist), str(why)),
6018 )
5607 errors += 1 6019 errors += 1
5608 continue 6020 continue
5609 6021
5610 lines = names.splitlines() 6022 lines = names.splitlines()
5611 archiveName = "" 6023 archiveName = ""
5612 archiveVersion = "" 6024 archiveVersion = ""
5613 names = [] 6025 names = []
5614 listOK = True 6026 listOK = True
5629 self.tr("Create Plugin Archive"), 6041 self.tr("Create Plugin Archive"),
5630 self.tr( 6042 self.tr(
5631 """<p>The file <b>{0}</b> is not ready yet.""" 6043 """<p>The file <b>{0}</b> is not ready yet."""
5632 """</p><p>Please rework it and delete the""" 6044 """</p><p>Please rework it and delete the"""
5633 """'; initial_list' line of the header.""" 6045 """'; initial_list' line of the header."""
5634 """</p>""").format(os.path.basename(pkglist))) 6046 """</p>"""
6047 ).format(os.path.basename(pkglist)),
6048 )
5635 errors += 1 6049 errors += 1
5636 listOK = False 6050 listOK = False
5637 break 6051 break
5638 elif line.strip(): 6052 elif line.strip():
5639 names.append(line.strip()) 6053 names.append(line.strip())
5640 6054
5641 if not listOK: 6055 if not listOK:
5642 continue 6056 continue
5643 6057
5644 names = sorted(names) 6058 names = sorted(names)
5645 archive = ( 6059 archive = (
5646 os.path.join(self.ppath, archiveName) 6060 os.path.join(self.ppath, archiveName)
5647 if archiveName else 6061 if archiveName
5648 os.path.join(self.ppath, 6062 else os.path.join(
5649 self.pdata["MAINSCRIPT"].replace(".py", ".zip")) 6063 self.ppath, self.pdata["MAINSCRIPT"].replace(".py", ".zip")
6064 )
5650 ) 6065 )
5651 try: 6066 try:
5652 archiveFile = zipfile.ZipFile(archive, "w") 6067 archiveFile = zipfile.ZipFile(archive, "w")
5653 except OSError as why: 6068 except OSError as why:
5654 EricMessageBox.critical( 6069 EricMessageBox.critical(
5655 self.ui, 6070 self.ui,
5656 self.tr("Create Plugin Archive"), 6071 self.tr("Create Plugin Archive"),
5657 self.tr( 6072 self.tr(
5658 """<p>The eric plugin archive file <b>{0}</b>""" 6073 """<p>The eric plugin archive file <b>{0}</b>"""
5659 """ could not be created.</p>""" 6074 """ could not be created.</p>"""
5660 """<p>Reason: {1}</p>""").format(archive, str(why))) 6075 """<p>Reason: {1}</p>"""
6076 ).format(archive, str(why)),
6077 )
5661 errors += 1 6078 errors += 1
5662 continue 6079 continue
5663 6080
5664 for name in names: 6081 for name in names:
5665 if name: 6082 if name:
5666 try: 6083 try:
5667 self.__createZipDirEntries( 6084 self.__createZipDirEntries(os.path.split(name)[0], archiveFile)
5668 os.path.split(name)[0], archiveFile)
5669 if snapshot and name == self.pdata["MAINSCRIPT"]: 6085 if snapshot and name == self.pdata["MAINSCRIPT"]:
5670 snapshotSource, version = ( 6086 snapshotSource, version = self.__createSnapshotSource(
5671 self.__createSnapshotSource( 6087 os.path.join(self.ppath, self.pdata["MAINSCRIPT"])
5672 os.path.join(self.ppath,
5673 self.pdata["MAINSCRIPT"]))
5674 ) 6088 )
5675 archiveFile.writestr(name, snapshotSource) 6089 archiveFile.writestr(name, snapshotSource)
5676 else: 6090 else:
5677 archiveFile.write(os.path.join(self.ppath, name), 6091 archiveFile.write(os.path.join(self.ppath, name), name)
5678 name)
5679 if name == self.pdata["MAINSCRIPT"]: 6092 if name == self.pdata["MAINSCRIPT"]:
5680 version = self.__pluginExtractVersion( 6093 version = self.__pluginExtractVersion(
5681 os.path.join(self.ppath, 6094 os.path.join(self.ppath, self.pdata["MAINSCRIPT"])
5682 self.pdata["MAINSCRIPT"])) 6095 )
5683 if archiveVersion and ( 6096 if archiveVersion and (
5684 self.__pluginVersionToTuple(version) < 6097 self.__pluginVersionToTuple(version)
5685 self.__pluginVersionToTuple(archiveVersion) 6098 < self.__pluginVersionToTuple(archiveVersion)
5686 ): 6099 ):
5687 version = archiveVersion 6100 version = archiveVersion
5688 except OSError as why: 6101 except OSError as why:
5689 EricMessageBox.critical( 6102 EricMessageBox.critical(
5690 self.ui, 6103 self.ui,
5691 self.tr("Create Plugin Archive"), 6104 self.tr("Create Plugin Archive"),
5692 self.tr( 6105 self.tr(
5693 """<p>The file <b>{0}</b> could not be""" 6106 """<p>The file <b>{0}</b> could not be"""
5694 """ stored in the archive. Ignoring it.</p>""" 6107 """ stored in the archive. Ignoring it.</p>"""
5695 """<p>Reason: {1}</p>""") 6108 """<p>Reason: {1}</p>"""
5696 .format(os.path.join(self.ppath, name), str(why))) 6109 ).format(os.path.join(self.ppath, name), str(why)),
6110 )
5697 archiveFile.writestr("VERSION", version.encode("utf-8")) 6111 archiveFile.writestr("VERSION", version.encode("utf-8"))
5698 archiveFile.close() 6112 archiveFile.close()
5699 6113
5700 if archive not in self.pdata["OTHERS"]: 6114 if archive not in self.pdata["OTHERS"]:
5701 self.appendFile(archive) 6115 self.appendFile(archive)
5702 6116
5703 progress.setValue(len(selectedLists)) 6117 progress.setValue(len(selectedLists))
5704 6118
5705 if errors: 6119 if errors:
5706 self.ui.showNotification( 6120 self.ui.showNotification(
5707 UI.PixmapCache.getPixmap("pluginArchive48"), 6121 UI.PixmapCache.getPixmap("pluginArchive48"),
5708 self.tr("Create Plugin Archive"), 6122 self.tr("Create Plugin Archive"),
5709 self.tr("<p>The eric plugin archive files were " 6123 self.tr(
5710 "created with some errors.</p>"), 6124 "<p>The eric plugin archive files were "
6125 "created with some errors.</p>"
6126 ),
5711 kind=NotificationTypes.CRITICAL, 6127 kind=NotificationTypes.CRITICAL,
5712 timeout=0) 6128 timeout=0,
6129 )
5713 else: 6130 else:
5714 self.ui.showNotification( 6131 self.ui.showNotification(
5715 UI.PixmapCache.getPixmap("pluginArchive48"), 6132 UI.PixmapCache.getPixmap("pluginArchive48"),
5716 self.tr("Create Plugin Archive"), 6133 self.tr("Create Plugin Archive"),
5717 self.tr("<p>The eric plugin archive files were " 6134 self.tr(
5718 "created successfully.</p>")) 6135 "<p>The eric plugin archive files were " "created successfully.</p>"
5719 6136 ),
6137 )
6138
5720 def __pluginCreateSnapshotArchives(self): 6139 def __pluginCreateSnapshotArchives(self):
5721 """ 6140 """
5722 Private slot to create eric plugin archive snapshot releases. 6141 Private slot to create eric plugin archive snapshot releases.
5723 """ 6142 """
5724 self.__pluginCreateArchives(True) 6143 self.__pluginCreateArchives(True)
5725 6144
5726 def __createZipDirEntries(self, path, zipFile): 6145 def __createZipDirEntries(self, path, zipFile):
5727 """ 6146 """
5728 Private method to create dir entries in the zip file. 6147 Private method to create dir entries in the zip file.
5729 6148
5730 @param path name of the directory entry to create (string) 6149 @param path name of the directory entry to create (string)
5731 @param zipFile open ZipFile object (zipfile.ZipFile) 6150 @param zipFile open ZipFile object (zipfile.ZipFile)
5732 """ 6151 """
5733 if path in ("", "/", "\\"): 6152 if path in ("", "/", "\\"):
5734 return 6153 return
5735 6154
5736 if not path.endswith("/") and not path.endswith("\\"): 6155 if not path.endswith("/") and not path.endswith("\\"):
5737 path = "{0}/".format(path) 6156 path = "{0}/".format(path)
5738 6157
5739 if path not in zipFile.namelist(): 6158 if path not in zipFile.namelist():
5740 self.__createZipDirEntries(os.path.split(path[:-1])[0], zipFile) 6159 self.__createZipDirEntries(os.path.split(path[:-1])[0], zipFile)
5741 zipFile.writestr(path, b"") 6160 zipFile.writestr(path, b"")
5742 6161
5743 def __createSnapshotSource(self, filename): 6162 def __createSnapshotSource(self, filename):
5744 """ 6163 """
5745 Private method to create a snapshot plugin version. 6164 Private method to create a snapshot plugin version.
5746 6165
5747 The version entry in the plugin module is modified to signify 6166 The version entry in the plugin module is modified to signify
5748 a snapshot version. This method appends the string "-snapshot-" 6167 a snapshot version. This method appends the string "-snapshot-"
5749 and date indicator to the version string. 6168 and date indicator to the version string.
5750 6169
5751 @param filename name of the plugin file to modify (string) 6170 @param filename name of the plugin file to modify (string)
5752 @return modified source (bytes), snapshot version string (string) 6171 @return modified source (bytes), snapshot version string (string)
5753 """ 6172 """
5754 try: 6173 try:
5755 sourcelines, encoding = Utilities.readEncodedFile(filename) 6174 sourcelines, encoding = Utilities.readEncodedFile(filename)
5756 sourcelines = sourcelines.splitlines(True) 6175 sourcelines = sourcelines.splitlines(True)
5757 except (OSError, UnicodeError) as why: 6176 except (OSError, UnicodeError) as why:
5758 EricMessageBox.critical( 6177 EricMessageBox.critical(
5759 self.ui, 6178 self.ui,
5760 self.tr("Create Plugin Archive"), 6179 self.tr("Create Plugin Archive"),
5761 self.tr("""<p>The plugin file <b>{0}</b> could """ 6180 self.tr(
5762 """not be read.</p>""" 6181 """<p>The plugin file <b>{0}</b> could """
5763 """<p>Reason: {1}</p>""") 6182 """not be read.</p>"""
5764 .format(filename, str(why))) 6183 """<p>Reason: {1}</p>"""
6184 ).format(filename, str(why)),
6185 )
5765 return b"", "" 6186 return b"", ""
5766 6187
5767 lineno = 0 6188 lineno = 0
5768 while lineno < len(sourcelines): 6189 while lineno < len(sourcelines):
5769 if sourcelines[lineno].startswith("version = "): 6190 if sourcelines[lineno].startswith("version = "):
5770 # found the line to modify 6191 # found the line to modify
5771 datestr = time.strftime("%Y%m%d") 6192 datestr = time.strftime("%Y%m%d")
5772 lineend = sourcelines[lineno].replace( 6193 lineend = sourcelines[lineno].replace(sourcelines[lineno].rstrip(), "")
5773 sourcelines[lineno].rstrip(), "")
5774 sversion = "{0}-snapshot-{1}".format( 6194 sversion = "{0}-snapshot-{1}".format(
5775 sourcelines[lineno].replace("version = ", "") 6195 sourcelines[lineno].replace("version = ", "").strip()[1:-1], datestr
5776 .strip()[1:-1], 6196 )
5777 datestr)
5778 sourcelines[lineno] = '{0} + "-snapshot-{1}"{2}'.format( 6197 sourcelines[lineno] = '{0} + "-snapshot-{1}"{2}'.format(
5779 sourcelines[lineno].rstrip(), datestr, lineend) 6198 sourcelines[lineno].rstrip(), datestr, lineend
6199 )
5780 break 6200 break
5781 6201
5782 lineno += 1 6202 lineno += 1
5783 6203
5784 source = Utilities.encode("".join(sourcelines), encoding)[0] 6204 source = Utilities.encode("".join(sourcelines), encoding)[0]
5785 return source, sversion 6205 return source, sversion
5786 6206
5787 def __pluginExtractVersion(self, filename): 6207 def __pluginExtractVersion(self, filename):
5788 """ 6208 """
5789 Private method to extract the version number entry. 6209 Private method to extract the version number entry.
5790 6210
5791 @param filename name of the plugin file (string) 6211 @param filename name of the plugin file (string)
5792 @return version string (string) 6212 @return version string (string)
5793 """ 6213 """
5794 version = "0.0.0" 6214 version = "0.0.0"
5795 try: 6215 try:
5799 EricMessageBox.critical( 6219 EricMessageBox.critical(
5800 self.ui, 6220 self.ui,
5801 self.tr("Create Plugin Archive"), 6221 self.tr("Create Plugin Archive"),
5802 self.tr( 6222 self.tr(
5803 """<p>The plugin file <b>{0}</b> could """ 6223 """<p>The plugin file <b>{0}</b> could """
5804 """not be read.</p> <p>Reason: {1}</p>""") 6224 """not be read.</p> <p>Reason: {1}</p>"""
5805 .format(filename, str(why))) 6225 ).format(filename, str(why)),
6226 )
5806 return "" 6227 return ""
5807 6228
5808 for sourceline in sourcelines: 6229 for sourceline in sourcelines:
5809 if sourceline.startswith("version = "): 6230 if sourceline.startswith("version = "):
5810 version = ( 6231 version = (
5811 sourceline.replace("version = ", "").strip() 6232 sourceline.replace("version = ", "")
5812 .replace('"', "").replace("'", "") 6233 .strip()
6234 .replace('"', "")
6235 .replace("'", "")
5813 ) 6236 )
5814 break 6237 break
5815 6238
5816 return version 6239 return version
5817 6240
5818 ######################################################################### 6241 #########################################################################
5819 ## Below are methods implementing the 'make' support 6242 ## Below are methods implementing the 'make' support
5820 ######################################################################### 6243 #########################################################################
5821 6244
5822 def __showContextMenuMake(self): 6245 def __showContextMenuMake(self):
5823 """ 6246 """
5824 Private slot called before the make menu is shown. 6247 Private slot called before the make menu is shown.
5825 """ 6248 """
5826 self.showMenu.emit("Make", self.makeMenu) 6249 self.showMenu.emit("Make", self.makeMenu)
5827 6250
5828 def hasDefaultMakeParameters(self): 6251 def hasDefaultMakeParameters(self):
5829 """ 6252 """
5830 Public method to test, if the project contains the default make 6253 Public method to test, if the project contains the default make
5831 parameters. 6254 parameters.
5832 6255
5833 @return flag indicating default parameter set 6256 @return flag indicating default parameter set
5834 @rtype bool 6257 @rtype bool
5835 """ 6258 """
5836 return self.pdata["MAKEPARAMS"] == { 6259 return self.pdata["MAKEPARAMS"] == {
5837 "MakeEnabled": False, 6260 "MakeEnabled": False,
5839 "MakeFile": "", 6262 "MakeFile": "",
5840 "MakeTarget": "", 6263 "MakeTarget": "",
5841 "MakeParameters": "", 6264 "MakeParameters": "",
5842 "MakeTestOnly": True, 6265 "MakeTestOnly": True,
5843 } 6266 }
5844 6267
5845 def isMakeEnabled(self): 6268 def isMakeEnabled(self):
5846 """ 6269 """
5847 Public method to test, if make is enabled for the project. 6270 Public method to test, if make is enabled for the project.
5848 6271
5849 @return flag indicating enabled make support 6272 @return flag indicating enabled make support
5850 @rtype bool 6273 @rtype bool
5851 """ 6274 """
5852 return self.pdata["MAKEPARAMS"]["MakeEnabled"] 6275 return self.pdata["MAKEPARAMS"]["MakeEnabled"]
5853 6276
5854 @pyqtSlot() 6277 @pyqtSlot()
5855 def executeMake(self): 6278 def executeMake(self):
5856 """ 6279 """
5857 Public slot to execute a project specific make run (auto-run) 6280 Public slot to execute a project specific make run (auto-run)
5858 (execute or question). 6281 (execute or question).
5859 """ 6282 """
5860 self.__executeMake( 6283 self.__executeMake(
5861 questionOnly=self.pdata["MAKEPARAMS"]["MakeTestOnly"], 6284 questionOnly=self.pdata["MAKEPARAMS"]["MakeTestOnly"], interactive=False
5862 interactive=False) 6285 )
5863 6286
5864 @pyqtSlot() 6287 @pyqtSlot()
5865 def __executeMake(self, questionOnly=False, interactive=True): 6288 def __executeMake(self, questionOnly=False, interactive=True):
5866 """ 6289 """
5867 Private method to execute a project specific make run. 6290 Private method to execute a project specific make run.
5868 6291
5869 @param questionOnly flag indicating to ask make for changes only 6292 @param questionOnly flag indicating to ask make for changes only
5870 @type bool 6293 @type bool
5871 @param interactive flag indicating an interactive invocation (i.e. 6294 @param interactive flag indicating an interactive invocation (i.e.
5872 through a menu action) 6295 through a menu action)
5873 @type bool 6296 @type bool
5874 """ 6297 """
5875 if ( 6298 if (
5876 not self.pdata["MAKEPARAMS"]["MakeEnabled"] or 6299 not self.pdata["MAKEPARAMS"]["MakeEnabled"]
5877 self.__makeProcess is not None 6300 or self.__makeProcess is not None
5878 ): 6301 ):
5879 return 6302 return
5880 6303
5881 prog = ( 6304 prog = (
5882 self.pdata["MAKEPARAMS"]["MakeExecutable"] 6305 self.pdata["MAKEPARAMS"]["MakeExecutable"]
5883 if self.pdata["MAKEPARAMS"]["MakeExecutable"] else 6306 if self.pdata["MAKEPARAMS"]["MakeExecutable"]
5884 Project.DefaultMake 6307 else Project.DefaultMake
5885 ) 6308 )
5886 6309
5887 args = [] 6310 args = []
5888 if self.pdata["MAKEPARAMS"]["MakeParameters"]: 6311 if self.pdata["MAKEPARAMS"]["MakeParameters"]:
5889 args.extend(Utilities.parseOptionString( 6312 args.extend(
5890 self.pdata["MAKEPARAMS"]["MakeParameters"])) 6313 Utilities.parseOptionString(self.pdata["MAKEPARAMS"]["MakeParameters"])
5891 6314 )
6315
5892 if self.pdata["MAKEPARAMS"]["MakeFile"]: 6316 if self.pdata["MAKEPARAMS"]["MakeFile"]:
5893 args.append("--makefile={0}".format( 6317 args.append("--makefile={0}".format(self.pdata["MAKEPARAMS"]["MakeFile"]))
5894 self.pdata["MAKEPARAMS"]["MakeFile"])) 6318
5895
5896 if questionOnly: 6319 if questionOnly:
5897 args.append("--question") 6320 args.append("--question")
5898 6321
5899 if self.pdata["MAKEPARAMS"]["MakeTarget"]: 6322 if self.pdata["MAKEPARAMS"]["MakeTarget"]:
5900 args.append(self.pdata["MAKEPARAMS"]["MakeTarget"]) 6323 args.append(self.pdata["MAKEPARAMS"]["MakeTarget"])
5901 6324
5902 self.__makeProcess = QProcess(self) 6325 self.__makeProcess = QProcess(self)
5903 self.__makeProcess.readyReadStandardOutput.connect( 6326 self.__makeProcess.readyReadStandardOutput.connect(self.__makeReadStdOut)
5904 self.__makeReadStdOut) 6327 self.__makeProcess.readyReadStandardError.connect(self.__makeReadStdErr)
5905 self.__makeProcess.readyReadStandardError.connect(
5906 self.__makeReadStdErr)
5907 self.__makeProcess.finished.connect( 6328 self.__makeProcess.finished.connect(
5908 lambda exitCode, exitStatus: self.__makeFinished( 6329 lambda exitCode, exitStatus: self.__makeFinished(
5909 exitCode, exitStatus, questionOnly, interactive)) 6330 exitCode, exitStatus, questionOnly, interactive
6331 )
6332 )
5910 self.__makeProcess.setWorkingDirectory(self.getProjectPath()) 6333 self.__makeProcess.setWorkingDirectory(self.getProjectPath())
5911 self.__makeProcess.start(prog, args) 6334 self.__makeProcess.start(prog, args)
5912 6335
5913 if not self.__makeProcess.waitForStarted(): 6336 if not self.__makeProcess.waitForStarted():
5914 EricMessageBox.critical( 6337 EricMessageBox.critical(
5915 self.ui, 6338 self.ui,
5916 self.tr("Execute Make"), 6339 self.tr("Execute Make"),
5917 self.tr("""The make process did not start.""")) 6340 self.tr("""The make process did not start."""),
5918 6341 )
6342
5919 self.__cleanupMake() 6343 self.__cleanupMake()
5920 6344
5921 @pyqtSlot() 6345 @pyqtSlot()
5922 def __makeReadStdOut(self): 6346 def __makeReadStdOut(self):
5923 """ 6347 """
5924 Private slot to process process output received via stdout. 6348 Private slot to process process output received via stdout.
5925 """ 6349 """
5926 if self.__makeProcess is not None: 6350 if self.__makeProcess is not None:
5927 output = str(self.__makeProcess.readAllStandardOutput(), 6351 output = str(
5928 Preferences.getSystem("IOEncoding"), 6352 self.__makeProcess.readAllStandardOutput(),
5929 'replace') 6353 Preferences.getSystem("IOEncoding"),
6354 "replace",
6355 )
5930 self.appendStdout.emit(output) 6356 self.appendStdout.emit(output)
5931 6357
5932 @pyqtSlot() 6358 @pyqtSlot()
5933 def __makeReadStdErr(self): 6359 def __makeReadStdErr(self):
5934 """ 6360 """
5935 Private slot to process process output received via stderr. 6361 Private slot to process process output received via stderr.
5936 """ 6362 """
5937 if self.__makeProcess is not None: 6363 if self.__makeProcess is not None:
5938 error = str(self.__makeProcess.readAllStandardError(), 6364 error = str(
5939 Preferences.getSystem("IOEncoding"), 6365 self.__makeProcess.readAllStandardError(),
5940 'replace') 6366 Preferences.getSystem("IOEncoding"),
6367 "replace",
6368 )
5941 self.appendStderr.emit(error) 6369 self.appendStderr.emit(error)
5942 6370
5943 def __makeFinished(self, exitCode, exitStatus, questionOnly, 6371 def __makeFinished(self, exitCode, exitStatus, questionOnly, interactive=True):
5944 interactive=True):
5945 """ 6372 """
5946 Private slot handling the make process finished signal. 6373 Private slot handling the make process finished signal.
5947 6374
5948 @param exitCode exit code of the make process 6375 @param exitCode exit code of the make process
5949 @type int 6376 @type int
5950 @param exitStatus exit status of the make process 6377 @param exitStatus exit status of the make process
5951 @type QProcess.ExitStatus 6378 @type QProcess.ExitStatus
5952 @param questionOnly flag indicating a test only run 6379 @param questionOnly flag indicating a test only run
5957 """ 6384 """
5958 if exitStatus == QProcess.ExitStatus.CrashExit: 6385 if exitStatus == QProcess.ExitStatus.CrashExit:
5959 EricMessageBox.critical( 6386 EricMessageBox.critical(
5960 self.ui, 6387 self.ui,
5961 self.tr("Execute Make"), 6388 self.tr("Execute Make"),
5962 self.tr("""The make process crashed.""")) 6389 self.tr("""The make process crashed."""),
6390 )
5963 else: 6391 else:
5964 if questionOnly and exitCode == 1: 6392 if questionOnly and exitCode == 1:
5965 # a rebuild is needed 6393 # a rebuild is needed
5966 title = self.tr("Test for Changes") 6394 title = self.tr("Test for Changes")
5967 6395
5968 if self.pdata["MAKEPARAMS"]["MakeTarget"]: 6396 if self.pdata["MAKEPARAMS"]["MakeTarget"]:
5969 message = self.tr( 6397 message = self.tr(
5970 """<p>There are changes that require the configured""" 6398 """<p>There are changes that require the configured"""
5971 """ make target <b>{0}</b> to be rebuilt.</p>""" 6399 """ make target <b>{0}</b> to be rebuilt.</p>"""
5972 ).format(self.pdata["MAKEPARAMS"]["MakeTarget"]) 6400 ).format(self.pdata["MAKEPARAMS"]["MakeTarget"])
5973 else: 6401 else:
5974 message = self.tr( 6402 message = self.tr(
5975 """<p>There are changes that require the default""" 6403 """<p>There are changes that require the default"""
5976 """ make target to be rebuilt.</p>""") 6404 """ make target to be rebuilt.</p>"""
5977 6405 )
6406
5978 self.ui.showNotification( 6407 self.ui.showNotification(
5979 UI.PixmapCache.getPixmap("makefile48"), 6408 UI.PixmapCache.getPixmap("makefile48"),
5980 title, 6409 title,
5981 message, 6410 message,
5982 kind=NotificationTypes.WARNING, 6411 kind=NotificationTypes.WARNING,
5983 timeout=0) 6412 timeout=0,
6413 )
5984 elif exitCode > 1: 6414 elif exitCode > 1:
5985 EricMessageBox.critical( 6415 EricMessageBox.critical(
5986 self.ui, 6416 self.ui,
5987 self.tr("Execute Make"), 6417 self.tr("Execute Make"),
5988 self.tr("""The makefile contains errors.""")) 6418 self.tr("""The makefile contains errors."""),
5989 6419 )
6420
5990 self.__cleanupMake() 6421 self.__cleanupMake()
5991 6422
5992 def __cleanupMake(self): 6423 def __cleanupMake(self):
5993 """ 6424 """
5994 Private method to clean up make related stuff. 6425 Private method to clean up make related stuff.
5995 """ 6426 """
5996 self.__makeProcess.readyReadStandardOutput.disconnect() 6427 self.__makeProcess.readyReadStandardOutput.disconnect()
5997 self.__makeProcess.readyReadStandardError.disconnect() 6428 self.__makeProcess.readyReadStandardError.disconnect()
5998 self.__makeProcess.finished.disconnect() 6429 self.__makeProcess.finished.disconnect()
5999 self.__makeProcess.deleteLater() 6430 self.__makeProcess.deleteLater()
6000 self.__makeProcess = None 6431 self.__makeProcess = None
6001 6432
6002 ######################################################################### 6433 #########################################################################
6003 ## Below are methods implementing some 'IDL' support functions 6434 ## Below are methods implementing some 'IDL' support functions
6004 ######################################################################### 6435 #########################################################################
6005 6436
6006 def hasDefaultIdlCompilerParameters(self): 6437 def hasDefaultIdlCompilerParameters(self):
6007 """ 6438 """
6008 Public method to test, if the project contains the default IDL compiler 6439 Public method to test, if the project contains the default IDL compiler
6009 parameters. 6440 parameters.
6010 6441
6011 @return flag indicating default parameter set 6442 @return flag indicating default parameter set
6012 @rtype bool 6443 @rtype bool
6013 """ 6444 """
6014 return self.pdata["IDLPARAMS"] == { 6445 return self.pdata["IDLPARAMS"] == {
6015 "IncludeDirs": [], 6446 "IncludeDirs": [],
6016 "DefinedNames": [], 6447 "DefinedNames": [],
6017 "UndefinedNames": [], 6448 "UndefinedNames": [],
6018 } 6449 }
6019 6450
6020 ######################################################################### 6451 #########################################################################
6021 ## Below are methods implementing some 'UIC' support functions 6452 ## Below are methods implementing some 'UIC' support functions
6022 ######################################################################### 6453 #########################################################################
6023 6454
6024 def hasDefaultUicCompilerParameters(self): 6455 def hasDefaultUicCompilerParameters(self):
6025 """ 6456 """
6026 Public method to test, if the project contains the default uic compiler 6457 Public method to test, if the project contains the default uic compiler
6027 parameters. 6458 parameters.
6028 6459
6029 @return flag indicating default parameter set 6460 @return flag indicating default parameter set
6030 @rtype bool 6461 @rtype bool
6031 """ 6462 """
6032 return self.pdata["UICPARAMS"] == { 6463 return self.pdata["UICPARAMS"] == {
6033 "Package": "", 6464 "Package": "",
6034 "RcSuffix": "", 6465 "RcSuffix": "",
6035 "PackagesRoot": "", 6466 "PackagesRoot": "",
6036 } 6467 }
6037 6468
6038 def getUicParameter(self, name): 6469 def getUicParameter(self, name):
6039 """ 6470 """
6040 Public method to get a named uic related parameter. 6471 Public method to get a named uic related parameter.
6041 6472
6042 @param name name of the parameter 6473 @param name name of the parameter
6043 @type str 6474 @type str
6044 @return value of the given parameter 6475 @return value of the given parameter
6045 @rtype any, None in case on non-existence 6476 @rtype any, None in case on non-existence
6046 """ 6477 """
6047 if name in self.pdata["UICPARAMS"]: 6478 if name in self.pdata["UICPARAMS"]:
6048 return self.pdata["UICPARAMS"][name] 6479 return self.pdata["UICPARAMS"][name]
6049 else: 6480 else:
6050 return None 6481 return None
6051 6482
6052 ######################################################################### 6483 #########################################################################
6053 ## Below are methods implementing some 'RCC' support functions 6484 ## Below are methods implementing some 'RCC' support functions
6054 ######################################################################### 6485 #########################################################################
6055 6486
6056 def hasDefaultRccCompilerParameters(self): 6487 def hasDefaultRccCompilerParameters(self):
6057 """ 6488 """
6058 Public method to test, if the project contains the default rcc compiler 6489 Public method to test, if the project contains the default rcc compiler
6059 parameters. 6490 parameters.
6060 6491
6061 @return flag indicating default parameter set 6492 @return flag indicating default parameter set
6062 @rtype bool 6493 @rtype bool
6063 """ 6494 """
6064 return ( 6495 return self.pdata["RCCPARAMS"] == self.getDefaultRccCompilerParameters()
6065 self.pdata["RCCPARAMS"] == self.getDefaultRccCompilerParameters() 6496
6066 )
6067
6068 def getDefaultRccCompilerParameters(self): 6497 def getDefaultRccCompilerParameters(self):
6069 """ 6498 """
6070 Public method to get the default rcc compiler parameters. 6499 Public method to get the default rcc compiler parameters.
6071 6500
6072 @return dictionary containing the default rcc compiler parameters 6501 @return dictionary containing the default rcc compiler parameters
6073 @rtype dict 6502 @rtype dict
6074 """ 6503 """
6075 return { 6504 return {
6076 "CompressionThreshold": 70, # default value 6505 "CompressionThreshold": 70, # default value
6077 "CompressLevel": 0, # use zlib default 6506 "CompressLevel": 0, # use zlib default
6078 "CompressionDisable": False, 6507 "CompressionDisable": False,
6079 "PathPrefix": "", 6508 "PathPrefix": "",
6080 } 6509 }
6081 6510
6082 ######################################################################### 6511 #########################################################################
6083 ## Below are methods implementing some 'docstring' support functions 6512 ## Below are methods implementing some 'docstring' support functions
6084 ######################################################################### 6513 #########################################################################
6085 6514
6086 def hasDefaultDocstringParameter(self): 6515 def hasDefaultDocstringParameter(self):
6087 """ 6516 """
6088 Public method to test, if the project contains the default docstring 6517 Public method to test, if the project contains the default docstring
6089 parameter. 6518 parameter.
6090 6519
6091 @return flag indicating default parameter 6520 @return flag indicating default parameter
6092 @rtype bool 6521 @rtype bool
6093 """ 6522 """
6094 return self.pdata["DOCSTRING"] == "" 6523 return self.pdata["DOCSTRING"] == ""
6095 6524
6096 def getDocstringType(self): 6525 def getDocstringType(self):
6097 """ 6526 """
6098 Public method to get the configured docstring style. 6527 Public method to get the configured docstring style.
6099 6528
6100 @return configured docstring style 6529 @return configured docstring style
6101 @rtype str 6530 @rtype str
6102 """ 6531 """
6103 return self.pdata["DOCSTRING"] 6532 return self.pdata["DOCSTRING"]
6104 6533
6105 ######################################################################### 6534 #########################################################################
6106 ## Below are methods implementing the 'SBOM' support 6535 ## Below are methods implementing the 'SBOM' support
6107 ######################################################################### 6536 #########################################################################
6108 6537
6109 def __showContextMenuOthers(self): 6538 def __showContextMenuOthers(self):
6110 """ 6539 """
6111 Private slot called before the 'Other Tools' menu is shown. 6540 Private slot called before the 'Other Tools' menu is shown.
6112 """ 6541 """
6113 self.showMenu.emit("OtherTools", self.othersMenu) 6542 self.showMenu.emit("OtherTools", self.othersMenu)
6114 6543
6115 @pyqtSlot() 6544 @pyqtSlot()
6116 def __createSBOMFile(self): 6545 def __createSBOMFile(self):
6117 """ 6546 """
6118 Private slot to create a SBOM file of the project dependencies. 6547 Private slot to create a SBOM file of the project dependencies.
6119 """ 6548 """
6120 import CycloneDXInterface 6549 import CycloneDXInterface
6121 6550
6122 CycloneDXInterface.createCycloneDXFile("<project>") 6551 CycloneDXInterface.createCycloneDXFile("<project>")
6123 6552
6124 ######################################################################### 6553 #########################################################################
6125 ## Below are methods implementing the 'Code Formatting' support 6554 ## Below are methods implementing the 'Code Formatting' support
6126 ######################################################################### 6555 #########################################################################
6127 6556
6128 def __showContextMenuFormat(self): 6557 def __showContextMenuFormat(self):
6129 """ 6558 """
6130 Private slot called before the 'Code Formatting' menu is shown. 6559 Private slot called before the 'Code Formatting' menu is shown.
6131 """ 6560 """
6132 self.showMenu.emit("Formatting", self.othersMenu) 6561 self.showMenu.emit("Formatting", self.othersMenu)
6133 6562
6134 @pyqtSlot() 6563 @pyqtSlot()
6135 def __aboutBlack(self): 6564 def __aboutBlack(self):
6136 """ 6565 """
6137 Private slot to show some information about the installed 'Black' tool. 6566 Private slot to show some information about the installed 'Black' tool.
6138 """ 6567 """
6139 import black 6568 import black
6140 6569
6141 EricMessageBox.information( 6570 EricMessageBox.information(
6142 None, 6571 None,
6143 self.tr("About Black"), 6572 self.tr("About Black"),
6144 self.tr("""<p><b>Black Version {0}</b></p>""" 6573 self.tr(
6145 """<p><i>Black</i> is the uncompromising Python code""" 6574 """<p><b>Black Version {0}</b></p>"""
6146 """ formatter.</p>""").format(black.__version__) 6575 """<p><i>Black</i> is the uncompromising Python code"""
6147 ) 6576 """ formatter.</p>"""
6148 6577 ).format(black.__version__),
6578 )
6579
6149 def __performFormatWithBlack(self, action): 6580 def __performFormatWithBlack(self, action):
6150 """ 6581 """
6151 Private method to format the project sources using the 'Black' tool. 6582 Private method to format the project sources using the 'Black' tool.
6152 6583
6153 Following actions are supported. 6584 Following actions are supported.
6154 <ul> 6585 <ul>
6155 <li>BlackFormattingAction.Format - the code reformatting is performed</li> 6586 <li>BlackFormattingAction.Format - the code reformatting is performed</li>
6156 <li>BlackFormattingAction.Check - a check is performed, if code formatting 6587 <li>BlackFormattingAction.Check - a check is performed, if code formatting
6157 is necessary</li> 6588 is necessary</li>
6158 <li>BlackFormattingAction.Diff - a unified diff of potential code formatting 6589 <li>BlackFormattingAction.Diff - a unified diff of potential code formatting
6159 changes is generated</li> 6590 changes is generated</li>
6160 </ul> 6591 </ul>
6161 6592
6162 @param action formatting operation to be performed 6593 @param action formatting operation to be performed
6163 @type BlackFormattingAction 6594 @type BlackFormattingAction
6164 """ 6595 """
6165 from CodeFormatting.BlackConfigurationDialog import BlackConfigurationDialog 6596 from CodeFormatting.BlackConfigurationDialog import BlackConfigurationDialog
6166 from CodeFormatting.BlackFormattingDialog import BlackFormattingDialog 6597 from CodeFormatting.BlackFormattingDialog import BlackFormattingDialog
6167 6598
6168 if ericApp().getObject("ViewManager").checkAllDirty(): 6599 if ericApp().getObject("ViewManager").checkAllDirty():
6169 dlg = BlackConfigurationDialog(withProject=True) 6600 dlg = BlackConfigurationDialog(withProject=True)
6170 if dlg.exec() == QDialog.DialogCode.Accepted: 6601 if dlg.exec() == QDialog.DialogCode.Accepted:
6171 config = dlg.getConfiguration() 6602 config = dlg.getConfiguration()
6172 6603
6173 formattingDialog = BlackFormattingDialog( 6604 formattingDialog = BlackFormattingDialog(
6174 config, 6605 config,
6175 self.getProjectFiles("SOURCES", normalized=True), 6606 self.getProjectFiles("SOURCES", normalized=True),
6176 project=self, 6607 project=self,
6177 action=action 6608 action=action,
6178 ) 6609 )
6179 formattingDialog.exec() 6610 formattingDialog.exec()
6180 6611
6612
6181 # 6613 #
6182 # eflag: noqa = M601 6614 # eflag: noqa = M601

eric ide

mercurial