Module soitool.module_list

Includes functionality for displaying a prioritized list of modules.

Expand source code
"""Includes functionality for displaying a prioritized list of modules."""
from PySide2.QtCore import Qt
from PySide2.QtWidgets import (
    QListWidget,
    QListWidgetItem,
    QAbstractItemView,
)
from soitool.dialog_wrappers import exec_warning_dialog
from soitool.soi import SOI
from soitool.enumerates import ModuleType


class ModuleList(QListWidget):
    """Contains module-names from soitool.SOI.

    List elements are names of modules or attachment-modules from soitool.SOI.
    List elements are editable, drag-and-droppable and unique (no duplicates).
    Makes changes in soitool.SOI lists through its soi property.

    Parameters
    ----------
    module_type : int
        Determines whether names are from modules or attachment-modules.
        Is used with the Enum 'ModuleType' to know which SOI-list (modules or
        attachments) to update when changes are made.
    soi : soitool.soi.SOI
        Reference to SOI-instance.
    """

    def __init__(self, module_type, soi):
        super().__init__()

        if not isinstance(soi, SOI):
            raise RuntimeError(
                "Only soitool.SOI is "
                "acceptable type for the soi property "
                "in class ModuleList."
            )
        self.type = module_type
        self.soi = soi
        self.original_element_name = None
        self.original_element_index = None

        self.setup_list()
        self.fill_list()

        self.soi.add_reorganization_listener(self.update_list_order)

    def setup_list(self):
        """Prepare list.

        Make list drag-and-droppable and remove horizontal scrollbar.
        """
        # Enable drag-and-drop
        self.setDragEnabled(True)
        self.viewport().setAcceptDrops(True)
        self.setDragDropMode(QAbstractItemView.InternalMove)

        # Remove horizontal scrollbar
        self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)

    def fill_list(self):
        """Fill list with elements in order defined in SOI."""
        # Get names of modules/attachments:
        if ModuleType(self.type) == ModuleType.MAIN_MODULE:
            names = [module["meta"]["name"] for module in self.soi.modules]
        elif ModuleType(self.type) == ModuleType.ATTACHMENT_MODULE:
            names = [
                attachment["meta"]["name"]
                for attachment in self.soi.attachments
            ]

        for i, name in enumerate(names):
            item = QListWidgetItem(name)
            item.setFlags(item.flags() | Qt.ItemIsEditable)
            self.insertItem(i, item)

    def update_list_order(self):
        """Update order of modules in list to respect order in SOI."""
        self.clear()
        self.fill_list()

    def currentChanged(self, current, previous):
        """Save name and index of an element when it is selected.

        Function is needed to remember original:
        1: index of an element in case it's' drag-and-dropped (notify parent).
        2: name of an element in case it's name changes (avoid duplicates).

        https://doc.qt.io/qt-5/qlistview.html#currentChanged.

        Parameters
        ----------
        current : QModelIndex
            Used to get index of element, is sent to super().
        previous : QModelIndex
            Is sent to super().
        """
        super().currentChanged(current, previous)
        # If an item is selected
        if current.row() != -1:
            self.original_element_name = self.item(current.row()).text()
            self.original_element_index = current.row()

    def dataChanged(self, index1, index2, roles):
        """Check for duplicate name and notify parent when an element changes.

        https://doc.qt.io/qt-5/qabstractitemview.html#dataChanged.

        Parameters
        ----------
        index1 : QModelIndex
            Used to get index of changed element, is sent to super().
        index2 : QModelIndex
            Is sent to super().
        roles : QVector
            Is sent to super().
        """
        index = index1.row()
        # Get all names and new name
        names = [self.item(i).text() for i in range(self.count())]
        new_name = names[index]

        # Count occurrences of new name
        occurrences = names.count(new_name)

        # If new name already exists, replace with original name
        if occurrences > 1:
            self.item(index).setText(self.original_element_name)
        # Name does not already exist, update list in soi
        else:
            name = self.item(index).text()

            if ModuleType(self.type) == ModuleType.MAIN_MODULE:
                self.soi.modules[index]["meta"]["name"] = name
            elif ModuleType(self.type) == ModuleType.ATTACHMENT_MODULE:
                self.soi.attachments[index]["meta"]["name"] = name

        super().dataChanged(index1, index2, roles)

    def dropEvent(self, event):
        """Notify parent when an element is drag-and-dropped.

        Note that if the SOI is not prepared for manual priorization an error
        message will be displayed, and nothing else will be done. This only
        applies to uses of this class with non-attachment modules.

        https://doc.qt.io/qt-5/qabstractitemview.html#dropEvent.

        Parameters
        ----------
        event : QDropEvent
            Is sent to super().
        """
        if (
            self.soi.algorithm_sort != "none"
            and ModuleType(self.type) == ModuleType.MAIN_MODULE
        ):
            exec_warning_dialog(
                text="SOI er ikke innstilt for manuell prioritering av "
                "moduler!",
                informative_text="Enn så lenge vil manuell prioritering av "
                "moduler bare fungere dersom SOI er innstilt til ikke å gjøre "
                "sortering av moduler før pakking. I fremtiden vil det være "
                "mulig å låse utvalgte moduler, men la resten optimalt "
                "pakkes.",
            )

        else:
            super().dropEvent(event)

            # Get origin and destination index of module/attachment
            origin = self.original_element_index
            destination = self.currentRow()

            # Update module/attachment priority (order in list):
            if ModuleType(self.type) == ModuleType.MAIN_MODULE:
                moving_module = self.soi.modules.pop(origin)
                self.soi.modules.insert(destination, moving_module)
            elif ModuleType(self.type) == ModuleType.ATTACHMENT_MODULE:
                moving_module = self.soi.attachments.pop(origin)
                self.soi.attachments.insert(destination, moving_module)

            self.soi.reorganize()

            self.original_element_index = self.currentRow()

Classes

class ModuleList (module_type, soi)

Contains module-names from soitool.SOI.

List elements are names of modules or attachment-modules from soitool.SOI. List elements are editable, drag-and-droppable and unique (no duplicates). Makes changes in soitool.SOI lists through its soi property.

Parameters

module_type : int
Determines whether names are from modules or attachment-modules. Is used with the Enum 'ModuleType' to know which SOI-list (modules or attachments) to update when changes are made.
soi : SOI
Reference to SOI-instance.
Expand source code
class ModuleList(QListWidget):
    """Contains module-names from soitool.SOI.

    List elements are names of modules or attachment-modules from soitool.SOI.
    List elements are editable, drag-and-droppable and unique (no duplicates).
    Makes changes in soitool.SOI lists through its soi property.

    Parameters
    ----------
    module_type : int
        Determines whether names are from modules or attachment-modules.
        Is used with the Enum 'ModuleType' to know which SOI-list (modules or
        attachments) to update when changes are made.
    soi : soitool.soi.SOI
        Reference to SOI-instance.
    """

    def __init__(self, module_type, soi):
        super().__init__()

        if not isinstance(soi, SOI):
            raise RuntimeError(
                "Only soitool.SOI is "
                "acceptable type for the soi property "
                "in class ModuleList."
            )
        self.type = module_type
        self.soi = soi
        self.original_element_name = None
        self.original_element_index = None

        self.setup_list()
        self.fill_list()

        self.soi.add_reorganization_listener(self.update_list_order)

    def setup_list(self):
        """Prepare list.

        Make list drag-and-droppable and remove horizontal scrollbar.
        """
        # Enable drag-and-drop
        self.setDragEnabled(True)
        self.viewport().setAcceptDrops(True)
        self.setDragDropMode(QAbstractItemView.InternalMove)

        # Remove horizontal scrollbar
        self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)

    def fill_list(self):
        """Fill list with elements in order defined in SOI."""
        # Get names of modules/attachments:
        if ModuleType(self.type) == ModuleType.MAIN_MODULE:
            names = [module["meta"]["name"] for module in self.soi.modules]
        elif ModuleType(self.type) == ModuleType.ATTACHMENT_MODULE:
            names = [
                attachment["meta"]["name"]
                for attachment in self.soi.attachments
            ]

        for i, name in enumerate(names):
            item = QListWidgetItem(name)
            item.setFlags(item.flags() | Qt.ItemIsEditable)
            self.insertItem(i, item)

    def update_list_order(self):
        """Update order of modules in list to respect order in SOI."""
        self.clear()
        self.fill_list()

    def currentChanged(self, current, previous):
        """Save name and index of an element when it is selected.

        Function is needed to remember original:
        1: index of an element in case it's' drag-and-dropped (notify parent).
        2: name of an element in case it's name changes (avoid duplicates).

        https://doc.qt.io/qt-5/qlistview.html#currentChanged.

        Parameters
        ----------
        current : QModelIndex
            Used to get index of element, is sent to super().
        previous : QModelIndex
            Is sent to super().
        """
        super().currentChanged(current, previous)
        # If an item is selected
        if current.row() != -1:
            self.original_element_name = self.item(current.row()).text()
            self.original_element_index = current.row()

    def dataChanged(self, index1, index2, roles):
        """Check for duplicate name and notify parent when an element changes.

        https://doc.qt.io/qt-5/qabstractitemview.html#dataChanged.

        Parameters
        ----------
        index1 : QModelIndex
            Used to get index of changed element, is sent to super().
        index2 : QModelIndex
            Is sent to super().
        roles : QVector
            Is sent to super().
        """
        index = index1.row()
        # Get all names and new name
        names = [self.item(i).text() for i in range(self.count())]
        new_name = names[index]

        # Count occurrences of new name
        occurrences = names.count(new_name)

        # If new name already exists, replace with original name
        if occurrences > 1:
            self.item(index).setText(self.original_element_name)
        # Name does not already exist, update list in soi
        else:
            name = self.item(index).text()

            if ModuleType(self.type) == ModuleType.MAIN_MODULE:
                self.soi.modules[index]["meta"]["name"] = name
            elif ModuleType(self.type) == ModuleType.ATTACHMENT_MODULE:
                self.soi.attachments[index]["meta"]["name"] = name

        super().dataChanged(index1, index2, roles)

    def dropEvent(self, event):
        """Notify parent when an element is drag-and-dropped.

        Note that if the SOI is not prepared for manual priorization an error
        message will be displayed, and nothing else will be done. This only
        applies to uses of this class with non-attachment modules.

        https://doc.qt.io/qt-5/qabstractitemview.html#dropEvent.

        Parameters
        ----------
        event : QDropEvent
            Is sent to super().
        """
        if (
            self.soi.algorithm_sort != "none"
            and ModuleType(self.type) == ModuleType.MAIN_MODULE
        ):
            exec_warning_dialog(
                text="SOI er ikke innstilt for manuell prioritering av "
                "moduler!",
                informative_text="Enn så lenge vil manuell prioritering av "
                "moduler bare fungere dersom SOI er innstilt til ikke å gjøre "
                "sortering av moduler før pakking. I fremtiden vil det være "
                "mulig å låse utvalgte moduler, men la resten optimalt "
                "pakkes.",
            )

        else:
            super().dropEvent(event)

            # Get origin and destination index of module/attachment
            origin = self.original_element_index
            destination = self.currentRow()

            # Update module/attachment priority (order in list):
            if ModuleType(self.type) == ModuleType.MAIN_MODULE:
                moving_module = self.soi.modules.pop(origin)
                self.soi.modules.insert(destination, moving_module)
            elif ModuleType(self.type) == ModuleType.ATTACHMENT_MODULE:
                moving_module = self.soi.attachments.pop(origin)
                self.soi.attachments.insert(destination, moving_module)

            self.soi.reorganize()

            self.original_element_index = self.currentRow()

Ancestors

  • PySide2.QtWidgets.QListWidget
  • PySide2.QtWidgets.QListView
  • PySide2.QtWidgets.QAbstractItemView
  • PySide2.QtWidgets.QAbstractScrollArea
  • PySide2.QtWidgets.QFrame
  • PySide2.QtWidgets.QWidget
  • PySide2.QtCore.QObject
  • PySide2.QtGui.QPaintDevice
  • Shiboken.Object

Class variables

var staticMetaObject

Methods

def currentChanged(self, current, previous)

Save name and index of an element when it is selected.

Function is needed to remember original: 1: index of an element in case it's' drag-and-dropped (notify parent). 2: name of an element in case it's name changes (avoid duplicates).

https://doc.qt.io/qt-5/qlistview.html#currentChanged.

Parameters

current : QModelIndex
Used to get index of element, is sent to super().
previous : QModelIndex
Is sent to super().
Expand source code
def currentChanged(self, current, previous):
    """Save name and index of an element when it is selected.

    Function is needed to remember original:
    1: index of an element in case it's' drag-and-dropped (notify parent).
    2: name of an element in case it's name changes (avoid duplicates).

    https://doc.qt.io/qt-5/qlistview.html#currentChanged.

    Parameters
    ----------
    current : QModelIndex
        Used to get index of element, is sent to super().
    previous : QModelIndex
        Is sent to super().
    """
    super().currentChanged(current, previous)
    # If an item is selected
    if current.row() != -1:
        self.original_element_name = self.item(current.row()).text()
        self.original_element_index = current.row()
def dataChanged(self, index1, index2, roles)

Check for duplicate name and notify parent when an element changes.

https://doc.qt.io/qt-5/qabstractitemview.html#dataChanged.

Parameters

index1 : QModelIndex
Used to get index of changed element, is sent to super().
index2 : QModelIndex
Is sent to super().
roles : QVector
Is sent to super().
Expand source code
def dataChanged(self, index1, index2, roles):
    """Check for duplicate name and notify parent when an element changes.

    https://doc.qt.io/qt-5/qabstractitemview.html#dataChanged.

    Parameters
    ----------
    index1 : QModelIndex
        Used to get index of changed element, is sent to super().
    index2 : QModelIndex
        Is sent to super().
    roles : QVector
        Is sent to super().
    """
    index = index1.row()
    # Get all names and new name
    names = [self.item(i).text() for i in range(self.count())]
    new_name = names[index]

    # Count occurrences of new name
    occurrences = names.count(new_name)

    # If new name already exists, replace with original name
    if occurrences > 1:
        self.item(index).setText(self.original_element_name)
    # Name does not already exist, update list in soi
    else:
        name = self.item(index).text()

        if ModuleType(self.type) == ModuleType.MAIN_MODULE:
            self.soi.modules[index]["meta"]["name"] = name
        elif ModuleType(self.type) == ModuleType.ATTACHMENT_MODULE:
            self.soi.attachments[index]["meta"]["name"] = name

    super().dataChanged(index1, index2, roles)
def dropEvent(self, event)

Notify parent when an element is drag-and-dropped.

Note that if the SOI is not prepared for manual priorization an error message will be displayed, and nothing else will be done. This only applies to uses of this class with non-attachment modules.

https://doc.qt.io/qt-5/qabstractitemview.html#dropEvent.

Parameters

event : QDropEvent
Is sent to super().
Expand source code
def dropEvent(self, event):
    """Notify parent when an element is drag-and-dropped.

    Note that if the SOI is not prepared for manual priorization an error
    message will be displayed, and nothing else will be done. This only
    applies to uses of this class with non-attachment modules.

    https://doc.qt.io/qt-5/qabstractitemview.html#dropEvent.

    Parameters
    ----------
    event : QDropEvent
        Is sent to super().
    """
    if (
        self.soi.algorithm_sort != "none"
        and ModuleType(self.type) == ModuleType.MAIN_MODULE
    ):
        exec_warning_dialog(
            text="SOI er ikke innstilt for manuell prioritering av "
            "moduler!",
            informative_text="Enn så lenge vil manuell prioritering av "
            "moduler bare fungere dersom SOI er innstilt til ikke å gjøre "
            "sortering av moduler før pakking. I fremtiden vil det være "
            "mulig å låse utvalgte moduler, men la resten optimalt "
            "pakkes.",
        )

    else:
        super().dropEvent(event)

        # Get origin and destination index of module/attachment
        origin = self.original_element_index
        destination = self.currentRow()

        # Update module/attachment priority (order in list):
        if ModuleType(self.type) == ModuleType.MAIN_MODULE:
            moving_module = self.soi.modules.pop(origin)
            self.soi.modules.insert(destination, moving_module)
        elif ModuleType(self.type) == ModuleType.ATTACHMENT_MODULE:
            moving_module = self.soi.attachments.pop(origin)
            self.soi.attachments.insert(destination, moving_module)

        self.soi.reorganize()

        self.original_element_index = self.currentRow()
def fill_list(self)

Fill list with elements in order defined in SOI.

Expand source code
def fill_list(self):
    """Fill list with elements in order defined in SOI."""
    # Get names of modules/attachments:
    if ModuleType(self.type) == ModuleType.MAIN_MODULE:
        names = [module["meta"]["name"] for module in self.soi.modules]
    elif ModuleType(self.type) == ModuleType.ATTACHMENT_MODULE:
        names = [
            attachment["meta"]["name"]
            for attachment in self.soi.attachments
        ]

    for i, name in enumerate(names):
        item = QListWidgetItem(name)
        item.setFlags(item.flags() | Qt.ItemIsEditable)
        self.insertItem(i, item)
def setup_list(self)

Prepare list.

Make list drag-and-droppable and remove horizontal scrollbar.

Expand source code
def setup_list(self):
    """Prepare list.

    Make list drag-and-droppable and remove horizontal scrollbar.
    """
    # Enable drag-and-drop
    self.setDragEnabled(True)
    self.viewport().setAcceptDrops(True)
    self.setDragDropMode(QAbstractItemView.InternalMove)

    # Remove horizontal scrollbar
    self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
def update_list_order(self)

Update order of modules in list to respect order in SOI.

Expand source code
def update_list_order(self):
    """Update order of modules in list to respect order in SOI."""
    self.clear()
    self.fill_list()