mirror of
https://github.com/fergalmoran/picard.git
synced 2025-12-26 19:29:01 +00:00
PICARD-356: Allow user defined replacements for Windows incompatible characters
This commit is contained in:
@@ -32,24 +32,29 @@
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
import re
|
||||
|
||||
from PyQt5 import (
|
||||
QtCore,
|
||||
QtGui,
|
||||
QtWidgets,
|
||||
)
|
||||
|
||||
from picard.config import (
|
||||
BoolOption,
|
||||
Option,
|
||||
get_config,
|
||||
)
|
||||
from picard.const.sys import IS_WIN
|
||||
from picard.util import system_supports_long_paths
|
||||
|
||||
from picard.ui import PicardDialog
|
||||
from picard.ui.options import (
|
||||
OptionsPage,
|
||||
register_options_page,
|
||||
)
|
||||
from picard.ui.ui_options_renaming_compat import Ui_RenamingCompatOptionsPage
|
||||
from picard.ui.ui_win_compat_dialog import Ui_WinCompatDialog
|
||||
|
||||
|
||||
class RenamingCompatOptionsPage(OptionsPage):
|
||||
@@ -65,21 +70,34 @@ class RenamingCompatOptionsPage(OptionsPage):
|
||||
BoolOption("setting", "windows_long_paths", system_supports_long_paths() if IS_WIN else False),
|
||||
BoolOption("setting", "ascii_filenames", False),
|
||||
BoolOption("setting", "replace_spaces_with_underscores", False),
|
||||
Option("setting", "win_compat_replacements", {
|
||||
'*': '_',
|
||||
':': '_',
|
||||
'<': '_',
|
||||
'>': '_',
|
||||
'?': '_',
|
||||
'|': '_',
|
||||
'"': '_',
|
||||
})
|
||||
]
|
||||
|
||||
options_changed = QtCore.pyqtSignal(dict)
|
||||
|
||||
def __init__(self, parent=None):
|
||||
super().__init__(parent)
|
||||
config = get_config()
|
||||
self.win_compat_replacements = config.setting["win_compat_replacements"]
|
||||
self.ui = Ui_RenamingCompatOptionsPage()
|
||||
self.ui.setupUi(self)
|
||||
self.ui.ascii_filenames.toggled.connect(self.on_options_changed)
|
||||
self.ui.windows_compatibility.toggled.connect(self.on_options_changed)
|
||||
self.ui.windows_long_paths.toggled.connect(self.on_options_changed)
|
||||
self.ui.replace_spaces_with_underscores.toggled.connect(self.on_options_changed)
|
||||
self.ui.btn_windows_compatibility_change.clicked.connect(self.open_win_compat_dialog)
|
||||
|
||||
def load(self):
|
||||
config = get_config()
|
||||
self.win_compat_replacements = config.setting["win_compat_replacements"]
|
||||
try:
|
||||
self.ui.windows_long_paths.toggled.disconnect(self.toggle_windows_long_paths)
|
||||
except TypeError:
|
||||
@@ -123,7 +141,62 @@ class RenamingCompatOptionsPage(OptionsPage):
|
||||
'windows_compatibility': self.ui.windows_compatibility.isChecked(),
|
||||
'windows_long_paths': self.ui.windows_long_paths.isChecked(),
|
||||
'replace_spaces_with_underscores': self.ui.replace_spaces_with_underscores.isChecked(),
|
||||
'win_compat_replacements': self.win_compat_replacements,
|
||||
}
|
||||
|
||||
def open_win_compat_dialog(self):
|
||||
dialog = WinCompatDialog(self.win_compat_replacements, parent=self)
|
||||
if dialog.exec_() == QtWidgets.QDialog.DialogCode.Accepted:
|
||||
self.win_compat_replacements = dialog.replacements
|
||||
self.on_options_changed()
|
||||
|
||||
|
||||
class WinCompatReplacementValidator(QtGui.QValidator):
|
||||
_re_valid_win_replacement = re.compile(r'^[^"*:<>?|/\\\s]?$')
|
||||
|
||||
def validate(self, text: str, pos):
|
||||
if self._re_valid_win_replacement.match(text):
|
||||
state = QtGui.QValidator.State.Acceptable
|
||||
else:
|
||||
state = QtGui.QValidator.State.Invalid
|
||||
return state, text, pos
|
||||
|
||||
|
||||
class WinCompatDialog(PicardDialog):
|
||||
def __init__(self, replacements, parent=None):
|
||||
super().__init__(parent)
|
||||
self.replacements = dict(replacements)
|
||||
self.ui = Ui_WinCompatDialog()
|
||||
self.ui.setupUi(self)
|
||||
self.ui.replace_asterisk.setValidator(WinCompatReplacementValidator())
|
||||
self.ui.replace_colon.setValidator(WinCompatReplacementValidator())
|
||||
self.ui.replace_gt.setValidator(WinCompatReplacementValidator())
|
||||
self.ui.replace_lt.setValidator(WinCompatReplacementValidator())
|
||||
self.ui.replace_pipe.setValidator(WinCompatReplacementValidator())
|
||||
self.ui.replace_questionmark.setValidator(WinCompatReplacementValidator())
|
||||
self.ui.replace_quotationmark.setValidator(WinCompatReplacementValidator())
|
||||
self.ui.buttonbox.accepted.connect(self.accept)
|
||||
self.ui.buttonbox.rejected.connect(self.reject)
|
||||
self.load()
|
||||
|
||||
def load(self):
|
||||
self.ui.replace_asterisk.setText(self.replacements['*'])
|
||||
self.ui.replace_colon.setText(self.replacements[':'])
|
||||
self.ui.replace_gt.setText(self.replacements['>'])
|
||||
self.ui.replace_lt.setText(self.replacements['<'])
|
||||
self.ui.replace_pipe.setText(self.replacements['|'])
|
||||
self.ui.replace_questionmark.setText(self.replacements['?'])
|
||||
self.ui.replace_quotationmark.setText(self.replacements['"'])
|
||||
|
||||
def accept(self):
|
||||
self.replacements['*'] = self.ui.replace_asterisk.text()
|
||||
self.replacements[':'] = self.ui.replace_colon.text()
|
||||
self.replacements['>'] = self.ui.replace_gt.text()
|
||||
self.replacements['<'] = self.ui.replace_lt.text()
|
||||
self.replacements['|'] = self.ui.replace_pipe.text()
|
||||
self.replacements['?'] = self.ui.replace_questionmark.text()
|
||||
self.replacements['"'] = self.ui.replace_quotationmark.text()
|
||||
super().accept()
|
||||
|
||||
|
||||
register_options_page(RenamingCompatOptionsPage)
|
||||
|
||||
@@ -11,7 +11,7 @@ class Ui_RenamingCompatOptionsPage(object):
|
||||
def setupUi(self, RenamingCompatOptionsPage):
|
||||
RenamingCompatOptionsPage.setObjectName("RenamingCompatOptionsPage")
|
||||
RenamingCompatOptionsPage.setEnabled(True)
|
||||
RenamingCompatOptionsPage.resize(453, 374)
|
||||
RenamingCompatOptionsPage.resize(453, 332)
|
||||
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Preferred)
|
||||
sizePolicy.setHorizontalStretch(0)
|
||||
sizePolicy.setVerticalStretch(0)
|
||||
@@ -22,9 +22,21 @@ class Ui_RenamingCompatOptionsPage(object):
|
||||
self.ascii_filenames = QtWidgets.QCheckBox(RenamingCompatOptionsPage)
|
||||
self.ascii_filenames.setObjectName("ascii_filenames")
|
||||
self.verticalLayout_5.addWidget(self.ascii_filenames)
|
||||
self.horizontalLayout = QtWidgets.QHBoxLayout()
|
||||
self.horizontalLayout.setObjectName("horizontalLayout")
|
||||
self.windows_compatibility = QtWidgets.QCheckBox(RenamingCompatOptionsPage)
|
||||
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed)
|
||||
sizePolicy.setHorizontalStretch(0)
|
||||
sizePolicy.setVerticalStretch(0)
|
||||
sizePolicy.setHeightForWidth(self.windows_compatibility.sizePolicy().hasHeightForWidth())
|
||||
self.windows_compatibility.setSizePolicy(sizePolicy)
|
||||
self.windows_compatibility.setObjectName("windows_compatibility")
|
||||
self.verticalLayout_5.addWidget(self.windows_compatibility)
|
||||
self.horizontalLayout.addWidget(self.windows_compatibility)
|
||||
self.btn_windows_compatibility_change = QtWidgets.QPushButton(RenamingCompatOptionsPage)
|
||||
self.btn_windows_compatibility_change.setEnabled(False)
|
||||
self.btn_windows_compatibility_change.setObjectName("btn_windows_compatibility_change")
|
||||
self.horizontalLayout.addWidget(self.btn_windows_compatibility_change)
|
||||
self.verticalLayout_5.addLayout(self.horizontalLayout)
|
||||
self.windows_long_paths = QtWidgets.QCheckBox(RenamingCompatOptionsPage)
|
||||
self.windows_long_paths.setEnabled(False)
|
||||
self.windows_long_paths.setObjectName("windows_long_paths")
|
||||
@@ -32,6 +44,8 @@ class Ui_RenamingCompatOptionsPage(object):
|
||||
self.replace_spaces_with_underscores = QtWidgets.QCheckBox(RenamingCompatOptionsPage)
|
||||
self.replace_spaces_with_underscores.setObjectName("replace_spaces_with_underscores")
|
||||
self.verticalLayout_5.addWidget(self.replace_spaces_with_underscores)
|
||||
spacerItem = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
|
||||
self.verticalLayout_5.addItem(spacerItem)
|
||||
self.example_selection_note = QtWidgets.QLabel(RenamingCompatOptionsPage)
|
||||
self.example_selection_note.setText("")
|
||||
self.example_selection_note.setWordWrap(True)
|
||||
@@ -40,13 +54,14 @@ class Ui_RenamingCompatOptionsPage(object):
|
||||
|
||||
self.retranslateUi(RenamingCompatOptionsPage)
|
||||
self.windows_compatibility.toggled['bool'].connect(self.windows_long_paths.setEnabled) # type: ignore
|
||||
self.windows_compatibility.toggled['bool'].connect(self.btn_windows_compatibility_change.setEnabled) # type: ignore
|
||||
QtCore.QMetaObject.connectSlotsByName(RenamingCompatOptionsPage)
|
||||
RenamingCompatOptionsPage.setTabOrder(self.ascii_filenames, self.windows_compatibility)
|
||||
RenamingCompatOptionsPage.setTabOrder(self.windows_compatibility, self.windows_long_paths)
|
||||
RenamingCompatOptionsPage.setTabOrder(self.ascii_filenames, self.windows_long_paths)
|
||||
|
||||
def retranslateUi(self, RenamingCompatOptionsPage):
|
||||
_translate = QtCore.QCoreApplication.translate
|
||||
self.ascii_filenames.setText(_("Replace non-ASCII characters"))
|
||||
self.windows_compatibility.setText(_("Windows compatibility"))
|
||||
self.btn_windows_compatibility_change.setText(_("Customize..."))
|
||||
self.windows_long_paths.setText(_("Allow paths longer than 259 characters"))
|
||||
self.replace_spaces_with_underscores.setText(_("Replace spaces with underscores"))
|
||||
|
||||
193
picard/ui/ui_win_compat_dialog.py
Normal file
193
picard/ui/ui_win_compat_dialog.py
Normal file
@@ -0,0 +1,193 @@
|
||||
# -*- 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_WinCompatDialog(object):
|
||||
def setupUi(self, WinCompatDialog):
|
||||
WinCompatDialog.setObjectName("WinCompatDialog")
|
||||
WinCompatDialog.setWindowModality(QtCore.Qt.WindowModal)
|
||||
WinCompatDialog.resize(285, 295)
|
||||
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding)
|
||||
sizePolicy.setHorizontalStretch(1)
|
||||
sizePolicy.setVerticalStretch(1)
|
||||
sizePolicy.setHeightForWidth(WinCompatDialog.sizePolicy().hasHeightForWidth())
|
||||
WinCompatDialog.setSizePolicy(sizePolicy)
|
||||
self.verticalLayout = QtWidgets.QVBoxLayout(WinCompatDialog)
|
||||
self.verticalLayout.setSizeConstraint(QtWidgets.QLayout.SetFixedSize)
|
||||
self.verticalLayout.setObjectName("verticalLayout")
|
||||
self.gridLayout = QtWidgets.QGridLayout()
|
||||
self.gridLayout.setObjectName("gridLayout")
|
||||
self.label_header_character = QtWidgets.QLabel(WinCompatDialog)
|
||||
font = QtGui.QFont()
|
||||
font.setBold(True)
|
||||
font.setWeight(75)
|
||||
self.label_header_character.setFont(font)
|
||||
self.label_header_character.setObjectName("label_header_character")
|
||||
self.gridLayout.addWidget(self.label_header_character, 0, 0, 1, 1)
|
||||
self.label_header_replace = QtWidgets.QLabel(WinCompatDialog)
|
||||
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Preferred)
|
||||
sizePolicy.setHorizontalStretch(0)
|
||||
sizePolicy.setVerticalStretch(0)
|
||||
sizePolicy.setHeightForWidth(self.label_header_replace.sizePolicy().hasHeightForWidth())
|
||||
self.label_header_replace.setSizePolicy(sizePolicy)
|
||||
font = QtGui.QFont()
|
||||
font.setBold(True)
|
||||
font.setWeight(75)
|
||||
self.label_header_replace.setFont(font)
|
||||
self.label_header_replace.setObjectName("label_header_replace")
|
||||
self.gridLayout.addWidget(self.label_header_replace, 0, 2, 1, 1)
|
||||
self.label_lt = QtWidgets.QLabel(WinCompatDialog)
|
||||
font = QtGui.QFont()
|
||||
font.setFamily("Monospace")
|
||||
self.label_lt.setFont(font)
|
||||
self.label_lt.setObjectName("label_lt")
|
||||
self.gridLayout.addWidget(self.label_lt, 3, 0, 1, 1)
|
||||
self.label_colon = QtWidgets.QLabel(WinCompatDialog)
|
||||
font = QtGui.QFont()
|
||||
font.setFamily("Monospace")
|
||||
self.label_colon.setFont(font)
|
||||
self.label_colon.setObjectName("label_colon")
|
||||
self.gridLayout.addWidget(self.label_colon, 2, 0, 1, 1)
|
||||
self.label_gt = QtWidgets.QLabel(WinCompatDialog)
|
||||
font = QtGui.QFont()
|
||||
font.setFamily("Monospace")
|
||||
self.label_gt.setFont(font)
|
||||
self.label_gt.setObjectName("label_gt")
|
||||
self.gridLayout.addWidget(self.label_gt, 4, 0, 1, 1)
|
||||
self.replace_questionmark = QtWidgets.QLineEdit(WinCompatDialog)
|
||||
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Fixed)
|
||||
sizePolicy.setHorizontalStretch(0)
|
||||
sizePolicy.setVerticalStretch(0)
|
||||
sizePolicy.setHeightForWidth(self.replace_questionmark.sizePolicy().hasHeightForWidth())
|
||||
self.replace_questionmark.setSizePolicy(sizePolicy)
|
||||
self.replace_questionmark.setMaximumSize(QtCore.QSize(20, 16777215))
|
||||
self.replace_questionmark.setMaxLength(1)
|
||||
self.replace_questionmark.setObjectName("replace_questionmark")
|
||||
self.gridLayout.addWidget(self.replace_questionmark, 5, 2, 1, 1)
|
||||
self.label_questionmark = QtWidgets.QLabel(WinCompatDialog)
|
||||
font = QtGui.QFont()
|
||||
font.setFamily("Monospace")
|
||||
self.label_questionmark.setFont(font)
|
||||
self.label_questionmark.setObjectName("label_questionmark")
|
||||
self.gridLayout.addWidget(self.label_questionmark, 5, 0, 1, 1)
|
||||
self.label_pipe = QtWidgets.QLabel(WinCompatDialog)
|
||||
font = QtGui.QFont()
|
||||
font.setFamily("Monospace")
|
||||
self.label_pipe.setFont(font)
|
||||
self.label_pipe.setObjectName("label_pipe")
|
||||
self.gridLayout.addWidget(self.label_pipe, 6, 0, 1, 1)
|
||||
self.replace_asterisk = QtWidgets.QLineEdit(WinCompatDialog)
|
||||
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Minimum)
|
||||
sizePolicy.setHorizontalStretch(0)
|
||||
sizePolicy.setVerticalStretch(0)
|
||||
sizePolicy.setHeightForWidth(self.replace_asterisk.sizePolicy().hasHeightForWidth())
|
||||
self.replace_asterisk.setSizePolicy(sizePolicy)
|
||||
self.replace_asterisk.setMaximumSize(QtCore.QSize(20, 16777215))
|
||||
self.replace_asterisk.setMaxLength(1)
|
||||
self.replace_asterisk.setObjectName("replace_asterisk")
|
||||
self.gridLayout.addWidget(self.replace_asterisk, 1, 2, 1, 1)
|
||||
self.replace_gt = QtWidgets.QLineEdit(WinCompatDialog)
|
||||
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Fixed)
|
||||
sizePolicy.setHorizontalStretch(0)
|
||||
sizePolicy.setVerticalStretch(0)
|
||||
sizePolicy.setHeightForWidth(self.replace_gt.sizePolicy().hasHeightForWidth())
|
||||
self.replace_gt.setSizePolicy(sizePolicy)
|
||||
self.replace_gt.setMaximumSize(QtCore.QSize(20, 16777215))
|
||||
self.replace_gt.setMaxLength(1)
|
||||
self.replace_gt.setObjectName("replace_gt")
|
||||
self.gridLayout.addWidget(self.replace_gt, 4, 2, 1, 1)
|
||||
spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
|
||||
self.gridLayout.addItem(spacerItem, 0, 3, 1, 1)
|
||||
self.replace_lt = QtWidgets.QLineEdit(WinCompatDialog)
|
||||
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Fixed)
|
||||
sizePolicy.setHorizontalStretch(0)
|
||||
sizePolicy.setVerticalStretch(0)
|
||||
sizePolicy.setHeightForWidth(self.replace_lt.sizePolicy().hasHeightForWidth())
|
||||
self.replace_lt.setSizePolicy(sizePolicy)
|
||||
self.replace_lt.setMaximumSize(QtCore.QSize(20, 16777215))
|
||||
self.replace_lt.setMaxLength(1)
|
||||
self.replace_lt.setObjectName("replace_lt")
|
||||
self.gridLayout.addWidget(self.replace_lt, 3, 2, 1, 1)
|
||||
self.label_asterisk = QtWidgets.QLabel(WinCompatDialog)
|
||||
font = QtGui.QFont()
|
||||
font.setFamily("Monospace")
|
||||
self.label_asterisk.setFont(font)
|
||||
self.label_asterisk.setObjectName("label_asterisk")
|
||||
self.gridLayout.addWidget(self.label_asterisk, 1, 0, 1, 1)
|
||||
self.replace_pipe = QtWidgets.QLineEdit(WinCompatDialog)
|
||||
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Fixed)
|
||||
sizePolicy.setHorizontalStretch(0)
|
||||
sizePolicy.setVerticalStretch(0)
|
||||
sizePolicy.setHeightForWidth(self.replace_pipe.sizePolicy().hasHeightForWidth())
|
||||
self.replace_pipe.setSizePolicy(sizePolicy)
|
||||
self.replace_pipe.setMaximumSize(QtCore.QSize(20, 16777215))
|
||||
self.replace_pipe.setMaxLength(1)
|
||||
self.replace_pipe.setObjectName("replace_pipe")
|
||||
self.gridLayout.addWidget(self.replace_pipe, 6, 2, 1, 1)
|
||||
self.replace_colon = QtWidgets.QLineEdit(WinCompatDialog)
|
||||
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Fixed)
|
||||
sizePolicy.setHorizontalStretch(0)
|
||||
sizePolicy.setVerticalStretch(0)
|
||||
sizePolicy.setHeightForWidth(self.replace_colon.sizePolicy().hasHeightForWidth())
|
||||
self.replace_colon.setSizePolicy(sizePolicy)
|
||||
self.replace_colon.setMaximumSize(QtCore.QSize(20, 16777215))
|
||||
self.replace_colon.setMaxLength(1)
|
||||
self.replace_colon.setObjectName("replace_colon")
|
||||
self.gridLayout.addWidget(self.replace_colon, 2, 2, 1, 1)
|
||||
self.label_quotationmark = QtWidgets.QLabel(WinCompatDialog)
|
||||
font = QtGui.QFont()
|
||||
font.setFamily("Monospace")
|
||||
self.label_quotationmark.setFont(font)
|
||||
self.label_quotationmark.setObjectName("label_quotationmark")
|
||||
self.gridLayout.addWidget(self.label_quotationmark, 7, 0, 1, 1)
|
||||
self.replace_quotationmark = QtWidgets.QLineEdit(WinCompatDialog)
|
||||
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Fixed)
|
||||
sizePolicy.setHorizontalStretch(0)
|
||||
sizePolicy.setVerticalStretch(0)
|
||||
sizePolicy.setHeightForWidth(self.replace_quotationmark.sizePolicy().hasHeightForWidth())
|
||||
self.replace_quotationmark.setSizePolicy(sizePolicy)
|
||||
self.replace_quotationmark.setMaximumSize(QtCore.QSize(20, 16777215))
|
||||
self.replace_quotationmark.setObjectName("replace_quotationmark")
|
||||
self.gridLayout.addWidget(self.replace_quotationmark, 7, 2, 1, 1)
|
||||
self.verticalLayout.addLayout(self.gridLayout)
|
||||
spacerItem1 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
|
||||
self.verticalLayout.addItem(spacerItem1)
|
||||
self.buttonbox = QtWidgets.QDialogButtonBox(WinCompatDialog)
|
||||
self.buttonbox.setOrientation(QtCore.Qt.Horizontal)
|
||||
self.buttonbox.setStandardButtons(QtWidgets.QDialogButtonBox.Cancel|QtWidgets.QDialogButtonBox.Save)
|
||||
self.buttonbox.setObjectName("buttonbox")
|
||||
self.verticalLayout.addWidget(self.buttonbox)
|
||||
|
||||
self.retranslateUi(WinCompatDialog)
|
||||
QtCore.QMetaObject.connectSlotsByName(WinCompatDialog)
|
||||
WinCompatDialog.setTabOrder(self.replace_asterisk, self.replace_colon)
|
||||
WinCompatDialog.setTabOrder(self.replace_colon, self.replace_lt)
|
||||
WinCompatDialog.setTabOrder(self.replace_lt, self.replace_gt)
|
||||
WinCompatDialog.setTabOrder(self.replace_gt, self.replace_questionmark)
|
||||
WinCompatDialog.setTabOrder(self.replace_questionmark, self.replace_pipe)
|
||||
WinCompatDialog.setTabOrder(self.replace_pipe, self.replace_quotationmark)
|
||||
|
||||
def retranslateUi(self, WinCompatDialog):
|
||||
_translate = QtCore.QCoreApplication.translate
|
||||
WinCompatDialog.setWindowTitle(_("Windows compatibility"))
|
||||
self.label_header_character.setText(_("Character"))
|
||||
self.label_header_replace.setText(_("Replacement"))
|
||||
self.label_lt.setText(_("<"))
|
||||
self.label_colon.setText(_(":"))
|
||||
self.label_gt.setText(_(">"))
|
||||
self.replace_questionmark.setText(_("_"))
|
||||
self.label_questionmark.setText(_("?"))
|
||||
self.label_pipe.setText(_("|"))
|
||||
self.replace_asterisk.setText(_("_"))
|
||||
self.replace_gt.setText(_("_"))
|
||||
self.replace_lt.setText(_("_"))
|
||||
self.label_asterisk.setText(_("*"))
|
||||
self.replace_pipe.setText(_("_"))
|
||||
self.replace_colon.setText(_("_"))
|
||||
self.label_quotationmark.setText(_("\""))
|
||||
self.replace_quotationmark.setText(_("_"))
|
||||
@@ -39,7 +39,10 @@
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
|
||||
from collections import namedtuple
|
||||
from collections import (
|
||||
defaultdict,
|
||||
namedtuple,
|
||||
)
|
||||
from collections.abc import Mapping
|
||||
from itertools import chain
|
||||
import json
|
||||
@@ -293,16 +296,21 @@ def sanitize_date(datestr):
|
||||
return ("", "%04d", "%04d-%02d", "%04d-%02d-%02d")[len(date)] % tuple(date)
|
||||
|
||||
|
||||
_re_win32_incompat = re.compile(r'["*:<>?|]', re.UNICODE)
|
||||
def replace_win32_incompat(string, repl="_"): # noqa: E302
|
||||
def replace_win32_incompat(string, repl="_", replacements=None): # noqa: E302
|
||||
"""Replace win32 filename incompatible characters from ``string`` by
|
||||
``repl``."""
|
||||
# Don't replace : with _ for windows drive
|
||||
# Don't replace : for windows drive
|
||||
if IS_WIN and os.path.isabs(string):
|
||||
drive, rest = ntpath.splitdrive(string)
|
||||
return drive + _re_win32_incompat.sub(repl, rest)
|
||||
drive, string = ntpath.splitdrive(string)
|
||||
else:
|
||||
return _re_win32_incompat.sub(repl, string)
|
||||
drive = ''
|
||||
|
||||
replacements = defaultdict(lambda: repl, replacements or {})
|
||||
for char in {'"', '*', ':', '<', '>', '?', '|'}:
|
||||
if char in string:
|
||||
string = string.replace(char, replacements[char])
|
||||
|
||||
return drive + string
|
||||
|
||||
|
||||
_re_non_alphanum = re.compile(r'\W+', re.UNICODE)
|
||||
|
||||
@@ -66,7 +66,7 @@ def script_to_filename_with_metadata(naming_format, metadata, file=None, setting
|
||||
filename = replace_non_ascii(filename, pathsave=True, win_compat=win_compat)
|
||||
# replace incompatible characters
|
||||
if win_compat:
|
||||
filename = replace_win32_incompat(filename)
|
||||
filename = replace_win32_incompat(filename, replacements=settings["win_compat_replacements"])
|
||||
if settings["replace_spaces_with_underscores"]:
|
||||
filename = _re_replace_underscores.sub('_', filename.strip())
|
||||
# remove null characters
|
||||
|
||||
@@ -63,6 +63,7 @@ settings = {
|
||||
'remove_wave_riff_info': False,
|
||||
'wave_riff_info_encoding': 'iso-8859-1',
|
||||
'replace_spaces_with_underscores': False,
|
||||
'win_compat_replacements': {},
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -166,6 +166,7 @@ class CoverArtImageTest(PicardTestCase):
|
||||
self.set_config_values({
|
||||
'image_type_as_filename': True,
|
||||
'windows_compatibility': True,
|
||||
'win_compat_replacements': {},
|
||||
'windows_long_paths': False,
|
||||
'replace_spaces_with_underscores': False,
|
||||
'enabled_plugins': [],
|
||||
@@ -197,6 +198,7 @@ class CoverArtImageMakeFilenameTest(PicardTestCase):
|
||||
self.metadata = Metadata()
|
||||
self.set_config_values({
|
||||
'windows_compatibility': False,
|
||||
'win_compat_replacements': {},
|
||||
'enabled_plugins': [],
|
||||
'ascii_filenames': False,
|
||||
'replace_spaces_with_underscores': False,
|
||||
|
||||
@@ -210,6 +210,7 @@ class FileNamingTest(PicardTestCase):
|
||||
'move_files': False,
|
||||
'rename_files': False,
|
||||
'windows_compatibility': True,
|
||||
'win_compat_replacements': {},
|
||||
'windows_long_paths': False,
|
||||
'replace_spaces_with_underscores': False,
|
||||
'file_renaming_scripts': {'test_id': {'script': '%album%/%title%'}},
|
||||
|
||||
@@ -39,6 +39,7 @@ settings = {
|
||||
'ascii_filenames': False,
|
||||
'enabled_plugins': [],
|
||||
'windows_compatibility': False,
|
||||
'win_compat_replacements': {},
|
||||
'replace_spaces_with_underscores': False,
|
||||
}
|
||||
|
||||
@@ -116,6 +117,19 @@ class ScriptToFilenameTest(PicardTestCase):
|
||||
filename = script_to_filename('%artist%?', metadata, settings=settings)
|
||||
self.assertEqual(expect_compat, filename)
|
||||
|
||||
def test_windows_compatibility_custom_replacements(self):
|
||||
metadata = Metadata()
|
||||
metadata['artist'] = '\\*:'
|
||||
expect_compat = '_+_!'
|
||||
settings = config.setting.copy()
|
||||
settings['windows_compatibility'] = True
|
||||
settings['win_compat_replacements'] = {
|
||||
'*': '+',
|
||||
'?': '!',
|
||||
}
|
||||
filename = script_to_filename('%artist%?', metadata, settings=settings)
|
||||
self.assertEqual(expect_compat, filename)
|
||||
|
||||
def test_replace_spaces_with_underscores(self):
|
||||
metadata = Metadata()
|
||||
metadata['artist'] = ' The \t New* _ Artist '
|
||||
|
||||
@@ -88,27 +88,62 @@ class ReplaceWin32IncompatTest(PicardTestCase):
|
||||
|
||||
@unittest.skipUnless(IS_WIN, "windows test")
|
||||
def test_correct_absolute_win32(self):
|
||||
self.assertEqual(util.replace_win32_incompat("c:\\test\\te\"st/2"),
|
||||
"c:\\test\\te_st/2")
|
||||
self.assertEqual(util.replace_win32_incompat("c:\\test\\d:/2"),
|
||||
"c:\\test\\d_/2")
|
||||
self.assertEqual(util.replace_win32_incompat('c:\\test\\te"st/2'),
|
||||
'c:\\test\\te_st/2')
|
||||
self.assertEqual(util.replace_win32_incompat('c:\\test\\d:/2'),
|
||||
'c:\\test\\d_/2')
|
||||
|
||||
@unittest.skipUnless(not IS_WIN, "non-windows test")
|
||||
@unittest.skipUnless(not IS_WIN, 'non-windows test')
|
||||
def test_correct_absolute_non_win32(self):
|
||||
self.assertEqual(util.replace_win32_incompat("/test/te\"st/2"),
|
||||
"/test/te_st/2")
|
||||
self.assertEqual(util.replace_win32_incompat("/test/d:/2"),
|
||||
"/test/d_/2")
|
||||
self.assertEqual(util.replace_win32_incompat('/test/te"st/2'),
|
||||
'/test/te_st/2')
|
||||
self.assertEqual(util.replace_win32_incompat('/test/d:/2'),
|
||||
'/test/d_/2')
|
||||
|
||||
def test_correct_relative(self):
|
||||
self.assertEqual(util.replace_win32_incompat("A\"*:<>?|b"),
|
||||
"A_______b")
|
||||
self.assertEqual(util.replace_win32_incompat("d:tes<t"),
|
||||
"d_tes_t")
|
||||
self.assertEqual(util.replace_win32_incompat('A"*:<>?|b'),
|
||||
'A_______b')
|
||||
self.assertEqual(util.replace_win32_incompat('d:tes<t'),
|
||||
'd_tes_t')
|
||||
|
||||
def test_incorrect(self):
|
||||
self.assertNotEqual(util.replace_win32_incompat("c:\\test\\te\"st2"),
|
||||
"c:\\test\\te\"st2")
|
||||
self.assertNotEqual(util.replace_win32_incompat('c:\\test\\te"st2'),
|
||||
'c:\\test\\te"st2')
|
||||
|
||||
def test_custom_replacement_char(self):
|
||||
self.assertEqual(util.replace_win32_incompat('A"*:<>?|b', repl='+'),
|
||||
"A+++++++b")
|
||||
|
||||
def test_custom_replacement_map(self):
|
||||
input = 'foo*:<>?|"'
|
||||
replacments = {
|
||||
'*': 'A',
|
||||
':': 'B',
|
||||
'<': 'C',
|
||||
'>': 'D',
|
||||
'?': 'E',
|
||||
'|': 'F',
|
||||
'"': 'G',
|
||||
}
|
||||
replaced = util.replace_win32_incompat(input, replacements=replacments)
|
||||
self.assertEqual('fooABCDEFG', replaced)
|
||||
|
||||
def test_partial_replacement_map(self):
|
||||
input = 'foo*:<>?|"'
|
||||
replacments = {
|
||||
'*': 'A',
|
||||
'<': 'C',
|
||||
}
|
||||
replaced = util.replace_win32_incompat(input, repl='-', replacements=replacments)
|
||||
self.assertEqual('fooA-C----', replaced)
|
||||
|
||||
def test_empty_string_replacement_map(self):
|
||||
input = 'foo:bar'
|
||||
replacments = {
|
||||
':': '',
|
||||
}
|
||||
replaced = util.replace_win32_incompat(input, replacements=replacments)
|
||||
self.assertEqual('foobar', replaced)
|
||||
|
||||
|
||||
class MakeFilenameTest(PicardTestCase):
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>453</width>
|
||||
<height>374</height>
|
||||
<height>332</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
@@ -19,7 +19,7 @@
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_5" stretch="0,0,0,0,0">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_5" stretch="0,0,0,0,0,0">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="ascii_filenames">
|
||||
<property name="text">
|
||||
@@ -27,13 +27,33 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="windows_compatibility">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Windows compatibility</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="btn_windows_compatibility_change">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Customize...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="windows_long_paths">
|
||||
<property name="enabled">
|
||||
@@ -51,6 +71,19 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="example_selection_note">
|
||||
<property name="text">
|
||||
@@ -65,7 +98,6 @@
|
||||
</widget>
|
||||
<tabstops>
|
||||
<tabstop>ascii_filenames</tabstop>
|
||||
<tabstop>windows_compatibility</tabstop>
|
||||
<tabstop>windows_long_paths</tabstop>
|
||||
</tabstops>
|
||||
<resources/>
|
||||
@@ -86,5 +118,21 @@
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>windows_compatibility</sender>
|
||||
<signal>toggled(bool)</signal>
|
||||
<receiver>btn_windows_compatibility_change</receiver>
|
||||
<slot>setEnabled(bool)</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>178</x>
|
||||
<y>51</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>397</x>
|
||||
<y>51</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
</ui>
|
||||
|
||||
349
ui/win_compat_dialog.ui
Normal file
349
ui/win_compat_dialog.ui
Normal file
@@ -0,0 +1,349 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>WinCompatDialog</class>
|
||||
<widget class="QDialog" name="WinCompatDialog">
|
||||
<property name="windowModality">
|
||||
<enum>Qt::WindowModal</enum>
|
||||
</property>
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>285</width>
|
||||
<height>295</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
||||
<horstretch>1</horstretch>
|
||||
<verstretch>1</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Windows compatibility</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<property name="sizeConstraint">
|
||||
<enum>QLayout::SetFixedSize</enum>
|
||||
</property>
|
||||
<item>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_header_character">
|
||||
<property name="font">
|
||||
<font>
|
||||
<weight>75</weight>
|
||||
<bold>true</bold>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Character</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="2">
|
||||
<widget class="QLabel" name="label_header_replace">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<weight>75</weight>
|
||||
<bold>true</bold>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Replacement</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="label_lt">
|
||||
<property name="font">
|
||||
<font>
|
||||
<family>Monospace</family>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string><</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label_colon">
|
||||
<property name="font">
|
||||
<font>
|
||||
<family>Monospace</family>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<widget class="QLabel" name="label_gt">
|
||||
<property name="font">
|
||||
<font>
|
||||
<family>Monospace</family>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>></string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="2">
|
||||
<widget class="QLineEdit" name="replace_questionmark">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>_</string>
|
||||
</property>
|
||||
<property name="maxLength">
|
||||
<number>1</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="0">
|
||||
<widget class="QLabel" name="label_questionmark">
|
||||
<property name="font">
|
||||
<font>
|
||||
<family>Monospace</family>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>?</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="0">
|
||||
<widget class="QLabel" name="label_pipe">
|
||||
<property name="font">
|
||||
<font>
|
||||
<family>Monospace</family>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>|</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="2">
|
||||
<widget class="QLineEdit" name="replace_asterisk">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Minimum">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>_</string>
|
||||
</property>
|
||||
<property name="maxLength">
|
||||
<number>1</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="2">
|
||||
<widget class="QLineEdit" name="replace_gt">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>_</string>
|
||||
</property>
|
||||
<property name="maxLength">
|
||||
<number>1</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="3">
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="3" column="2">
|
||||
<widget class="QLineEdit" name="replace_lt">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>_</string>
|
||||
</property>
|
||||
<property name="maxLength">
|
||||
<number>1</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_asterisk">
|
||||
<property name="font">
|
||||
<font>
|
||||
<family>Monospace</family>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>*</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="2">
|
||||
<widget class="QLineEdit" name="replace_pipe">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>_</string>
|
||||
</property>
|
||||
<property name="maxLength">
|
||||
<number>1</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="2">
|
||||
<widget class="QLineEdit" name="replace_colon">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>_</string>
|
||||
</property>
|
||||
<property name="maxLength">
|
||||
<number>1</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="0">
|
||||
<widget class="QLabel" name="label_quotationmark">
|
||||
<property name="font">
|
||||
<font>
|
||||
<family>Monospace</family>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>"</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="2">
|
||||
<widget class="QLineEdit" name="replace_quotationmark">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>_</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDialogButtonBox" name="buttonbox">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Save</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<tabstops>
|
||||
<tabstop>replace_asterisk</tabstop>
|
||||
<tabstop>replace_colon</tabstop>
|
||||
<tabstop>replace_lt</tabstop>
|
||||
<tabstop>replace_gt</tabstop>
|
||||
<tabstop>replace_questionmark</tabstop>
|
||||
<tabstop>replace_pipe</tabstop>
|
||||
<tabstop>replace_quotationmark</tabstop>
|
||||
</tabstops>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
Reference in New Issue
Block a user