class TransformationLibrary(QGroupBox):
    def __init__(self, transformation_confirmation):
        super().__init__("Transformation Library")

        self.transformation_configuration = transformation_confirmation

        self.setLayout(QVBoxLayout())

        self._initialize_library()

    def _initialize_library(self):
        self.transformation_list = QListView()
        self.transformation_list.setEditTriggers(
            QAbstractItemView.NoEditTriggers)
        self.layout().addWidget(self.transformation_list)

        self.transformation_list.setModel(QStandardItemModel())

        self.transformation_list.clicked.connect(self.configure_transformation)

        # Populate transformations list
        for transformation in TRANSFORMATIONS:
            transformation_name = transformation.schema["metadata"]["name"]
            transformation_description = transformation.schema["metadata"][
                "description"]

            transformation_element = QStandardItem()
            transformation_element.setText(transformation_name)
            transformation_element.setToolTip(transformation_description)

            self.transformation_list.model().appendRow(transformation_element)

    def configure_transformation(self, x):
        """Resolve selected transformation and pass it to transformation_configuration to display config"""

        model = self.transformation_list.model()
        selected_transformation = TRANSFORMATIONS_BY_NAME[model.data(x)]
        logging.debug(f"Selected transformation: {selected_transformation}")

        self.transformation_configuration.swap_configuration(
            selected_transformation)
Beispiel #2
0
class FilePicker(QGroupBox):
    def __init__(self, files):
        super().__init__("File Picker")

        self.setLayout(QVBoxLayout())

        self.file_sequence = FileSequence([])

        self._initialize_file_list()

        self.file_sequence = FileSequence(files)
        self._update_file_picker_list([str(file) for file in files])

    def log_file_sequence_status(self):
        logging.debug(f"Current file sequence: {self.file_sequence}")

    def clear_file_list(self):
        self.file_sequence = FileSequence([])
        self.file_list.model().clear()
        self.log_file_sequence_status()

    def _initialize_file_list(self):
        self.file_list = QListView()
        self.file_list.setEditTriggers(QAbstractItemView.NoEditTriggers)
        self.layout().addWidget(self.file_list)

        self.file_list.setModel(QStandardItemModel())

        select_files = QPushButton("Select Files")
        select_files.clicked.connect(self._select_files_listener)
        self.layout().addWidget(select_files)

    def _update_file_picker_list(self, file_names):
        model = self.file_list.model()

        # Update File Picker list from files[]
        model.clear()
        for f in range(self.file_sequence.rowCount()):
            item = QStandardItem()
            item.setText(file_names[f])
            model.appendRow(item)

        self.log_file_sequence_status()

    def _select_files_listener(self):
        """Handles selection of files to rename"""

        files = QFileDialog.getOpenFileNames(self, "Select Files", ".")
        self.file_sequence = FileSequence(files[0])

        self._update_file_picker_list(files[0])
Beispiel #3
0
class ListerView(QDialog):
    def __init__(self,  title, message, items, parent=None):
        """
        Constructor of ListerView which creates a new dialog with
        scrolled items which the user can mark
        
        Args:
            title (str): The dialog title that should appear
            message (str): The message that the user will see at the top of the dialog
            items ([str]): A list of strings that will be showns as options
        """

        super(ListerView, self).__init__(parent=parent)
        form = QFormLayout(self)
        form.addRow(QLabel(message))
        self.listView = QListView(self)
        self.listView.clicked.connect(self.mouse_click_event)
        form.addRow(self.listView)
        model = QStandardItemModel(self.listView)
        self.setWindowTitle(title)
        for item in items:
            standardItem = QStandardItem(item)
            standardItem.setCheckable(True)
            standardItem.setEditable(False)
            model.appendRow(standardItem)
        self.listView.setModel(model)

    def mouse_click_event(self):
        """
        Callback method that will trigger then the user presses a mouse button
        while hovering over an item
        """

        row = [qmi.row() for qmi in self.listView.selectedIndexes()][0]
        item = self.listView.model().item(row)
        checkState = item.checkState()
        if checkState == Qt.Checked:
            checkState = Qt.Unchecked
        else:
            checkState = Qt.Checked
        item.setCheckState(checkState)

    def enable_button_box(self):
        """
        Method for enabling the buttons the bottom that correspond to OK and Cancel
        """

        form = self.layout()
        buttonBox = QDialogButtonBox(
            QDialogButtonBox.Ok | QDialogButtonBox.Cancel, Qt.Horizontal, self)
        form.addRow(buttonBox)
        buttonBox.accepted.connect(self.accept)
        buttonBox.rejected.connect(self.reject)

    def get_results(self):
        """
        Method for quering the results of the user markings
        The result is a list of strings
        """

        selected = []
        model = self.listView.model()
        i = 0
        while model.item(i):
            if model.item(i).checkState():
                selected.append(model.item(i).text())
            i += 1
        return selected
Beispiel #4
0
class PipelineEditor(QGroupBox):
    def __init__(self, file_picker):
        super().__init__("Pipeline Editor")

        self.setLayout(QVBoxLayout())

        self.file_picker = file_picker

        self.pipeline = Pipeline()
        self.pipelineView = QListView()
        self.pipelineView.setEditTriggers(QAbstractItemView.NoEditTriggers)
        self.pipelineView.setModel(QStandardItemModel())

        self.layout().addWidget(self.pipelineView)

        # === BUTTON CONTAINER ===
        button_rows = QWidget()
        self.layout().addWidget(button_rows)
        button_rows_layout = QVBoxLayout(button_rows)
        button_rows_layout.setContentsMargins(0, 0, 0, 0)

        # === ROW 1 ===
        row_1 = QWidget()
        button_rows_layout.addWidget(row_1)
        row_1_layout = QHBoxLayout(row_1)
        row_1_layout.setContentsMargins(0, 0, 0, 0)

        self.moveUpButton = QPushButton("Move Up")
        row_1_layout.addWidget(self.moveUpButton)
        self.moveUpButton.clicked.connect(self._move_up_listener)

        self.moveDownButton = QPushButton("Move Down")
        row_1_layout.addWidget(self.moveDownButton)
        self.moveDownButton.clicked.connect(self._move_down_listener)

        self.deleteButton = QPushButton("Delete")
        row_1_layout.addWidget(self.deleteButton)
        self.deleteButton.clicked.connect(self._delete_listener)

        # === ROW 2 ===
        row_2 = QWidget()
        button_rows_layout.addWidget(row_2)
        row_2_layout = QHBoxLayout(row_2)
        row_2_layout.setContentsMargins(0, 0, 0, 0)

        self.applyButton = QPushButton("Apply Pipeline")
        row_2_layout.addWidget(self.applyButton)
        self.applyButton.clicked.connect(self._apply_pipeline_listener)

        self.update_pipeline_view()

    def update_pipeline_view(self):
        logging.debug(self.pipeline)
        model = self.pipelineView.model()
        model.clear()

        for t in range(self.pipeline.rowCount()):
            item = QStandardItem()
            item.setText(repr(self.pipeline.data(t)))
            model.appendRow(item)

    def _modify_transformation_listener(self):
        # TODO
        raise NotImplementedError

    def _move_up_listener(self):
        try:
            to_move = self.pipelineView.selectionModel().selectedIndexes(
            )[0].row()
            if to_move < 1:
                return
            self.pipeline.move_transformation_up(to_move)
            self.update_pipeline_view()
            self.pipelineView.setCurrentIndex(self.pipelineView.model().index(
                to_move - 1, 0))
        except IndexError:
            return

    def _move_down_listener(self):
        try:
            to_move = self.pipelineView.selectionModel().selectedIndexes(
            )[0].row()
            if to_move > self.pipelineView.model().rowCount() - 2:
                return
            self.pipeline.move_transformation_down(to_move)
            self.update_pipeline_view()
            self.pipelineView.setCurrentIndex(self.pipelineView.model().index(
                to_move + 1, 0))
        except IndexError:
            return

    def _delete_listener(self):
        try:
            to_delete = self.pipelineView.selectionModel().selectedIndexes(
            )[0].row()
            self.pipeline.remove_transformation(to_delete)
            self.update_pipeline_view()
            if to_delete > self.pipelineView.model().rowCount() - 1:
                self.pipelineView.setCurrentIndex(
                    self.pipelineView.model().index(to_delete - 1, 0))
            else:
                self.pipelineView.setCurrentIndex(
                    self.pipelineView.model().index(to_delete, 0))
        except IndexError:
            return

    def _apply_pipeline_listener(self):
        # Check that at least one transformation has been added to the pipeline
        if self.pipeline.rowCount() == 0:
            no_transformations_messagebox = QMessageBox(self)
            no_transformations_messagebox.setText(
                "ERROR: No transformations selected")
            no_transformations_messagebox.exec_()
            return

        file_sequence = self.file_picker.file_sequence.files

        # Check that at least one file has been added to the file sequence
        if len(file_sequence) == 0:
            no_files_messagebox = QMessageBox(self)
            no_files_messagebox.setText("ERROR: No files selected")
            no_files_messagebox.exec_()
            return

        transformed_sequence = self.pipeline.resolve(file_sequence)

        before_after = list(zip(file_sequence, transformed_sequence))

        preview_text_lines = []
        for rename in before_after:
            preview_text_lines.append(f"{rename[0].name} -> {rename[1].name}")
        preview_text = "\n".join(preview_text_lines)

        confirmation = QMessageBox(self)
        confirmation.setText("Are you sure you want to apply the pipeline?")
        confirmation.setDetailedText(preview_text)
        confirmation.setStandardButtons(QMessageBox.Yes | QMessageBox.No)
        confirmation.setDefaultButton(QMessageBox.No)
        ret = confirmation.exec_()

        if ret == int(QMessageBox.Yes):
            for rename in before_after:
                from_path = rename[0]
                to_path = rename[1]

                shutil.move(str(from_path), str(to_path))
            self.file_picker.clear_file_list()