diff -r 6bbb4e047902 -r 7085ece52151 eric7/CycloneDXInterface/CycloneDXMetaDataDialog.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/eric7/CycloneDXInterface/CycloneDXMetaDataDialog.py Thu Jun 09 16:13:18 2022 +0200 @@ -0,0 +1,149 @@ +# -*- coding: utf-8 -*- + +# Copyright (c) 2022 Detlev Offenbach <detlev@die-offenbachs.de> +# + +""" +Module implementing a dialog to edit the metadata of the CycloneDX SBOM. +""" + +import os + +from PyQt6.QtCore import pyqtSlot, QCoreApplication +from PyQt6.QtWidgets import QDialog, QDialogButtonBox + +from EricWidgets import EricMessageBox + +from cyclonedx.model.component import ComponentType + +from .Ui_CycloneDXMetaDataDialog import Ui_CycloneDXMetaDataDialog + + +class CycloneDXMetaDataDialog(QDialog, Ui_CycloneDXMetaDataDialog): + """ + Class implementing a dialog to edit the metadata of the CycloneDX SBOM. + """ + ComponentTypeMapping = { + ComponentType.APPLICATION: QCoreApplication.translate( + "CycloneDXMetaDataDialog", "Application"), + ComponentType.CONTAINER: QCoreApplication.translate( + "CycloneDXMetaDataDialog", "Container"), + ComponentType.DEVICE: QCoreApplication.translate( + "CycloneDXMetaDataDialog", "Device"), + ComponentType.FILE: QCoreApplication.translate( + "CycloneDXMetaDataDialog", "File"), + ComponentType.FIRMWARE: QCoreApplication.translate( + "CycloneDXMetaDataDialog", "Firmware"), + ComponentType.FRAMEWORK: QCoreApplication.translate( + "CycloneDXMetaDataDialog", "Framework"), + ComponentType.LIBRARY: QCoreApplication.translate( + "CycloneDXMetaDataDialog", "Library"), + ComponentType.OPERATING_SYSTEM: QCoreApplication.translate( + "CycloneDXMetaDataDialog", "Operating System"), + } + + def __init__(self, metadata=None, parent=None): + """ + Constructor + + @param metadata dictionary containing metadata to populate the dialog + (defaults to None) + @type dict (optional) + @param parent reference to the parent widget (defaults to None) + @type QWidget (optional) + """ + super().__init__(parent) + self.setupUi(self) + + self.__populateComponentTypeSelector() + self.__populateLicenseSelector() + + if metadata: + # populate the dialog from given metadata dictionary + self.nameEdit.setText(metadata["Name"]) + self.versionEdit.setText(metadata["Version"]) + self.descriptionEdit.setPlainText(metadata["Description"]) + self.authorEdit.setText(metadata["AuthorName"]) + self.emailEdit.setText(metadata["AuthorEmail"]) + self.licenseComboBox.setCurrentText(metadata["License"]) + self.manufacturerEdit.setText(metadata["Manufacturer"]) + self.supplierEdit.setText(metadata["Supplier"]) + index = self.typeComboBox.findData(metadata["Type"]) + self.typeComboBox.setCurrentIndex(index) + + self.nameEdit.textChanged.connect(self.__updateOkButton) + self.typeComboBox.currentTextChanged.connect(self.__updateOkButton) + self.licenseComboBox.currentTextChanged.connect(self.__updateOkButton) + + self.__updateOkButton() + + def __populateComponentTypeSelector(self): + """ + Private method to populate the component type selector. + """ + self.typeComboBox.addItem("", "") + for componentType, displayStr in sorted( + CycloneDXMetaDataDialog.ComponentTypeMapping.items(), + key=lambda x: x[1] + ): + self.typeComboBox.addItem(displayStr, componentType) + + def __populateLicenseSelector(self): + """ + Private method to populate the license selector with the list of trove + license types. + + Note: The trove licanese list file was created from querying + "https://pypi.org/pypi?%3Aaction=list_classifiers". + """ + filename = os.path.join( + os.path.dirname(__file__), "..", "data", + "trove_license_classifiers.txt") + try: + with open(filename, "r") as f: + lines = f.readlines() + except OSError as err: + EricMessageBox.warning( + self, + self.tr("Reading Trove License Classifiers"), + self.tr("""<p>The Trove License Classifiers file <b>{0}</b>""" + """ could not be read.</p><p>Reason: {1}</p>""") + .format(filename, str(err))) + return + + self.licenseComboBox.addItem("") + self.licenseComboBox.addItems(sorted( + line.split("::")[-1].strip() + for line in lines + if line.startswith("License ") # play it safe + )) + + @pyqtSlot() + def __updateOkButton(self): + """ + Private slot to update the enabled state of the OK button. + """ + self.buttonBox.button(QDialogButtonBox.StandardButton.Ok).setEnabled( + bool(self.nameEdit.text()) and + bool(self.typeComboBox.currentText()) and + bool(self.licenseComboBox.currentText()) + ) + + def getMetaData(self): + """ + Public method to get the entered data. + + @return dictionary containing the metadata. + @rtype dict + """ + return { + "Name": self.nameEdit.text(), + "Type": self.typeComboBox.currentData(), + "Version": self.versionEdit.text(), + "Description": self.descriptionEdit.toPlainText(), + "AuthorName": self.authorEdit.text(), + "AuthorEmail": self.emailEdit.text(), + "License": self.licenseComboBox.currentText(), + "Manufacturer": self.manufacturerEdit.text(), + "Supplier": self.supplierEdit.text(), + }