eric7/CycloneDXInterface/CycloneDXMetaDataDialog.py

Thu, 09 Jun 2022 16:13:18 +0200

author
Detlev Offenbach <detlev@die-offenbachs.de>
date
Thu, 09 Jun 2022 16:13:18 +0200
branch
eric7
changeset 9141
7085ece52151
child 9175
21e2be5f0b41
permissions
-rw-r--r--

Completed the SBOM generation support by adding a metadata dialog.

# -*- 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(),
        }

eric ide

mercurial