Esempio n. 1
0
class MainWindow(QDialog, SetupTabStopsMixin, CenterOnScreenMixin):
    WINDOW_TITLE_TEXT = 'BAON'
    OPTIONS_BOX_TEXT = 'Options'
    SCAN_RECURSIVE_CHECKBOX_TEXT = 'Recursively scan subfolders'
    USE_PATH_CHECKBOX_TEXT = 'Use path'
    USE_EXTENSION_CHECKBOX_TEXT = 'Use extension'
    RULES_BOX_TEXT = 'Rename Rules'
    FILES_BOX_TEXT = 'Renamed Files'

    RENAME_WARNINGS_DIALOG_CAPTION = 'Please Confirm'
    RENAME_WARNINGS_DIALOG_TEXT = 'There are warnings for some of the files. Proceed with the rename operation anyway?'

    RENAME_COMPLETE_DIALOG_CAPTION = 'Rename Complete'
    RENAME_COMPLETE_DIALOG_TEXT =\
        'The files have been renamed successfully. Do you wish to perform another rename operation?'

    DEFAULT_WINDOW_WIDTH = 800
    DEFAULT_WINDOW_HEIGHT = 600
    RULES_BOX_HEIGHT = 112

    base_path_edited = pyqtSignal(str)
    scan_recursive_changed = pyqtSignal(bool)
    rules_text_changed = pyqtSignal(str)
    use_path_changed = pyqtSignal(bool)
    use_extension_changed = pyqtSignal(bool)

    request_add_override = pyqtSignal(BAONPath, BAONPath)
    request_remove_override = pyqtSignal(BAONPath)

    request_do_rename = pyqtSignal()

    request_rescan = pyqtSignal()

    _base_path_panel = None
    _scan_recursive_checkbox = None
    _use_path_checkbox = None
    _use_extension_checkbox = None
    _rules_editor = None
    _files_display = None
    _files_display_summary_panel = None
    _status_box = None
    _dialog_button_box = None

    def __init__(self, args):
        super().__init__()

        self._init_ui()
        self._fill_in_controls(args)
        self._center_on_screen()

    def _init_ui(self):
        self.setWindowTitle(self.WINDOW_TITLE_TEXT)
        self.resize(self.DEFAULT_WINDOW_WIDTH, self.DEFAULT_WINDOW_HEIGHT)

        main_layout = QVBoxLayout(self)
        main_layout.addWidget(self._create_base_path_panel())
        main_layout.addWidget(self._create_options_box())
        main_layout.addWidget(self._create_rules_box())
        main_layout.addWidget(self._create_files_box())
        main_layout.addWidget(self._create_status_box())
        main_layout.addWidget(self._create_dialog_buttons())

        self._setup_tab_stops(
            self._base_path_panel,
            self._scan_recursive_checkbox,
            self._use_path_checkbox,
            self._use_extension_checkbox,
            self._rules_editor,
            self._files_display,
            self._files_display_summary,
            self._dialog_button_box,
        )

    def _create_base_path_panel(self):
        self._base_path_panel = BasePathPanel(self)
        self._base_path_panel.path_edited.connect(self.base_path_edited)

        return self._base_path_panel

    def _create_options_box(self):
        box = QGroupBox(self.OPTIONS_BOX_TEXT, self)

        self._scan_recursive_checkbox = QCheckBox(self.SCAN_RECURSIVE_CHECKBOX_TEXT, box)
        self._scan_recursive_checkbox.toggled.connect(self.scan_recursive_changed)

        self._use_path_checkbox = QCheckBox(self.USE_PATH_CHECKBOX_TEXT, box)
        self._use_path_checkbox.toggled.connect(self.use_path_changed)

        self._use_extension_checkbox = QCheckBox(self.USE_EXTENSION_CHECKBOX_TEXT, box)
        self._use_extension_checkbox.toggled.connect(self.use_extension_changed)

        layout = QHBoxLayout(box)
        layout.addWidget(self._scan_recursive_checkbox)
        layout.addWidget(self._use_path_checkbox)
        layout.addWidget(self._use_extension_checkbox)
        layout.addStretch()

        return box

    def _create_rules_box(self):
        box = QGroupBox(self.RULES_BOX_TEXT, self)
        box.setMaximumHeight(self.RULES_BOX_HEIGHT)

        self._rules_editor = RulesEditor(box)
        self._rules_editor.rules_edited.connect(self.rules_text_changed)

        layout = QHBoxLayout(box)
        layout.addWidget(self._rules_editor)

        return box

    def _create_files_box(self):
        box = QGroupBox(self.FILES_BOX_TEXT, self)
        box.setSizePolicy(QSizePolicy(QSizePolicy.Preferred, QSizePolicy.Expanding))

        self._files_display = FilesDisplay(box)
        self._files_display_summary = FilesDisplaySummaryPanel(box)

        self._files_display.request_add_override.connect(self.request_add_override)
        self._files_display.request_remove_override.connect(self.request_remove_override)

        self._files_display.counts_changed.connect(self._files_display_summary.set_counts)
        self._files_display.is_browsing_category_changed.connect(self._files_display_summary.set_is_browsing_category)
        self._files_display.has_next_in_category_changed.connect(self._files_display_summary.set_has_next_in_category)
        self._files_display.has_prev_in_category_changed.connect(self._files_display_summary.set_has_prev_in_category)

        self._files_display_summary.start_browsing_category.connect(self._files_display.start_browsing_category)
        self._files_display_summary.next_in_category.connect(self._files_display.next_in_category)
        self._files_display_summary.prev_in_category.connect(self._files_display.prev_in_category)

        layout = QVBoxLayout(box)
        layout.addWidget(self._files_display)
        layout.addWidget(self._files_display_summary)

        return box

    def _create_status_box(self):
        self._status_box = StatusBox(self)

        return self._status_box

    def _create_dialog_buttons(self):
        self._dialog_button_box = QDialogButtonBox(self)
        self._dialog_button_box.setOrientation(Qt.Horizontal)
        self._dialog_button_box.setStandardButtons(QDialogButtonBox.Cancel | QDialogButtonBox.Ok)
        self._dialog_button_box.setCenterButtons(True)

        self._dialog_button_box.accepted.connect(self._confirm_rename)
        self._dialog_button_box.rejected.connect(self.reject)

        return self._dialog_button_box

    def _fill_in_controls(self, args):
        if args.base_path is not None:
            self._base_path_panel.set_base_path(args.base_path)
        if args.scan_recursive is not None:
            self._scan_recursive_checkbox.setChecked(args.scan_recursive)
        if args.use_extension is not None:
            self._use_extension_checkbox.setChecked(args.use_extension)
        if args.use_path is not None:
            self._use_path_checkbox.setChecked(args.use_path)
        if args.rules_text is not None:
            self._rules_editor.set_rules(args.rules_text)

    @pyqtSlot()
    def show_first_time(self):
        self.show()
        self.raise_()

        # We need to do this here as otherwise the operation may fail on some platforms
        self.setWindowIcon(QIcon(':/app_icon.png'))

    @pyqtSlot(str)
    def set_base_path(self, base_path):
        self._base_path_panel.set_base_path(base_path)

    @pyqtSlot(BAONStatus)
    def report_status(self, status):
        files_busy = \
            status.scan_status in [BAONStatus.IN_PROGRESS, BAONStatus.PENDING] or \
            status.rename_status in [BAONStatus.IN_PROGRESS, BAONStatus.PENDING]

        self._files_display.setEnabled(not files_busy)

        if status.rules_status == BAONStatus.ERROR:
            self._rules_editor.show_error(status.rules_status_extra.source_span)
        else:
            self._rules_editor.clear_error()

        self._status_box.show_status(status)

        self._dialog_button_box.button(QDialogButtonBox.Ok).setEnabled(
            status.execute_status in [BAONStatus.WAITING_FOR_USER, BAONStatus.ERROR]
        )

        if status.execute_status == BAONStatus.AVAILABLE:
            self._on_rename_completed()

    @pyqtSlot(list)
    def update_scanned_files(self, files):
        self._files_display.set_original_files(files)

    @pyqtSlot(list)
    def update_renamed_files(self, files):
        self._files_display.set_renamed_files(files)

    @pyqtSlot()
    def _confirm_rename(self):
        if self._files_display.has_rename_warnings():
            if not self._ask_user(self.RENAME_WARNINGS_DIALOG_CAPTION, self.RENAME_WARNINGS_DIALOG_TEXT):
                return

        self.request_do_rename.emit()

    def _on_rename_completed(self):
        self._rules_editor.clear()
        self.request_rescan.emit()

        if self._ask_user(self.RENAME_COMPLETE_DIALOG_CAPTION, self.RENAME_COMPLETE_DIALOG_TEXT):
            pass
        else:
            self.reject()

    def _ask_user(self, caption, text):
        on_mac = platform.system() == 'Darwin'

        dialog = QMessageBox(
            QMessageBox.Question,
            caption,
            text,
            QMessageBox.Yes | QMessageBox.No,
            self,
            Qt.Sheet if on_mac else Qt.Dialog | Qt.MSWindowsFixedSizeDialogHint,
        )
        dialog.setDefaultButton(QMessageBox.No)
        dialog.setWindowModality(Qt.WindowModal)

        return dialog.exec_() == QMessageBox.Yes
Esempio n. 2
0
    def _create_base_path_panel(self):
        self._base_path_panel = BasePathPanel(self)
        self._base_path_panel.path_edited.connect(self.base_path_edited)

        return self._base_path_panel