Skip to content

bmz_export_widget

BMZExportWidget #

Bases: QDialog

A dialog to get information about the model to export.

Source code in src/careamics_napari/bmz/bmz_export_widget.py
class BMZExportWidget(QDialog):
    """A dialog to get information about the model to export."""

    def __init__(
        self,
        parent: QWidget | None = None,
        cover_image_path: str | Path | None = None,
    ):
        """Initialize the widget.

        Parameters
        ----------
        parent : QWidget
            Parent widget. Default is None.
        careamics_config : BaseConfig
            The configuration for the CAREamics algorithm.
        """
        super().__init__(parent)
        self.setWindowModality(Qt.ApplicationModal)  # type: ignore

        self.default_cover = str(cover_image_path)
        self.uploaded_cover = None
        self.authors: list[AuthorModel] = []

        # ui
        # model name
        self.name_textbox = QLineEdit()
        self.name_textbox.setPlaceholderText("At least 5 characters")

        # general description
        self.description_textbox = QPlainTextEdit()
        self.description_textbox.setFixedHeight(90)
        self.description_textbox.setPlaceholderText(
            "Enter a short description of your model."
        )

        # data description
        self.data_description_textbox = QPlainTextEdit()
        self.data_description_textbox.setFixedHeight(120)
        self.data_description_textbox.setPlaceholderText(
            "Describe the data that you used for training the model.\n"
            "Use Markdown formatting and must include a 'Validation' header "
            "(like ### Validation) describing validation metrics & methods."
        )

        # authors
        self.authors_listview = QListWidget()
        self.authors_listview.setFixedHeight(90)
        self.add_author_button = QPushButton("Add")
        self.add_author_button.clicked.connect(self._open_new_author)
        self.edit_author_button = QPushButton("Edit")
        self.edit_author_button.clicked.connect(self._open_edit_author)
        self.del_author_button = QPushButton("Remove")
        self.del_author_button.clicked.connect(self._del_author)

        # cover image
        self.image_label = QLabel()
        self.image_label.setBackgroundRole(QPalette.Dark)
        self.image_label.setSizePolicy(QSizePolicy.Ignored, QSizePolicy.Ignored)
        self.image_label.setScaledContents(True)

        self.image_scroll = QScrollArea()
        self.image_scroll.setBackgroundRole(QPalette.Dark)
        self.image_scroll.setWidget(self.image_label)
        self.image_scroll.setFixedHeight(300)
        self.image_scroll.setStyleSheet("border: 1px solid grey;")

        self.default_cover_button = QPushButton("Default Cover Image")
        self.default_cover_button.setMaximumWidth(150)
        self.default_cover_button.clicked.connect(self._set_default_cover_image)
        self.upload_image_button = QPushButton("Upload Cover Image")
        self.upload_image_button.setMaximumWidth(150)
        self.upload_image_button.clicked.connect(self._upload_cover_image)

        # submit & cancel buttons
        self.submit_button = QPushButton("&Export")
        self.submit_button.setMaximumWidth(120)
        self.submit_button.clicked.connect(self._submit)
        self.cancel_button = QPushButton("&Cancel")
        self.cancel_button.setMaximumWidth(120)
        self.cancel_button.clicked.connect(lambda: self.reject())  # type: ignore

        # layout
        form = QFormLayout()
        form.setFormAlignment(Qt.AlignLeft | Qt.AlignTop)  # type: ignore
        form.setFieldGrowthPolicy(
            QFormLayout.AllNonFixedFieldsGrow  # type: ignore
        )
        form.addRow("Model Name: ", self.name_textbox)
        form.addRow("General Description:", self.description_textbox)
        form.addRow("Data Description:", self.data_description_textbox)
        vbox = QVBoxLayout()
        vbox.addWidget(self.add_author_button)
        vbox.addWidget(self.edit_author_button)
        vbox.addWidget(self.del_author_button)
        hbox = QHBoxLayout()
        hbox.addWidget(self.authors_listview)
        hbox.addLayout(vbox)
        form.addRow("Authors:", hbox)
        hbox = QHBoxLayout()
        hbox.addWidget(self.default_cover_button)  # type: ignore
        hbox.addWidget(self.upload_image_button)  # type: ignore
        vbox = QVBoxLayout()
        vbox.addWidget(self.image_scroll)
        vbox.addLayout(hbox)
        vbox.addSpacing(15)
        form.addRow("Cover Image:", vbox)
        hbox = QHBoxLayout()
        hbox.addWidget(self.submit_button)
        hbox.addWidget(self.cancel_button)
        form.addRow(hbox)

        self.setLayout(form)
        self.setWindowTitle("BMZ Export")

        self._bind_properties()
        self._set_default_cover_image()

    def _bind_properties(self) -> None:
        """Bind the properties to the UI elements."""
        type(self).model_name = bind(self.name_textbox, "text")
        type(self).general_description = bind(self.description_textbox, "plainText")
        type(self).data_description = bind(self.data_description_textbox, "plainText")
        type(self).cover_image = property(
            fget=lambda self: self.uploaded_cover
            if self.uploaded_cover is not None
            else self.default_cover,
        )

    def _populate_authors_list(self) -> None:
        """Populates the authors' listview widget with the list of authors."""
        self.authors_listview.clear()
        self.authors_listview.addItems(author.name for author in self.authors)

    def _open_new_author(self) -> None:
        """Show author's form to add a new author."""
        author_win = AuthorWidget(self)
        author_win.setWindowModality(Qt.ApplicationModal)  # type: ignore
        author_win.submit.connect(self._add_author)
        author_win.show()

    def _open_edit_author(self) -> None:
        """Show author's form to modify an existing author."""
        selected_index = self.authors_listview.currentRow()
        if selected_index > -1:
            author = self.authors[selected_index]
            author_win = AuthorWidget(self, author)
            author_win.setWindowModality(Qt.ApplicationModal)  # type: ignore
            author_win.submit.connect(
                lambda author: self._update_author(selected_index, author)
            )
            author_win.show()

    def _del_author(self) -> None:
        """Remove the selected author."""
        selected_index = self.authors_listview.currentRow()
        if selected_index > -1:
            reply, del_row = self._remove_from_listview(
                self.authors_listview,
                "Are you sure you want to remove the selected author?",
            )
            if reply:
                del self.authors[del_row]
                self._populate_authors_list()

    def _add_author(self, author: AuthorModel) -> None:
        """Add a new author to the list."""
        self.authors.append(author)
        self._populate_authors_list()

    def _update_author(self, index: int, author: AuthorModel) -> None:
        """Update the author at the given index with the given data."""
        self.authors[index] = author
        self._populate_authors_list()

    def _remove_from_listview(
        self, list_widget: QListWidget, msg: str | None = None
    ) -> tuple[QMessageBox.StandardButton, int]:
        """Removes the selected item from the given listview widget."""
        curr_row = list_widget.currentRow()
        if curr_row > -1:
            reply = QMessageBox.warning(
                self,
                "CAREamics",
                msg or "Are you sure you want to remove the selected item from the list?",
                QMessageBox.Yes | QMessageBox.No,
                QMessageBox.No,
            )
            if reply == QMessageBox.Yes:
                list_widget.takeItem(curr_row)

        return reply == QMessageBox.Yes, curr_row

    def _set_default_cover_image(self) -> None:
        """Set the default cover image."""
        self.image_label.setPixmap(QPixmap(self.default_cover))
        self.image_label.adjustSize()

    def _upload_cover_image(self) -> None:
        """Upload a cover image."""
        file_path, _ = QFileDialog.getOpenFileName(
            self,
            "Select Cover Image",
            "",
            "Image Files (*.png *.jpg *.bmp);;All Files (*)",
        )
        if file_path:
            self.uploaded_cover = file_path
            self.image_label.setPixmap(QPixmap(file_path))
            self.image_label.adjustSize()

    def _submit(self) -> None:
        """Submit the entered information."""
        if len(self.model_name.strip()) < 5:
            QMessageBox.critical(
                self, "CAREamics", "Model name must be at least 5 characters long!"
            )
            return
        if not self.general_description.strip():
            QMessageBox.critical(self, "CAREamics", "General description is required!")
            return
        if not self.data_description.strip():
            QMessageBox.critical(self, "CAREamics", "Data description is required!")
            return
        if not self.authors:
            QMessageBox.critical(self, "CAREamics", "At least one author is required!")
            return
        if self.cover_image is None:
            QMessageBox.critical(self, "CAREamics", "A cover image is required!")
            return

        self.accept()

__init__(parent=None, cover_image_path=None) #

Initialize the widget.

Parameters:

Name Type Description Default
parent QWidget

Parent widget. Default is None.

None
careamics_config BaseConfig

The configuration for the CAREamics algorithm.

required
Source code in src/careamics_napari/bmz/bmz_export_widget.py
def __init__(
    self,
    parent: QWidget | None = None,
    cover_image_path: str | Path | None = None,
):
    """Initialize the widget.

    Parameters
    ----------
    parent : QWidget
        Parent widget. Default is None.
    careamics_config : BaseConfig
        The configuration for the CAREamics algorithm.
    """
    super().__init__(parent)
    self.setWindowModality(Qt.ApplicationModal)  # type: ignore

    self.default_cover = str(cover_image_path)
    self.uploaded_cover = None
    self.authors: list[AuthorModel] = []

    # ui
    # model name
    self.name_textbox = QLineEdit()
    self.name_textbox.setPlaceholderText("At least 5 characters")

    # general description
    self.description_textbox = QPlainTextEdit()
    self.description_textbox.setFixedHeight(90)
    self.description_textbox.setPlaceholderText(
        "Enter a short description of your model."
    )

    # data description
    self.data_description_textbox = QPlainTextEdit()
    self.data_description_textbox.setFixedHeight(120)
    self.data_description_textbox.setPlaceholderText(
        "Describe the data that you used for training the model.\n"
        "Use Markdown formatting and must include a 'Validation' header "
        "(like ### Validation) describing validation metrics & methods."
    )

    # authors
    self.authors_listview = QListWidget()
    self.authors_listview.setFixedHeight(90)
    self.add_author_button = QPushButton("Add")
    self.add_author_button.clicked.connect(self._open_new_author)
    self.edit_author_button = QPushButton("Edit")
    self.edit_author_button.clicked.connect(self._open_edit_author)
    self.del_author_button = QPushButton("Remove")
    self.del_author_button.clicked.connect(self._del_author)

    # cover image
    self.image_label = QLabel()
    self.image_label.setBackgroundRole(QPalette.Dark)
    self.image_label.setSizePolicy(QSizePolicy.Ignored, QSizePolicy.Ignored)
    self.image_label.setScaledContents(True)

    self.image_scroll = QScrollArea()
    self.image_scroll.setBackgroundRole(QPalette.Dark)
    self.image_scroll.setWidget(self.image_label)
    self.image_scroll.setFixedHeight(300)
    self.image_scroll.setStyleSheet("border: 1px solid grey;")

    self.default_cover_button = QPushButton("Default Cover Image")
    self.default_cover_button.setMaximumWidth(150)
    self.default_cover_button.clicked.connect(self._set_default_cover_image)
    self.upload_image_button = QPushButton("Upload Cover Image")
    self.upload_image_button.setMaximumWidth(150)
    self.upload_image_button.clicked.connect(self._upload_cover_image)

    # submit & cancel buttons
    self.submit_button = QPushButton("&Export")
    self.submit_button.setMaximumWidth(120)
    self.submit_button.clicked.connect(self._submit)
    self.cancel_button = QPushButton("&Cancel")
    self.cancel_button.setMaximumWidth(120)
    self.cancel_button.clicked.connect(lambda: self.reject())  # type: ignore

    # layout
    form = QFormLayout()
    form.setFormAlignment(Qt.AlignLeft | Qt.AlignTop)  # type: ignore
    form.setFieldGrowthPolicy(
        QFormLayout.AllNonFixedFieldsGrow  # type: ignore
    )
    form.addRow("Model Name: ", self.name_textbox)
    form.addRow("General Description:", self.description_textbox)
    form.addRow("Data Description:", self.data_description_textbox)
    vbox = QVBoxLayout()
    vbox.addWidget(self.add_author_button)
    vbox.addWidget(self.edit_author_button)
    vbox.addWidget(self.del_author_button)
    hbox = QHBoxLayout()
    hbox.addWidget(self.authors_listview)
    hbox.addLayout(vbox)
    form.addRow("Authors:", hbox)
    hbox = QHBoxLayout()
    hbox.addWidget(self.default_cover_button)  # type: ignore
    hbox.addWidget(self.upload_image_button)  # type: ignore
    vbox = QVBoxLayout()
    vbox.addWidget(self.image_scroll)
    vbox.addLayout(hbox)
    vbox.addSpacing(15)
    form.addRow("Cover Image:", vbox)
    hbox = QHBoxLayout()
    hbox.addWidget(self.submit_button)
    hbox.addWidget(self.cancel_button)
    form.addRow(hbox)

    self.setLayout(form)
    self.setWindowTitle("BMZ Export")

    self._bind_properties()
    self._set_default_cover_image()