eric7/Project/Project.py

branch
eric7-maintenance
changeset 9192
a763d57e23bc
parent 9111
4ac66b6c33a4
parent 9187
e53e07c6f482
equal deleted inserted replaced
9137:bd90cbe0b7d2 9192:a763d57e23bc
13 import glob 13 import glob
14 import fnmatch 14 import fnmatch
15 import copy 15 import copy
16 import zipfile 16 import zipfile
17 import contextlib 17 import contextlib
18 import pathlib
18 19
19 from PyQt6.QtCore import ( 20 from PyQt6.QtCore import (
20 pyqtSlot, QFile, QFileInfo, pyqtSignal, QCryptographicHash, QIODevice, 21 pyqtSlot, QFile, pyqtSignal, QCryptographicHash, QIODevice, QByteArray,
21 QByteArray, QObject, QProcess 22 QObject, QProcess
22 ) 23 )
23 from PyQt6.QtGui import QKeySequence, QAction 24 from PyQt6.QtGui import QKeySequence, QAction
24 from PyQt6.QtWidgets import ( 25 from PyQt6.QtWidgets import (
25 QLineEdit, QToolBar, QDialog, QInputDialog, QMenu 26 QLineEdit, QToolBar, QDialog, QInputDialog, QMenu
26 ) 27 )
524 "PathPrefix": "", 525 "PathPrefix": "",
525 }, 526 },
526 "EOL": -1, 527 "EOL": -1,
527 "DOCSTRING": "", 528 "DOCSTRING": "",
528 "TESTING_FRAMEWORK": "", 529 "TESTING_FRAMEWORK": "",
530 "LICENSE": "",
529 } 531 }
530 532
531 self.__initDebugProperties() 533 self.__initDebugProperties()
532 534
533 self.pudata = { 535 self.pudata = {
689 self.recent = [] 691 self.recent = []
690 Preferences.Prefs.rsettings.sync() 692 Preferences.Prefs.rsettings.sync()
691 rp = Preferences.Prefs.rsettings.value(recentNameProject) 693 rp = Preferences.Prefs.rsettings.value(recentNameProject)
692 if rp is not None: 694 if rp is not None:
693 for f in rp: 695 for f in rp:
694 if QFileInfo(f).exists(): 696 if pathlib.Path(f).exists():
695 self.recent.append(f) 697 self.recent.append(f)
696 698
697 def __saveRecent(self): 699 def __saveRecent(self):
698 """ 700 """
699 Private method to save the list of recently opened filenames. 701 Private method to save the list of recently opened filenames.
1188 fn1, ext = os.path.splitext(os.path.basename(self.pfile)) 1190 fn1, ext = os.path.splitext(os.path.basename(self.pfile))
1189 fn = os.path.join(self.getProjectManagementDir(), 1191 fn = os.path.join(self.getProjectManagementDir(),
1190 '{0}.edj'.format(fn1)) 1192 '{0}.edj'.format(fn1))
1191 if os.path.exists(fn): 1193 if os.path.exists(fn):
1192 # try the new JSON based format first 1194 # try the new JSON based format first
1193 self.__debuggerPropertiesFile.readFile(fn) 1195 if self.__debuggerPropertiesFile.readFile(fn):
1196 self.debugPropertiesLoaded = True
1197 self.debugPropertiesChanged = False
1194 else: 1198 else:
1195 # try the old XML based format second 1199 # try the old XML based format second
1196 fn = os.path.join(self.getProjectManagementDir(), 1200 fn = os.path.join(self.getProjectManagementDir(),
1197 '{0}.e4d'.format(fn1)) 1201 '{0}.e4d'.format(fn1))
1198 1202
2339 bool(self.pdata["TRANSLATIONPATTERN"])) 2343 bool(self.pdata["TRANSLATIONPATTERN"]))
2340 self.makeGrp.setEnabled( 2344 self.makeGrp.setEnabled(
2341 self.pdata["MAKEPARAMS"]["MakeEnabled"]) 2345 self.pdata["MAKEPARAMS"]["MakeEnabled"])
2342 self.menuMakeAct.setEnabled( 2346 self.menuMakeAct.setEnabled(
2343 self.pdata["MAKEPARAMS"]["MakeEnabled"]) 2347 self.pdata["MAKEPARAMS"]["MakeEnabled"])
2348 self.menuOtherToolsAct.setEnabled(True)
2344 2349
2345 self.projectAboutToBeCreated.emit() 2350 self.projectAboutToBeCreated.emit()
2346 2351
2347 hashStr = str(QCryptographicHash.hash( 2352 hashStr = str(QCryptographicHash.hash(
2348 QByteArray(self.ppath.encode("utf-8")), 2353 QByteArray(self.ppath.encode("utf-8")),
3031 bool(self.pdata["TRANSLATIONPATTERN"])) 3036 bool(self.pdata["TRANSLATIONPATTERN"]))
3032 self.makeGrp.setEnabled( 3037 self.makeGrp.setEnabled(
3033 self.pdata["MAKEPARAMS"]["MakeEnabled"]) 3038 self.pdata["MAKEPARAMS"]["MakeEnabled"])
3034 self.menuMakeAct.setEnabled( 3039 self.menuMakeAct.setEnabled(
3035 self.pdata["MAKEPARAMS"]["MakeEnabled"]) 3040 self.pdata["MAKEPARAMS"]["MakeEnabled"])
3041 self.menuOtherToolsAct.setEnabled(True)
3036 3042
3037 # open a project debugger properties file being quiet 3043 # open a project debugger properties file being quiet
3038 # about errors 3044 # about errors
3039 if Preferences.getProject("AutoLoadDbgProperties"): 3045 if Preferences.getProject("AutoLoadDbgProperties"):
3040 self.__readDebugProperties(True) 3046 self.__readDebugProperties(True)
3122 self.tr("Project Files (*.epj)"), 3128 self.tr("Project Files (*.epj)"),
3123 defaultFilter, 3129 defaultFilter,
3124 EricFileDialog.DontConfirmOverwrite) 3130 EricFileDialog.DontConfirmOverwrite)
3125 3131
3126 if fn: 3132 if fn:
3127 ext = QFileInfo(fn).suffix() 3133 fpath = pathlib.Path(fn)
3128 if not ext: 3134 if not fpath.suffix:
3129 ex = selectedFilter.split("(*")[1].split(")")[0] 3135 ex = selectedFilter.split("(*")[1].split(")")[0]
3130 if ex: 3136 if ex:
3131 fn += ex 3137 fpath = fpath.with_suffix(ex)
3132 if QFileInfo(fn).exists(): 3138 if fpath.exists():
3133 res = EricMessageBox.yesNo( 3139 res = EricMessageBox.yesNo(
3134 self.ui, 3140 self.ui,
3135 self.tr("Save File"), 3141 self.tr("Save File"),
3136 self.tr("""<p>The file <b>{0}</b> already exists.""" 3142 self.tr("""<p>The file <b>{0}</b> already exists."""
3137 """ Overwrite it?</p>""").format(fn), 3143 """ Overwrite it?</p>""").format(fpath),
3138 icon=EricMessageBox.Warning) 3144 icon=EricMessageBox.Warning)
3139 if not res: 3145 if not res:
3140 return False 3146 return False
3141 3147
3142 self.name = QFileInfo(fn).baseName() 3148 self.name = fpath.stem
3143 ok = self.__writeProject(fn) 3149 ok = self.__writeProject(str(fpath))
3144 3150
3145 if ok: 3151 if ok:
3146 # create management directory if not present 3152 # create management directory if not present
3147 self.createProjectManagementDir() 3153 self.createProjectManagementDir()
3148 3154
3287 self.menuApidocAct.setEnabled(False) 3293 self.menuApidocAct.setEnabled(False)
3288 self.menuPackagersAct.setEnabled(False) 3294 self.menuPackagersAct.setEnabled(False)
3289 self.pluginGrp.setEnabled(False) 3295 self.pluginGrp.setEnabled(False)
3290 self.makeGrp.setEnabled(False) 3296 self.makeGrp.setEnabled(False)
3291 self.menuMakeAct.setEnabled(False) 3297 self.menuMakeAct.setEnabled(False)
3298 self.menuOtherToolsAct.setEnabled(False)
3292 3299
3293 self.__model.projectClosed() 3300 self.__model.projectClosed()
3294 self.projectClosedHooks.emit() 3301 self.projectClosedHooks.emit()
3295 self.projectClosed.emit(shutdown) 3302 self.projectClosed.emit(shutdown)
3296 3303
3779 @return testing framework name of the project 3786 @return testing framework name of the project
3780 @rtype str 3787 @rtype str
3781 """ 3788 """
3782 try: 3789 try:
3783 return self.pdata["TESTING_FRAMEWORK"] 3790 return self.pdata["TESTING_FRAMEWORK"]
3791 except KeyError:
3792 return ""
3793
3794 def getProjectLicense(self):
3795 """
3796 Public method to get the license type used by the project.
3797
3798 @return license type of the project
3799 @rtype str
3800 """
3801 try:
3802 return self.pdata["LICENSE"]
3784 except KeyError: 3803 except KeyError:
3785 return "" 3804 return ""
3786 3805
3787 def __isInPdata(self, fn): 3806 def __isInPdata(self, fn):
3788 """ 3807 """
4384 """ target is necessary.</p>""" 4403 """ target is necessary.</p>"""
4385 )) 4404 ))
4386 self.makeTestAct.triggered.connect( 4405 self.makeTestAct.triggered.connect(
4387 lambda: self.__executeMake(questionOnly=True)) 4406 lambda: self.__executeMake(questionOnly=True))
4388 self.actions.append(self.makeTestAct) 4407 self.actions.append(self.makeTestAct)
4408
4409 self.createSBOMAct = EricAction(
4410 self.tr('Create SBOM File'),
4411 self.tr('Create &SBOM File'), 0, 0,
4412 self, 'project_create_sbom')
4413 self.createSBOMAct.setStatusTip(
4414 self.tr("Create a SBOM file of the project dependencies."))
4415 self.createSBOMAct.setWhatsThis(self.tr(
4416 """<b>Create SBOM File</b>"""
4417 """<p>This allows the creation of a SBOM file of the project"""
4418 """ dependencies. This may be based on various input sources"""
4419 """ and will be saved as a CycloneDX SBOM file.</p>"""
4420 ))
4421 self.createSBOMAct.triggered.connect(self.__createSBOMFile)
4422 self.actions.append(self.createSBOMAct)
4389 4423
4390 self.closeAct.setEnabled(False) 4424 self.closeAct.setEnabled(False)
4391 self.saveAct.setEnabled(False) 4425 self.saveAct.setEnabled(False)
4392 self.saveasAct.setEnabled(False) 4426 self.saveasAct.setEnabled(False)
4393 self.actGrp2.setEnabled(False) 4427 self.actGrp2.setEnabled(False)
4422 self.graphicsMenu = QMenu(self.tr('&Diagrams'), toolsMenu) 4456 self.graphicsMenu = QMenu(self.tr('&Diagrams'), toolsMenu)
4423 self.packagersMenu = QMenu(self.tr('Pac&kagers'), toolsMenu) 4457 self.packagersMenu = QMenu(self.tr('Pac&kagers'), toolsMenu)
4424 self.apidocMenu = QMenu(self.tr('Source &Documentation'), toolsMenu) 4458 self.apidocMenu = QMenu(self.tr('Source &Documentation'), toolsMenu)
4425 self.apidocMenu.setTearOffEnabled(True) 4459 self.apidocMenu.setTearOffEnabled(True)
4426 self.makeMenu = QMenu(self.tr('Make'), toolsMenu) 4460 self.makeMenu = QMenu(self.tr('Make'), toolsMenu)
4461 self.othersMenu = QMenu(self.tr('Other Tools'), toolsMenu)
4427 4462
4428 self.__menus = { 4463 self.__menus = {
4429 "Main": menu, 4464 "Main": menu,
4430 "Recent": self.recentMenu, 4465 "Recent": self.recentMenu,
4431 "VCS": self.vcsMenu, 4466 "VCS": self.vcsMenu,
4435 "Session": self.sessionMenu, 4470 "Session": self.sessionMenu,
4436 "Apidoc": self.apidocMenu, 4471 "Apidoc": self.apidocMenu,
4437 "Debugger": self.debuggerMenu, 4472 "Debugger": self.debuggerMenu,
4438 "Packagers": self.packagersMenu, 4473 "Packagers": self.packagersMenu,
4439 "Make": self.makeMenu, 4474 "Make": self.makeMenu,
4475 "OtherTools": self.othersMenu,
4440 } 4476 }
4441 4477
4442 # connect the aboutToShow signals 4478 # connect the aboutToShow signals
4443 self.recentMenu.aboutToShow.connect(self.__showContextMenuRecent) 4479 self.recentMenu.aboutToShow.connect(self.__showContextMenuRecent)
4444 self.recentMenu.triggered.connect(self.__openRecent) 4480 self.recentMenu.triggered.connect(self.__openRecent)
4449 self.apidocMenu.aboutToShow.connect(self.__showContextMenuApiDoc) 4485 self.apidocMenu.aboutToShow.connect(self.__showContextMenuApiDoc)
4450 self.packagersMenu.aboutToShow.connect(self.__showContextMenuPackagers) 4486 self.packagersMenu.aboutToShow.connect(self.__showContextMenuPackagers)
4451 self.sessionMenu.aboutToShow.connect(self.__showContextMenuSession) 4487 self.sessionMenu.aboutToShow.connect(self.__showContextMenuSession)
4452 self.debuggerMenu.aboutToShow.connect(self.__showContextMenuDebugger) 4488 self.debuggerMenu.aboutToShow.connect(self.__showContextMenuDebugger)
4453 self.makeMenu.aboutToShow.connect(self.__showContextMenuMake) 4489 self.makeMenu.aboutToShow.connect(self.__showContextMenuMake)
4490 self.othersMenu.aboutToShow.connect(self.__showContextMenuOthers)
4454 menu.aboutToShow.connect(self.__showMenu) 4491 menu.aboutToShow.connect(self.__showMenu)
4455 4492
4456 # build the show menu 4493 # build the show menu
4457 self.menuShow.setTearOffEnabled(True) 4494 self.menuShow.setTearOffEnabled(True)
4458 self.menuShow.addAction(self.codeMetricsAct) 4495 self.menuShow.addAction(self.codeMetricsAct)
4480 4517
4481 # build the make menu 4518 # build the make menu
4482 self.makeMenu.setTearOffEnabled(True) 4519 self.makeMenu.setTearOffEnabled(True)
4483 self.makeMenu.addActions(self.makeGrp.actions()) 4520 self.makeMenu.addActions(self.makeGrp.actions())
4484 self.makeMenu.addSeparator() 4521 self.makeMenu.addSeparator()
4522
4523 # build the 'Other Tools' menu
4524 self.othersMenu.setTearOffEnabled(True)
4525 self.othersMenu.addAction(self.createSBOMAct)
4485 4526
4486 # build the project main menu 4527 # build the project main menu
4487 menu.setTearOffEnabled(True) 4528 menu.setTearOffEnabled(True)
4488 menu.addActions(self.actGrp1.actions()) 4529 menu.addActions(self.actGrp1.actions())
4489 self.menuRecentAct = menu.addMenu(self.recentMenu) 4530 self.menuRecentAct = menu.addMenu(self.recentMenu)
4517 self.menuShowAct = toolsMenu.addMenu(self.menuShow) 4558 self.menuShowAct = toolsMenu.addMenu(self.menuShow)
4518 toolsMenu.addSeparator() 4559 toolsMenu.addSeparator()
4519 self.menuApidocAct = toolsMenu.addMenu(self.apidocMenu) 4560 self.menuApidocAct = toolsMenu.addMenu(self.apidocMenu)
4520 toolsMenu.addSeparator() 4561 toolsMenu.addSeparator()
4521 self.menuPackagersAct = toolsMenu.addMenu(self.packagersMenu) 4562 self.menuPackagersAct = toolsMenu.addMenu(self.packagersMenu)
4563 toolsMenu.addSeparator()
4564 self.menuOtherToolsAct = toolsMenu.addMenu(self.othersMenu)
4522 4565
4523 self.menuCheckAct.setEnabled(False) 4566 self.menuCheckAct.setEnabled(False)
4524 self.menuShowAct.setEnabled(False) 4567 self.menuShowAct.setEnabled(False)
4525 self.menuDiagramAct.setEnabled(False) 4568 self.menuDiagramAct.setEnabled(False)
4526 self.menuSessionAct.setEnabled(False) 4569 self.menuSessionAct.setEnabled(False)
4527 self.menuDebuggerAct.setEnabled(False) 4570 self.menuDebuggerAct.setEnabled(False)
4528 self.menuApidocAct.setEnabled(False) 4571 self.menuApidocAct.setEnabled(False)
4529 self.menuPackagersAct.setEnabled(False) 4572 self.menuPackagersAct.setEnabled(False)
4530 self.menuMakeAct.setEnabled(False) 4573 self.menuMakeAct.setEnabled(False)
4574 self.menuOtherToolsAct.setEnabled(False)
4531 4575
4532 self.__menu = menu 4576 self.__menu = menu
4533 self.__toolsMenu = toolsMenu 4577 self.__toolsMenu = toolsMenu
4534 4578
4535 return menu, toolsMenu 4579 return menu, toolsMenu
4602 act = self.recentMenu.addAction( 4646 act = self.recentMenu.addAction(
4603 formatStr.format( 4647 formatStr.format(
4604 idx, 4648 idx,
4605 Utilities.compactPath(rp, self.ui.maxMenuFilePathLen))) 4649 Utilities.compactPath(rp, self.ui.maxMenuFilePathLen)))
4606 act.setData(rp) 4650 act.setData(rp)
4607 act.setEnabled(QFileInfo(rp).exists()) 4651 act.setEnabled(pathlib.Path(rp).exists())
4608 4652
4609 self.recentMenu.addSeparator() 4653 self.recentMenu.addSeparator()
4610 self.recentMenu.addAction(self.tr('&Clear'), self.clearRecent) 4654 self.recentMenu.addAction(self.tr('&Clear'), self.clearRecent)
4611 4655
4612 def __openRecent(self, act): 4656 def __openRecent(self, act):
5395 """ selected. Aborting...</p>""")) 5439 """ selected. Aborting...</p>"""))
5396 return 5440 return
5397 5441
5398 progress = EricProgressDialog( 5442 progress = EricProgressDialog(
5399 self.tr("Creating plugin archives..."), self.tr("Abort"), 5443 self.tr("Creating plugin archives..."), self.tr("Abort"),
5400 0, len(selectedLists), self.tr("%v/%m Archives")) 5444 0, len(selectedLists), self.tr("%v/%m Archives"), self.ui)
5401 progress.setMinimumDuration(0) 5445 progress.setMinimumDuration(0)
5402 progress.setWindowTitle(self.tr("Create Plugin Archives")) 5446 progress.setWindowTitle(self.tr("Create Plugin Archives"))
5403 errors = 0 5447 errors = 0
5404 for count, pkglist in enumerate(selectedLists): 5448 for count, pkglist in enumerate(selectedLists):
5405 progress.setValue(count) 5449 progress.setValue(count)
5912 5956
5913 @return configured docstring style 5957 @return configured docstring style
5914 @rtype str 5958 @rtype str
5915 """ 5959 """
5916 return self.pdata["DOCSTRING"] 5960 return self.pdata["DOCSTRING"]
5961
5962 #########################################################################
5963 ## Below are methods implementing the 'SBOM' support
5964 #########################################################################
5965
5966 def __showContextMenuOthers(self):
5967 """
5968 Private slot called before the 'Other Tools' menu is shown.
5969 """
5970 self.showMenu.emit("OtherTools", self.othersMenu)
5971
5972 @pyqtSlot()
5973 def __createSBOMFile(self):
5974 """
5975 Private slot to create a SBOM file of the project dependencies.
5976 """
5977 import CycloneDXInterface
5978
5979 CycloneDXInterface.createCycloneDXFile("<project>")
5917 5980
5918 # 5981 #
5919 # eflag: noqa = M601 5982 # eflag: noqa = M601

eric ide

mercurial