diff --git a/picard/ui/options/renaming.py b/picard/ui/options/renaming.py index bc148c31e..284715e6e 100644 --- a/picard/ui/options/renaming.py +++ b/picard/ui/options/renaming.py @@ -16,6 +16,7 @@ # Copyright (C) 2016 Suhas # Copyright (C) 2016-2017 Sambhav Kothari # Copyright (C) 2021 Gabriel Ferreira +# Copyright (C) 2021 Bob Swift # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License @@ -58,6 +59,7 @@ from picard.ui.options import ( OptionsPage, register_options_page, ) +from picard.ui.options.renaming_editor import RenamingEditorOptionsPage from picard.ui.options.scripting import ( ScriptCheckError, ScriptingDocumentationDialog, @@ -119,6 +121,7 @@ class RenamingOptionsPage(OptionsPage): ) self.ui.file_naming_format.textChanged.connect(self.check_formats) self.ui.file_naming_format_default.clicked.connect(self.set_file_naming_format_default) + self.ui.open_script_editor.clicked.connect(self.show_script_editing_page) self.ui.move_files_to_browse.clicked.connect(self.move_files_to_browse) script_edit = self.ui.file_naming_format @@ -147,6 +150,9 @@ class RenamingOptionsPage(OptionsPage): # Sync example lists vertical scrolling sync_vertical_scrollbars((self.ui.example_filename_before, self.ui.example_filename_after)) + def show_script_editing_page(self): + RenamingEditorOptionsPage.show_instance(parent=self) + def show_scripting_documentation(self): ScriptingDocumentationDialog.show_instance(parent=self) @@ -165,6 +171,7 @@ class RenamingOptionsPage(OptionsPage): active = self.ui.move_files.isChecked() or self.ui.rename_files.isChecked() self.ui.file_naming_format.setEnabled(active) self.ui.file_naming_format_default.setEnabled(active) + self.ui.open_script_editor.setEnabled(active) palette = self.script_palette_normal if active else self.script_palette_readonly self.ui.file_naming_format.setPalette(palette) diff --git a/picard/ui/options/renaming_editor.py b/picard/ui/options/renaming_editor.py new file mode 100644 index 000000000..be8257923 --- /dev/null +++ b/picard/ui/options/renaming_editor.py @@ -0,0 +1,298 @@ +# -*- coding: utf-8 -*- +# +# Picard, the next-generation MusicBrainz tagger +# +# Copyright (C) 2006-2008, 2011 Lukáš Lalinský +# Copyright (C) 2008-2009 Nikolai Prokoschenko +# Copyright (C) 2009-2010, 2014-2015, 2018-2021 Philipp Wolfer +# Copyright (C) 2011-2013 Michael Wiencek +# Copyright (C) 2011-2013 Wieland Hoffmann +# Copyright (C) 2013 Calvin Walton +# Copyright (C) 2013 Ionuț Ciocîrlan +# Copyright (C) 2013-2014 Sophist-UK +# Copyright (C) 2013-2015, 2018-2019, 2021 Laurent Monin +# Copyright (C) 2015 Alex Berman +# Copyright (C) 2015 Ohm Patel +# Copyright (C) 2016 Suhas +# Copyright (C) 2016-2017 Sambhav Kothari +# Copyright (C) 2021 Gabriel Ferreira +# Copyright (C) 2021 Bob Swift +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + +from functools import partial +import os.path + +from picard.config import ( + TextOption, + get_config, +) +from picard.const import DEFAULT_FILE_NAMING_FORMAT +from picard.file import File +from picard.script import ( + ScriptError, + ScriptParser, +) +from picard.util.settingsoverride import SettingsOverride + +from picard.ui import ( + PicardDialog, + SingletonDialog, +) +from picard.ui.options import ( + OptionsCheckError, + OptionsPage, +) +from picard.ui.options.scripting import ( + ScriptCheckError, + ScriptingDocumentationDialog, +) +from picard.ui.ui_options_renaming_editor import Ui_RenamingEditorOptionsPage + + +class RenamingEditorOptionsPage(PicardDialog, SingletonDialog): + + NAME = "filerenamingeditor" + TITLE = N_("File Naming Editor") + PARENT = None + SORT_ORDER = 40 + ACTIVE = True + HELP_URL = '/config/options_filerenaming.html' + STYLESHEET_ERROR = OptionsPage.STYLESHEET_ERROR + + options = [ + TextOption( + "setting", + "file_naming_format", + DEFAULT_FILE_NAMING_FORMAT, + ), + ] + + def __init__(self, parent=None): + super().__init__(parent) + self.ui = Ui_RenamingEditorOptionsPage() + self.ui.setupUi(self) + + self.PARENT = parent + + self.ui.file_naming_editor_save.clicked.connect(self.save_script) + self.ui.file_naming_editor_cancel.clicked.connect(self.reject) + + self.ui.file_naming_format.setEnabled(True) + self.ui.file_naming_format_default.setEnabled(True) + + self.ui.file_naming_format.textChanged.connect(self.check_formats) + self.ui.file_naming_format_default.clicked.connect(self.set_file_naming_format_default) + + self.ui.scripting_documentation_button.clicked.connect(self.show_scripting_documentation) + self.ui.example_filename_sample_files_button.clicked.connect(self._sample_example_files) + self._sampled_example_files = [] + + # Sync example lists vertical scrolling + def sync_vertical_scrollbars(widgets): + """Sync position of vertical scrollbars for listed widgets""" + def _sync_scrollbar_vert(widget, value): + widget.blockSignals(True) + widget.verticalScrollBar().setValue(value) + widget.blockSignals(False) + + widgets = set(widgets) + for widget in widgets: + for other in widgets - {widget}: + widget.verticalScrollBar().valueChanged.connect( + partial(_sync_scrollbar_vert, other)) + + # Sync example lists vertical scrolling + sync_vertical_scrollbars((self.ui.example_filename_before, self.ui.example_filename_after)) + + self.load() + + def save_script(self): + self.PARENT.ui.file_naming_format.setPlainText(self.ui.file_naming_format.toPlainText()) + self.accept() + + def show_scripting_documentation(self): + ScriptingDocumentationDialog.show_instance(parent=self) + + def check_formats(self): + self.test() + self.update_examples() + + def _example_to_filename(self, file): + config = get_config() + settings = SettingsOverride(config.setting, { + 'ascii_filenames': self.PARENT.ui.ascii_filenames.isChecked(), + 'file_naming_format': self.ui.file_naming_format.toPlainText(), + 'move_files': self.PARENT.ui.move_files.isChecked(), + 'move_files_to': os.path.normpath(self.PARENT.ui.move_files_to.text()), + 'rename_files': self.PARENT.ui.rename_files.isChecked(), + 'windows_compatibility': self.PARENT.ui.windows_compatibility.isChecked(), + }) + + try: + if config.setting["enable_tagger_scripts"]: + for s_pos, s_name, s_enabled, s_text in config.setting["list_of_scripts"]: + if s_enabled and s_text: + parser = ScriptParser() + parser.eval(s_text, file.metadata) + filename_before = file.filename + filename_after = file.make_filename(filename_before, file.metadata, settings) + if not settings["move_files"]: + return os.path.basename(filename_before), os.path.basename(filename_after) + return filename_before, filename_after + except ScriptError: + return "", "" + except TypeError: + return "", "" + + def _sample_example_files(self): + # Get a new sample of randomly selected /loaded files to use as renaming examples + import random + max_samples = 10 # pick up to 10 samples + if self.tagger.window.selected_objects: + # If files/albums/tracks are selected, sample example files from them + files = self.tagger.get_files_from_objects(self.tagger.window.selected_objects) + length = min(max_samples, len(files)) + files = [file for file in random.sample(files, k=length)] + else: + # If files/albums/tracks are not selected, sample example files from the pool of loaded files + files = self.tagger.files + length = min(max_samples, len(files)) + files = [files[key] for key in random.sample(files.keys(), k=length)] + + if not files: + # If no file has been loaded, use generic examples + files = [self.example_1(), self.example_2()] + self._sampled_example_files = files + self.update_examples() + + def update_examples(self): + self.ui.example_filename_before.clear() + self.ui.example_filename_after.clear() + + if not self._sampled_example_files: + self._sample_example_files() + example_files = self._sampled_example_files + + examples = [self._example_to_filename(example) for example in example_files] + for before, after in sorted(examples, key=lambda x: x[1]): + self.ui.example_filename_before.addItem(before) + self.ui.example_filename_after.addItem(after) + + def load(self): + self.ui.file_naming_format.setPlainText(self.PARENT.ui.file_naming_format.toPlainText()) + self.update_examples() + + def check(self): + self.check_format() + if self.PARENT.ui.move_files.isChecked() and not self.PARENT.ui.move_files_to.text().strip(): + raise OptionsCheckError(_("Error"), _("The location to move files to must not be empty.")) + + def check_format(self): + parser = ScriptParser() + try: + parser.eval(self.ui.file_naming_format.toPlainText()) + except Exception as e: + raise ScriptCheckError("", str(e)) + if self.PARENT.ui.rename_files.isChecked(): + if not self.ui.file_naming_format.toPlainText().strip(): + raise ScriptCheckError("", _("The file naming format must not be empty.")) + + # def save(self): + # self.PARENT.ui.file_naming_format.setPlainText(self.ui.file_naming_format.toPlainText()) + + def display_error(self, error): + # Ignore scripting errors, those are handled inline + if not isinstance(error, ScriptCheckError): + super().display_error(error) + + def set_file_naming_format_default(self): + self.ui.file_naming_format.setText(self.options[0].default) +# self.ui.file_naming_format.setCursorPosition(0) + + def example_1(self): + file = File("ticket_to_ride.mp3") + file.state = File.NORMAL + file.metadata['album'] = 'Help!' + file.metadata['title'] = 'Ticket to Ride' + file.metadata['~releasecomment'] = '2014 mono remaster' + file.metadata['artist'] = 'The Beatles' + file.metadata['artistsort'] = 'Beatles, The' + file.metadata['albumartist'] = 'The Beatles' + file.metadata['albumartistsort'] = 'Beatles, The' + file.metadata['tracknumber'] = '7' + file.metadata['totaltracks'] = '14' + file.metadata['discnumber'] = '1' + file.metadata['totaldiscs'] = '1' + file.metadata['originaldate'] = '1965-08-06' + file.metadata['originalyear'] = '1965' + file.metadata['date'] = '2014-09-08' + file.metadata['releasetype'] = ['album', 'soundtrack'] + file.metadata['~primaryreleasetype'] = ['album'] + file.metadata['~secondaryreleasetype'] = ['soundtrack'] + file.metadata['releasestatus'] = 'official' + file.metadata['releasecountry'] = 'US' + file.metadata['~extension'] = 'mp3' + file.metadata['musicbrainz_albumid'] = 'd7fbbb0a-1348-40ad-8eef-cd438d4cd203' + file.metadata['musicbrainz_albumartistid'] = 'b10bbbfc-cf9e-42e0-be17-e2c3e1d2600d' + file.metadata['musicbrainz_artistid'] = 'b10bbbfc-cf9e-42e0-be17-e2c3e1d2600d' + file.metadata['musicbrainz_recordingid'] = 'ed052ae1-c950-47f2-8d2b-46e1b58ab76c' + file.metadata['musicbrainz_releasetrackid'] = '392639f5-5629-477e-b04b-93bffa703405' + return file + + def example_2(self): + config = get_config() + file = File("track05.mp3") + file.state = File.NORMAL + file.metadata['album'] = "Coup d'État, Volume 1: Ku De Ta / Prologue" + file.metadata['title'] = "I've Got to Learn the Mambo" + file.metadata['artist'] = "Snowboy feat. James Hunter" + file.metadata['artistsort'] = "Snowboy feat. Hunter, James" + file.metadata['albumartist'] = config.setting['va_name'] + file.metadata['albumartistsort'] = config.setting['va_name'] + file.metadata['tracknumber'] = '5' + file.metadata['totaltracks'] = '13' + file.metadata['discnumber'] = '2' + file.metadata['totaldiscs'] = '2' + file.metadata['discsubtitle'] = "Beat Up" + file.metadata['originaldate'] = '2005-07-04' + file.metadata['originalyear'] = '2005' + file.metadata['date'] = '2005-07-04' + file.metadata['releasetype'] = ['album', 'compilation'] + file.metadata['~primaryreleasetype'] = 'album' + file.metadata['~secondaryreleasetype'] = 'compilation' + file.metadata['releasestatus'] = 'official' + file.metadata['releasecountry'] = 'AU' + file.metadata['compilation'] = '1' + file.metadata['~multiartist'] = '1' + file.metadata['~extension'] = 'mp3' + file.metadata['musicbrainz_albumid'] = '4b50c71e-0a07-46ac-82e4-cb85dc0c9bdd' + file.metadata['musicbrainz_recordingid'] = 'b3c487cb-0e55-477d-8df3-01ec6590f099' + file.metadata['musicbrainz_releasetrackid'] = 'f8649a05-da39-39ba-957c-7abf8f9012be' + file.metadata['musicbrainz_albumartistid'] = '89ad4ac3-39f7-470e-963a-56509c546377' + file.metadata['musicbrainz_artistid'] = ['7b593455-d207-482c-8c6f-19ce22c94679', + '9e082466-2390-40d1-891e-4803531f43fd'] + return file + + def test(self): + self.ui.renaming_error.setStyleSheet("") + self.ui.renaming_error.setText("") + try: + self.check_format() + except ScriptCheckError as e: + self.ui.renaming_error.setStyleSheet(self.STYLESHEET_ERROR) + self.ui.renaming_error.setText(e.info) + return diff --git a/picard/ui/ui_options_renaming.py b/picard/ui/ui_options_renaming.py index bf0129fe0..4dda042fe 100644 --- a/picard/ui/ui_options_renaming.py +++ b/picard/ui/ui_options_renaming.py @@ -88,13 +88,6 @@ class Ui_RenamingOptionsPage(object): self.example_filename_sample_files_button = QtWidgets.QPushButton(RenamingOptionsPage) self.example_filename_sample_files_button.setObjectName("example_filename_sample_files_button") self.horizontalLayout.addWidget(self.example_filename_sample_files_button) - spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) - self.horizontalLayout.addItem(spacerItem) - self.scripting_documentation_button = QtWidgets.QPushButton(RenamingOptionsPage) - self.scripting_documentation_button.setObjectName("scripting_documentation_button") - self.horizontalLayout.addWidget(self.scripting_documentation_button) - spacerItem1 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) - self.horizontalLayout.addItem(spacerItem1) self.file_naming_format_default = QtWidgets.QPushButton(RenamingOptionsPage) sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed) sizePolicy.setHorizontalStretch(0) @@ -104,6 +97,16 @@ class Ui_RenamingOptionsPage(object): self.file_naming_format_default.setMinimumSize(QtCore.QSize(0, 0)) self.file_naming_format_default.setObjectName("file_naming_format_default") self.horizontalLayout.addWidget(self.file_naming_format_default) + spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + self.horizontalLayout.addItem(spacerItem) + self.scripting_documentation_button = QtWidgets.QPushButton(RenamingOptionsPage) + self.scripting_documentation_button.setObjectName("scripting_documentation_button") + self.horizontalLayout.addWidget(self.scripting_documentation_button) + spacerItem1 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + self.horizontalLayout.addItem(spacerItem1) + self.open_script_editor = QtWidgets.QPushButton(RenamingOptionsPage) + self.open_script_editor.setObjectName("open_script_editor") + self.horizontalLayout.addWidget(self.open_script_editor) self.verticalLayout_5.addLayout(self.horizontalLayout) self.renaming_error = QtWidgets.QLabel(RenamingOptionsPage) self.renaming_error.setText("") @@ -142,7 +145,6 @@ class Ui_RenamingOptionsPage(object): RenamingOptionsPage.setTabOrder(self.move_files_to_browse, self.move_additional_files) RenamingOptionsPage.setTabOrder(self.move_additional_files, self.move_additional_files_pattern) RenamingOptionsPage.setTabOrder(self.move_additional_files_pattern, self.delete_empty_dirs) - RenamingOptionsPage.setTabOrder(self.delete_empty_dirs, self.file_naming_format_default) def retranslateUi(self, RenamingOptionsPage): _translate = QtCore.QCoreApplication.translate @@ -156,8 +158,9 @@ class Ui_RenamingOptionsPage(object): self.windows_compatibility.setText(_("Windows compatibility")) self.file_naming_format_label.setText(_("Name files like this")) self.example_filename_sample_files_button.setText(_("Renew examples")) - self.scripting_documentation_button.setText(_("Scripting Documentation")) self.file_naming_format_default.setText(_("Default")) + self.scripting_documentation_button.setText(_("Scripting Documentation")) + self.open_script_editor.setText(_("Script Editor")) self.groupBox.setTitle(_("Examples")) self.example_filename_before_label.setText(_("Before")) self.example_filename_after_label.setText(_("After")) diff --git a/picard/ui/ui_options_renaming_editor.py b/picard/ui/ui_options_renaming_editor.py new file mode 100644 index 000000000..e4f39a026 --- /dev/null +++ b/picard/ui/ui_options_renaming_editor.py @@ -0,0 +1,143 @@ +# -*- coding: utf-8 -*- + +# Automatically generated - don't edit. +# Use `python setup.py build_ui` to update it. + + +from PyQt5 import QtCore, QtGui, QtWidgets + + +class Ui_RenamingEditorOptionsPage(object): + def setupUi(self, RenamingEditorOptionsPage): + RenamingEditorOptionsPage.setObjectName("RenamingEditorOptionsPage") + RenamingEditorOptionsPage.setWindowModality(QtCore.Qt.WindowModal) + RenamingEditorOptionsPage.setEnabled(True) + RenamingEditorOptionsPage.resize(453, 552) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Preferred) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(RenamingEditorOptionsPage.sizePolicy().hasHeightForWidth()) + RenamingEditorOptionsPage.setSizePolicy(sizePolicy) + self.verticalLayout_5 = QtWidgets.QVBoxLayout(RenamingEditorOptionsPage) + self.verticalLayout_5.setObjectName("verticalLayout_5") + self.verticalLayout_2 = QtWidgets.QVBoxLayout() + self.verticalLayout_2.setContentsMargins(-1, 0, -1, 0) + self.verticalLayout_2.setObjectName("verticalLayout_2") + self.file_naming_format_label = QtWidgets.QLabel(RenamingEditorOptionsPage) + self.file_naming_format_label.setObjectName("file_naming_format_label") + self.verticalLayout_2.addWidget(self.file_naming_format_label) + self.frame = QtWidgets.QFrame(RenamingEditorOptionsPage) + self.frame.setMinimumSize(QtCore.QSize(0, 20)) + self.frame.setFrameShape(QtWidgets.QFrame.NoFrame) + self.frame.setFrameShadow(QtWidgets.QFrame.Raised) + self.frame.setLineWidth(0) + self.frame.setObjectName("frame") + self.verticalLayout_3 = QtWidgets.QVBoxLayout(self.frame) + self.verticalLayout_3.setContentsMargins(0, 0, 0, 0) + self.verticalLayout_3.setObjectName("verticalLayout_3") + self.splitter = QtWidgets.QSplitter(self.frame) + self.splitter.setOrientation(QtCore.Qt.Vertical) + self.splitter.setObjectName("splitter") + self.file_naming_format = ScriptTextEdit(self.splitter) + self.file_naming_format.setEnabled(False) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.MinimumExpanding) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.file_naming_format.sizePolicy().hasHeightForWidth()) + self.file_naming_format.setSizePolicy(sizePolicy) + self.file_naming_format.setMinimumSize(QtCore.QSize(0, 250)) + self.file_naming_format.viewport().setProperty("cursor", QtGui.QCursor(QtCore.Qt.IBeamCursor)) + self.file_naming_format.setTabChangesFocus(False) + self.file_naming_format.setLineWrapMode(QtWidgets.QTextEdit.NoWrap) + self.file_naming_format.setTabStopWidth(20) + self.file_naming_format.setAcceptRichText(False) + self.file_naming_format.setTextInteractionFlags(QtCore.Qt.TextEditorInteraction) + self.file_naming_format.setObjectName("file_naming_format") + self.groupBox = QtWidgets.QGroupBox(self.splitter) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Expanding) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.groupBox.sizePolicy().hasHeightForWidth()) + self.groupBox.setSizePolicy(sizePolicy) + self.groupBox.setMinimumSize(QtCore.QSize(0, 150)) + self.groupBox.setObjectName("groupBox") + self.verticalLayout_4 = QtWidgets.QVBoxLayout(self.groupBox) + self.verticalLayout_4.setContentsMargins(-1, 6, -1, 0) + self.verticalLayout_4.setObjectName("verticalLayout_4") + self.horizontalLayout_3 = QtWidgets.QHBoxLayout() + self.horizontalLayout_3.setObjectName("horizontalLayout_3") + self.example_filename_before_label = QtWidgets.QLabel(self.groupBox) + self.example_filename_before_label.setObjectName("example_filename_before_label") + self.horizontalLayout_3.addWidget(self.example_filename_before_label) + self.example_filename_after_label = QtWidgets.QLabel(self.groupBox) + self.example_filename_after_label.setObjectName("example_filename_after_label") + self.horizontalLayout_3.addWidget(self.example_filename_after_label) + self.verticalLayout_4.addLayout(self.horizontalLayout_3) + self.horizontalLayout_2 = QtWidgets.QHBoxLayout() + self.horizontalLayout_2.setObjectName("horizontalLayout_2") + self.example_filename_before = QtWidgets.QListWidget(self.groupBox) + self.example_filename_before.setObjectName("example_filename_before") + self.horizontalLayout_2.addWidget(self.example_filename_before) + self.example_filename_after = QtWidgets.QListWidget(self.groupBox) + self.example_filename_after.setObjectName("example_filename_after") + self.horizontalLayout_2.addWidget(self.example_filename_after) + self.verticalLayout_4.addLayout(self.horizontalLayout_2) + self.horizontalLayout = QtWidgets.QHBoxLayout() + self.horizontalLayout.setSpacing(2) + self.horizontalLayout.setObjectName("horizontalLayout") + self.example_filename_sample_files_button = QtWidgets.QPushButton(self.groupBox) + self.example_filename_sample_files_button.setObjectName("example_filename_sample_files_button") + self.horizontalLayout.addWidget(self.example_filename_sample_files_button) + spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + self.horizontalLayout.addItem(spacerItem) + self.scripting_documentation_button = QtWidgets.QPushButton(self.groupBox) + self.scripting_documentation_button.setObjectName("scripting_documentation_button") + self.horizontalLayout.addWidget(self.scripting_documentation_button) + spacerItem1 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + self.horizontalLayout.addItem(spacerItem1) + self.renaming_error = QtWidgets.QLabel(self.groupBox) + self.renaming_error.setText("") + self.renaming_error.setAlignment(QtCore.Qt.AlignCenter) + self.renaming_error.setObjectName("renaming_error") + self.horizontalLayout.addWidget(self.renaming_error) + self.file_naming_format_default = QtWidgets.QPushButton(self.groupBox) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.file_naming_format_default.sizePolicy().hasHeightForWidth()) + self.file_naming_format_default.setSizePolicy(sizePolicy) + self.file_naming_format_default.setMinimumSize(QtCore.QSize(0, 0)) + self.file_naming_format_default.setObjectName("file_naming_format_default") + self.horizontalLayout.addWidget(self.file_naming_format_default) + self.verticalLayout_4.addLayout(self.horizontalLayout) + self.verticalLayout_3.addWidget(self.splitter) + self.verticalLayout_2.addWidget(self.frame) + self.verticalLayout_5.addLayout(self.verticalLayout_2) + self.horizontalLayout_4 = QtWidgets.QHBoxLayout() + self.horizontalLayout_4.setContentsMargins(-1, 0, -1, -1) + self.horizontalLayout_4.setObjectName("horizontalLayout_4") + spacerItem2 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + self.horizontalLayout_4.addItem(spacerItem2) + self.file_naming_editor_cancel = QtWidgets.QPushButton(RenamingEditorOptionsPage) + self.file_naming_editor_cancel.setObjectName("file_naming_editor_cancel") + self.horizontalLayout_4.addWidget(self.file_naming_editor_cancel) + self.file_naming_editor_save = QtWidgets.QPushButton(RenamingEditorOptionsPage) + self.file_naming_editor_save.setObjectName("file_naming_editor_save") + self.horizontalLayout_4.addWidget(self.file_naming_editor_save) + self.verticalLayout_5.addLayout(self.horizontalLayout_4) + + self.retranslateUi(RenamingEditorOptionsPage) + QtCore.QMetaObject.connectSlotsByName(RenamingEditorOptionsPage) + + def retranslateUi(self, RenamingEditorOptionsPage): + _translate = QtCore.QCoreApplication.translate + self.file_naming_format_label.setText(_("Name files like this")) + self.groupBox.setTitle(_("Examples")) + self.example_filename_before_label.setText(_("Before")) + self.example_filename_after_label.setText(_("After")) + self.example_filename_sample_files_button.setText(_("Renew examples")) + self.scripting_documentation_button.setText(_("Scripting Documentation")) + self.file_naming_format_default.setText(_("Default")) + self.file_naming_editor_cancel.setText(_("Cancel")) + self.file_naming_editor_save.setText(_("Save")) +from picard.ui.widgets.scripttextedit import ScriptTextEdit diff --git a/ui/options_renaming.ui b/ui/options_renaming.ui index 6ce6280f5..a8280ce80 100644 --- a/ui/options_renaming.ui +++ b/ui/options_renaming.ui @@ -173,6 +173,25 @@ + + + + + 0 + 0 + + + + + 0 + 0 + + + + Default + + + @@ -207,21 +226,9 @@ - - - - 0 - 0 - - - - - 0 - 0 - - + - Default + Script Editor @@ -302,7 +309,6 @@ move_additional_files move_additional_files_pattern delete_empty_dirs - file_naming_format_default diff --git a/ui/options_renaming_editor.ui b/ui/options_renaming_editor.ui new file mode 100644 index 000000000..d869972d0 --- /dev/null +++ b/ui/options_renaming_editor.ui @@ -0,0 +1,295 @@ + + + RenamingEditorOptionsPage + + + Qt::WindowModal + + + true + + + + 0 + 0 + 453 + 552 + + + + + 0 + 0 + + + + + + + 0 + + + 0 + + + + + Name files like this + + + + + + + + 0 + 20 + + + + QFrame::NoFrame + + + QFrame::Raised + + + 0 + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Qt::Vertical + + + + false + + + + 0 + 0 + + + + + 0 + 250 + + + + IBeamCursor + + + false + + + QTextEdit::NoWrap + + + 20 + + + false + + + Qt::TextEditorInteraction + + + + + + 0 + 0 + + + + + 0 + 150 + + + + Examples + + + + 6 + + + 0 + + + + + + + Before + + + + + + + After + + + + + + + + + + + + + + + + + + + 2 + + + + + Renew examples + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Scripting Documentation + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + Qt::AlignCenter + + + + + + + + 0 + 0 + + + + + 0 + 0 + + + + Default + + + + + + + + + + + + + + + + + + 0 + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Cancel + + + + + + + Save + + + + + + + + + + ScriptTextEdit + QTextEdit +
picard.ui.widgets.scripttextedit
+
+
+ + file_naming_format_default + + + +