Esempio n. 1
0
 def __init__(self, files, parent=None):
     QtGui.QDialog.__init__(self, parent)
     self.ui = Ui_TagsFromFileNamesDialog()
     self.ui.setupUi(self)
     items = [
         "%artist%/%album%/%tracknumber% %title%",
         "%artist%/%album%/%tracknumber% - %title%",
         "%artist%/%album - %tracknumber% - %title%",
     ]
     format = config.persist["tags_from_filenames_format"]
     if format and format not in items:
         items.insert(0, format)
     self.ui.format.addItems(items)
     self.ui.buttonbox.addButton(StandardButton(StandardButton.OK), QtGui.QDialogButtonBox.AcceptRole)
     self.ui.buttonbox.addButton(StandardButton(StandardButton.CANCEL), QtGui.QDialogButtonBox.RejectRole)
     self.ui.buttonbox.accepted.connect(self.accept)
     self.ui.buttonbox.rejected.connect(self.reject)
     self.ui.preview.clicked.connect(self.preview)
     self.ui.files.setHeaderLabels([_("File Name")])
     self.restoreWindowState()
     self.files = files
     self.items = []
     for file in files:
         item = QtGui.QTreeWidgetItem(self.ui.files)
         item.setText(0, os.path.basename(file.filename))
         self.items.append(item)
     self._tag_re = re.compile("(%\w+%)")
Esempio n. 2
0
 def __init__(self, files, parent=None):
     PicardDialog.__init__(self, parent)
     self.ui = Ui_TagsFromFileNamesDialog()
     self.ui.setupUi(self)
     items = [
         "%artist%/%album%/%tracknumber% %title%",
         "%artist%/%album%/%tracknumber% - %title%",
         "%artist%/%album - %tracknumber% - %title%",
     ]
     format = config.persist["tags_from_filenames_format"]
     if format and format not in items:
         items.insert(0, format)
     self.ui.format.addItems(items)
     self.ui.buttonbox.addButton(StandardButton(StandardButton.OK), QtGui.QDialogButtonBox.AcceptRole)
     self.ui.buttonbox.addButton(StandardButton(StandardButton.CANCEL), QtGui.QDialogButtonBox.RejectRole)
     self.ui.buttonbox.accepted.connect(self.accept)
     self.ui.buttonbox.rejected.connect(self.reject)
     self.ui.preview.clicked.connect(self.preview)
     self.ui.files.setHeaderLabels([_("File Name")])
     self.restoreWindowState()
     self.files = files
     self.items = []
     for file in files:
         item = QtGui.QTreeWidgetItem(self.ui.files)
         item.setText(0, os.path.basename(file.filename))
         self.items.append(item)
     self._tag_re = re.compile("(%\w+%)")
Esempio n. 3
0
 def __init__(self, files, parent=None):
     super().__init__(parent)
     self.ui = Ui_TagsFromFileNamesDialog()
     self.ui.setupUi(self)
     items = [
         "%artist%/%album%/%title%",
         "%artist%/%album%/%tracknumber% %title%",
         "%artist%/%album%/%tracknumber% - %title%",
         "%artist%/%album% - %tracknumber% - %title%",
         "%artist% - %album%/%title%",
         "%artist% - %album%/%tracknumber% %title%",
         "%artist% - %album%/%tracknumber% - %title%",
     ]
     config = get_config()
     tff_format = config.persist["tags_from_filenames_format"]
     if tff_format not in items:
         selected_index = 0
         if tff_format:
             items.insert(0, tff_format)
     else:
         selected_index = items.index(tff_format)
     self.ui.format.addItems(items)
     self.ui.format.setCurrentIndex(selected_index)
     self.ui.buttonbox.addButton(
         StandardButton(StandardButton.HELP),
         QtWidgets.QDialogButtonBox.ButtonRole.HelpRole)
     self.ui.buttonbox.addButton(
         StandardButton(StandardButton.OK),
         QtWidgets.QDialogButtonBox.ButtonRole.AcceptRole)
     self.ui.buttonbox.addButton(
         StandardButton(StandardButton.CANCEL),
         QtWidgets.QDialogButtonBox.ButtonRole.RejectRole)
     self.ui.buttonbox.accepted.connect(self.accept)
     self.ui.buttonbox.rejected.connect(self.reject)
     self.ui.buttonbox.helpRequested.connect(self.show_help)
     self.ui.preview.clicked.connect(self.preview)
     self.ui.files.setHeaderLabels([_("File Name")])
     self.files = files
     self.items = []
     for file in files:
         item = QtWidgets.QTreeWidgetItem(self.ui.files)
         item.setText(0, os.path.basename(file.filename))
         self.items.append(item)
Esempio n. 4
0
 def __init__(self, files, parent=None):
     PicardDialog.__init__(self, parent)
     self.ui = Ui_TagsFromFileNamesDialog()
     self.ui.setupUi(self)
     items = [
         "%artist%/%album%/%title%",
         "%artist%/%album%/%tracknumber% %title%",
         "%artist%/%album%/%tracknumber% - %title%",
         "%artist%/%album% - %tracknumber% - %title%",
         "%artist% - %album%/%title%",
         "%artist% - %album%/%tracknumber% %title%",
         "%artist% - %album%/%tracknumber% - %title%",
     ]
     tff_format = config.persist["tags_from_filenames_format"]
     if tff_format not in items:
         selected_index = 0
         if tff_format:
             items.insert(0, tff_format)
     else:
         selected_index = items.index(tff_format)
     self.ui.format.addItems(items)
     self.ui.format.setCurrentIndex(selected_index)
     self.ui.buttonbox.addButton(StandardButton(StandardButton.OK),
                                 QtWidgets.QDialogButtonBox.AcceptRole)
     self.ui.buttonbox.addButton(StandardButton(StandardButton.CANCEL),
                                 QtWidgets.QDialogButtonBox.RejectRole)
     self.ui.buttonbox.accepted.connect(self.accept)
     self.ui.buttonbox.rejected.connect(self.reject)
     self.ui.preview.clicked.connect(self.preview)
     self.ui.files.setHeaderLabels([_("File Name")])
     self.restoreWindowState()
     self.files = files
     self.items = []
     for file in files:
         item = QtWidgets.QTreeWidgetItem(self.ui.files)
         item.setText(0, os.path.basename(file.filename))
         self.items.append(item)
     self._tag_re = re.compile(r"(%\w+%)")
     self.numeric_tags = ('tracknumber', 'totaltracks', 'discnumber',
                          'totaldiscs')
Esempio n. 5
0
 def __init__(self, files, parent=None):
     super().__init__(parent)
     self.ui = Ui_TagsFromFileNamesDialog()
     self.ui.setupUi(self)
     items = [
         "%artist%/%album%/%title%",
         "%artist%/%album%/%tracknumber% %title%",
         "%artist%/%album%/%tracknumber% - %title%",
         "%artist%/%album% - %tracknumber% - %title%",
         "%artist% - %album%/%title%",
         "%artist% - %album%/%tracknumber% %title%",
         "%artist% - %album%/%tracknumber% - %title%",
     ]
     tff_format = config.persist["tags_from_filenames_format"]
     if tff_format not in items:
         selected_index = 0
         if tff_format:
             items.insert(0, tff_format)
     else:
         selected_index = items.index(tff_format)
     self.ui.format.addItems(items)
     self.ui.format.setCurrentIndex(selected_index)
     self.ui.buttonbox.addButton(StandardButton(StandardButton.OK), QtWidgets.QDialogButtonBox.AcceptRole)
     self.ui.buttonbox.addButton(StandardButton(StandardButton.CANCEL), QtWidgets.QDialogButtonBox.RejectRole)
     self.ui.buttonbox.accepted.connect(self.accept)
     self.ui.buttonbox.rejected.connect(self.reject)
     self.ui.preview.clicked.connect(self.preview)
     self.ui.files.setHeaderLabels([_("File Name")])
     self.files = files
     self.items = []
     for file in files:
         item = QtWidgets.QTreeWidgetItem(self.ui.files)
         item.setText(0, os.path.basename(file.filename))
         self.items.append(item)
     self._tag_re = re.compile(r"(%\w+%)")
     self.numeric_tags = ('tracknumber', 'totaltracks', 'discnumber', 'totaldiscs')
Esempio n. 6
0
class TagsFromFileNamesDialog(PicardDialog):

    options = [
        config.TextOption("persist", "tags_from_filenames_format", ""),
        config.Option("persist", "tags_from_filenames_position", QtCore.QPoint()),
        config.Option("persist", "tags_from_filenames_size", QtCore.QSize(560, 400)),
    ]

    def __init__(self, files, parent=None):
        PicardDialog.__init__(self, parent)
        self.ui = Ui_TagsFromFileNamesDialog()
        self.ui.setupUi(self)
        items = [
            "%artist%/%album%/%tracknumber% %title%",
            "%artist%/%album%/%tracknumber% - %title%",
            "%artist%/%album - %tracknumber% - %title%",
        ]
        format = config.persist["tags_from_filenames_format"]
        if format and format not in items:
            items.insert(0, format)
        self.ui.format.addItems(items)
        self.ui.buttonbox.addButton(StandardButton(StandardButton.OK), QtGui.QDialogButtonBox.AcceptRole)
        self.ui.buttonbox.addButton(StandardButton(StandardButton.CANCEL), QtGui.QDialogButtonBox.RejectRole)
        self.ui.buttonbox.accepted.connect(self.accept)
        self.ui.buttonbox.rejected.connect(self.reject)
        self.ui.preview.clicked.connect(self.preview)
        self.ui.files.setHeaderLabels([_("File Name")])
        self.restoreWindowState()
        self.files = files
        self.items = []
        for file in files:
            item = QtGui.QTreeWidgetItem(self.ui.files)
            item.setText(0, os.path.basename(file.filename))
            self.items.append(item)
        self._tag_re = re.compile("(%\w+%)")

    def parse_format(self):
        format = unicode(self.ui.format.currentText())
        columns = []
        format_re = ["(?:^|/)"]
        for part in self._tag_re.split(format):
            if part.startswith("%") and part.endswith("%"):
                name = part[1:-1]
                columns.append(name)
                if name in ("tracknumber", "totaltracks", "discnumber", "totaldiscs"):
                    format_re.append("(?P<" + name + ">\d+)")
                elif name in ("date"):
                    format_re.append("(?P<" + name + ">\d+(?:-\d+(?:-\d+)?)?)")
                else:
                    format_re.append("(?P<" + name + ">[^/]*?)")
            else:
                format_re.append(re.escape(part))
        format_re.append("\\.(\\w+)$")
        format_re = re.compile("".join(format_re))
        return format_re, columns

    def match_file(self, file, format):
        match = format.search("/".join(os.path.split(file.filename)))
        if match:
            result = {}
            for name, value in match.groupdict().iteritems():
                value = value.strip()
                if self.ui.replace_underscores.isChecked():
                    value = value.replace("_", " ")
                result[name] = value
            return result
        else:
            return {}

    def preview(self):
        format, columns = self.parse_format()
        self.ui.files.setHeaderLabels([_("File Name")] + map(display_tag_name, columns))
        for item, file in zip(self.items, self.files):
            matches = self.match_file(file, format)
            for i in range(len(columns)):
                value = matches.get(columns[i], "")
                item.setText(i + 1, value)
        self.ui.files.header().resizeSections(QtGui.QHeaderView.ResizeToContents)
        self.ui.files.header().setStretchLastSection(True)

    def accept(self):
        format, columns = self.parse_format()
        for file in self.files:
            metadata = self.match_file(file, format)
            for name, value in metadata.iteritems():
                file.metadata[name] = value
            file.update()
        config.persist["tags_from_filenames_format"] = self.ui.format.currentText()
        self.saveWindowState()
        QtGui.QDialog.accept(self)

    def reject(self):
        self.saveWindowState()
        QtGui.QDialog.reject(self)

    def closeEvent(self, event):
        self.saveWindowState()
        event.accept()

    def saveWindowState(self):
        pos = self.pos()
        if not pos.isNull():
            config.persist["tags_from_filenames_position"] = pos
        config.persist["tags_from_filenames_size"] = self.size()

    def restoreWindowState(self):
        pos = config.persist["tags_from_filenames_position"]
        if pos.x() > 0 and pos.y() > 0:
            self.move(pos)
        self.resize(config.persist["tags_from_filenames_size"])
Esempio n. 7
0
class TagsFromFileNamesDialog(PicardDialog):

    help_url = 'doc_tags_from_filenames'

    options = [
        TextOption("persist", "tags_from_filenames_format", ""),
    ]

    def __init__(self, files, parent=None):
        super().__init__(parent)
        self.ui = Ui_TagsFromFileNamesDialog()
        self.ui.setupUi(self)
        items = [
            "%artist%/%album%/%title%",
            "%artist%/%album%/%tracknumber% %title%",
            "%artist%/%album%/%tracknumber% - %title%",
            "%artist%/%album% - %tracknumber% - %title%",
            "%artist% - %album%/%title%",
            "%artist% - %album%/%tracknumber% %title%",
            "%artist% - %album%/%tracknumber% - %title%",
        ]
        config = get_config()
        tff_format = config.persist["tags_from_filenames_format"]
        if tff_format not in items:
            selected_index = 0
            if tff_format:
                items.insert(0, tff_format)
        else:
            selected_index = items.index(tff_format)
        self.ui.format.addItems(items)
        self.ui.format.setCurrentIndex(selected_index)
        self.ui.buttonbox.addButton(
            StandardButton(StandardButton.HELP),
            QtWidgets.QDialogButtonBox.ButtonRole.HelpRole)
        self.ui.buttonbox.addButton(
            StandardButton(StandardButton.OK),
            QtWidgets.QDialogButtonBox.ButtonRole.AcceptRole)
        self.ui.buttonbox.addButton(
            StandardButton(StandardButton.CANCEL),
            QtWidgets.QDialogButtonBox.ButtonRole.RejectRole)
        self.ui.buttonbox.accepted.connect(self.accept)
        self.ui.buttonbox.rejected.connect(self.reject)
        self.ui.buttonbox.helpRequested.connect(self.show_help)
        self.ui.preview.clicked.connect(self.preview)
        self.ui.files.setHeaderLabels([_("File Name")])
        self.files = files
        self.items = []
        for file in files:
            item = QtWidgets.QTreeWidgetItem(self.ui.files)
            item.setText(0, os.path.basename(file.filename))
            self.items.append(item)

    def preview(self):
        expression = TagMatchExpression(
            self.ui.format.currentText(),
            self.ui.replace_underscores.isChecked())
        columns = expression.matched_tags
        headers = [_("File Name")] + list(map(display_tag_name, columns))
        self.ui.files.setColumnCount(len(headers))
        self.ui.files.setHeaderLabels(headers)
        for item, file in zip(self.items, self.files):
            matches = expression.match_file(file.filename)
            for i, column in enumerate(columns):
                values = matches.get(column, [])
                item.setText(i + 1, '; '.join(values))
        self.ui.files.header().resizeSections(
            QtWidgets.QHeaderView.ResizeMode.ResizeToContents)
        self.ui.files.header().setStretchLastSection(True)

    def accept(self):
        expression = TagMatchExpression(
            self.ui.format.currentText(),
            self.ui.replace_underscores.isChecked())
        for file in self.files:
            metadata = expression.match_file(file.filename)
            file.metadata.update(metadata)
            file.update()
        config = get_config()
        config.persist[
            "tags_from_filenames_format"] = self.ui.format.currentText()
        super().accept()
Esempio n. 8
0
class TagsFromFileNamesDialog(QtGui.QDialog):

    options = [
        config.TextOption("persist", "tags_from_filenames_format", ""),
        config.Option("persist", "tags_from_filenames_position", QtCore.QPoint(), QtCore.QVariant.toPoint),
        config.Option("persist", "tags_from_filenames_size", QtCore.QSize(560, 400), QtCore.QVariant.toSize),
    ]

    def __init__(self, files, parent=None):
        QtGui.QDialog.__init__(self, parent)
        self.ui = Ui_TagsFromFileNamesDialog()
        self.ui.setupUi(self)
        items = [
            "%artist%/%album%/%tracknumber% %title%",
            "%artist%/%album%/%tracknumber% - %title%",
            "%artist%/%album - %tracknumber% - %title%",
        ]
        format = config.persist["tags_from_filenames_format"]
        if format and format not in items:
            items.insert(0, format)
        self.ui.format.addItems(items)
        self.ui.buttonbox.addButton(StandardButton(StandardButton.OK), QtGui.QDialogButtonBox.AcceptRole)
        self.ui.buttonbox.addButton(StandardButton(StandardButton.CANCEL), QtGui.QDialogButtonBox.RejectRole)
        self.ui.buttonbox.accepted.connect(self.accept)
        self.ui.buttonbox.rejected.connect(self.reject)
        self.ui.preview.clicked.connect(self.preview)
        self.ui.files.setHeaderLabels([_("File Name")])
        self.restoreWindowState()
        self.files = files
        self.items = []
        for file in files:
            item = QtGui.QTreeWidgetItem(self.ui.files)
            item.setText(0, os.path.basename(file.filename))
            self.items.append(item)
        self._tag_re = re.compile("(%\w+%)")

    def parse_format(self):
        format = unicode(self.ui.format.currentText())
        columns = []
        format_re = ['(?:^|/)']
        for part in self._tag_re.split(format):
            if part.startswith('%') and part.endswith('%'):
                name = part[1:-1]
                columns.append(name)
                if name in ('tracknumber', 'totaltracks', 'discnumber', 'totaldiscs'):
                    format_re.append('(?P<' + name + '>\d+)')
                elif name in ('date'):
                    format_re.append('(?P<' + name + '>\d+(?:-\d+(?:-\d+)?)?)')
                else:
                    format_re.append('(?P<' + name + '>[^/]*?)')
            else:
                format_re.append(re.escape(part))
        format_re.append('\\.(\\w+)$')
        format_re = re.compile("".join(format_re))
        return format_re, columns

    def match_file(self, file, format):
        match = format.search('/'.join(os.path.split(file.filename)))
        if match:
            result = {}
            for name, value in match.groupdict().iteritems():
                value = value.strip()
                if self.ui.replace_underscores.isChecked():
                    value = value.replace('_', ' ')
                result[name] = value
            return result
        else:
            return {}

    def preview(self):
        format, columns = self.parse_format()
        self.ui.files.setHeaderLabels([_("File Name")] + map(display_tag_name, columns))
        for item, file in zip(self.items, self.files):
            matches = self.match_file(file, format)
            for i in range(len(columns)):
                value = matches.get(columns[i], '')
                item.setText(i + 1, value)
        self.ui.files.header().resizeSections(QtGui.QHeaderView.ResizeToContents)
        self.ui.files.header().setStretchLastSection(True)

    def accept(self):
        format, columns = self.parse_format()
        for file in self.files:
            metadata = self.match_file(file, format)
            for name, value in metadata.iteritems():
                file.metadata[name] = value
            file.update()
        config.persist["tags_from_filenames_format"] = self.ui.format.currentText()
        self.saveWindowState()
        QtGui.QDialog.accept(self)

    def reject(self):
        self.saveWindowState()
        QtGui.QDialog.reject(self)

    def closeEvent(self, event):
        self.saveWindowState()
        event.accept()

    def saveWindowState(self):
        pos = self.pos()
        if not pos.isNull():
            config.persist["tags_from_filenames_position"] = pos
        config.persist["tags_from_filenames_size"] = self.size()

    def restoreWindowState(self):
        pos = config.persist["tags_from_filenames_position"]
        if pos.x() > 0 and pos.y() > 0:
            self.move(pos)
        self.resize(config.persist["tags_from_filenames_size"])
Esempio n. 9
0
class TagsFromFileNamesDialog(PicardDialog):

    options = [
        config.TextOption("persist", "tags_from_filenames_format", ""),
    ]

    def __init__(self, files, parent=None):
        super().__init__(parent)
        self.ui = Ui_TagsFromFileNamesDialog()
        self.ui.setupUi(self)
        items = [
            "%artist%/%album%/%title%",
            "%artist%/%album%/%tracknumber% %title%",
            "%artist%/%album%/%tracknumber% - %title%",
            "%artist%/%album% - %tracknumber% - %title%",
            "%artist% - %album%/%title%",
            "%artist% - %album%/%tracknumber% %title%",
            "%artist% - %album%/%tracknumber% - %title%",
        ]
        tff_format = config.persist["tags_from_filenames_format"]
        if tff_format not in items:
            selected_index = 0
            if tff_format:
                items.insert(0, tff_format)
        else:
            selected_index = items.index(tff_format)
        self.ui.format.addItems(items)
        self.ui.format.setCurrentIndex(selected_index)
        self.ui.buttonbox.addButton(StandardButton(StandardButton.OK),
                                    QtWidgets.QDialogButtonBox.AcceptRole)
        self.ui.buttonbox.addButton(StandardButton(StandardButton.CANCEL),
                                    QtWidgets.QDialogButtonBox.RejectRole)
        self.ui.buttonbox.accepted.connect(self.accept)
        self.ui.buttonbox.rejected.connect(self.reject)
        self.ui.preview.clicked.connect(self.preview)
        self.ui.files.setHeaderLabels([_("File Name")])
        self.files = files
        self.items = []
        for file in files:
            item = QtWidgets.QTreeWidgetItem(self.ui.files)
            item.setText(0, os.path.basename(file.filename))
            self.items.append(item)
        self._tag_re = re.compile(r"(%\w+%)")
        self.numeric_tags = ('tracknumber', 'totaltracks', 'discnumber',
                             'totaldiscs')

    def parse_response(self):
        tff_format = self.ui.format.currentText()
        columns = []
        format_re = ['(?:^|/)']
        for part in self._tag_re.split(tff_format):
            if part.startswith('%') and part.endswith('%'):
                name = part[1:-1]
                columns.append(name)
                if name in self.numeric_tags:
                    format_re.append('(?P<' + name + r'>\d+)')
                elif name == 'date':
                    format_re.append('(?P<' + name +
                                     r'>\d+(?:-\d+(?:-\d+)?)?)')
                else:
                    format_re.append('(?P<' + name + '>[^/]*?)')
            else:
                format_re.append(re.escape(part))
        format_re.append(r'\.(\w+)$')
        format_re = re.compile("".join(format_re))
        return format_re, columns

    def match_file(self, file, tff_format):
        match = tff_format.search(file.filename.replace('\\', '/'))
        if match:
            result = {}
            for name, value in match.groupdict().items():
                value = value.strip()
                if name in self.numeric_tags:
                    value = value.lstrip("0")
                if self.ui.replace_underscores.isChecked():
                    value = value.replace('_', ' ')
                result[name] = value
            return result
        else:
            return {}

    def preview(self):
        tff_format, columns = self.parse_response()
        self.ui.files.setHeaderLabels([_("File Name")] +
                                      list(map(display_tag_name, columns)))
        for item, file in zip(self.items, self.files):
            matches = self.match_file(file, tff_format)
            for i, column in enumerate(columns):
                item.setText(i + 1, matches.get(column, ''))
        self.ui.files.header().resizeSections(
            QtWidgets.QHeaderView.ResizeToContents)
        self.ui.files.header().setStretchLastSection(True)

    def accept(self):
        tff_format, columns = self.parse_response()
        for file in self.files:
            metadata = self.match_file(file, tff_format)
            for name, value in metadata.items():
                file.metadata[name] = value
            file.update()
        config.persist[
            "tags_from_filenames_format"] = self.ui.format.currentText()
        super().accept()
Esempio n. 10
0
class TagsFromFileNamesDialog(PicardDialog):

    options = [
        config.TextOption("persist", "tags_from_filenames_format", ""),
        config.Option("persist", "tags_from_filenames_position", QtCore.QPoint()),
        config.Option("persist", "tags_from_filenames_size", QtCore.QSize(560, 400)),
    ]

    def __init__(self, files, parent=None):
        PicardDialog.__init__(self, parent)
        self.ui = Ui_TagsFromFileNamesDialog()
        self.ui.setupUi(self)
        items = [
            "%artist%/%album%/%title%",
            "%artist%/%album%/%tracknumber% %title%",
            "%artist%/%album%/%tracknumber% - %title%",
            "%artist%/%album% - %tracknumber% - %title%",
            "%artist% - %album%/%title%",
            "%artist% - %album%/%tracknumber% %title%",
            "%artist% - %album%/%tracknumber% - %title%",
        ]
        tff_format = config.persist["tags_from_filenames_format"]
        if tff_format not in items:
            selected_index = 0
            if tff_format:
                items.insert(0, tff_format)
        else:
            selected_index = items.index(tff_format)
        self.ui.format.addItems(items)
        self.ui.format.setCurrentIndex(selected_index)
        self.ui.buttonbox.addButton(StandardButton(StandardButton.OK), QtWidgets.QDialogButtonBox.AcceptRole)
        self.ui.buttonbox.addButton(StandardButton(StandardButton.CANCEL), QtWidgets.QDialogButtonBox.RejectRole)
        self.ui.buttonbox.accepted.connect(self.accept)
        self.ui.buttonbox.rejected.connect(self.reject)
        self.ui.preview.clicked.connect(self.preview)
        self.ui.files.setHeaderLabels([_("File Name")])
        self.restoreWindowState()
        self.files = files
        self.items = []
        for file in files:
            item = QtWidgets.QTreeWidgetItem(self.ui.files)
            item.setText(0, os.path.basename(file.filename))
            self.items.append(item)
        self._tag_re = re.compile(r"(%\w+%)")
        self.numeric_tags = ('tracknumber', 'totaltracks', 'discnumber', 'totaldiscs')

    def parse_format(self):
        tff_format = self.ui.format.currentText()
        columns = []
        format_re = ['(?:^|/)']
        for part in self._tag_re.split(tff_format):
            if part.startswith('%') and part.endswith('%'):
                name = part[1:-1]
                columns.append(name)
                if name in self.numeric_tags:
                    format_re.append('(?P<' + name + r'>\d+)')
                elif name in ('date'):
                    format_re.append('(?P<' + name + r'>\d+(?:-\d+(?:-\d+)?)?)')
                else:
                    format_re.append('(?P<' + name + '>[^/]*?)')
            else:
                format_re.append(re.escape(part))
        format_re.append(r'\.(\w+)$')
        format_re = re.compile("".join(format_re))
        return format_re, columns

    def match_file(self, file, tff_format):
        match = tff_format.search(file.filename.replace('\\','/'))
        if match:
            result = {}
            for name, value in match.groupdict().items():
                value = value.strip()
                if name in self.numeric_tags:
                    value = value.lstrip("0")
                if self.ui.replace_underscores.isChecked():
                    value = value.replace('_', ' ')
                result[name] = value
            return result
        else:
            return {}

    def preview(self):
        tff_format, columns = self.parse_format()
        self.ui.files.setHeaderLabels([_("File Name")] + list(map(display_tag_name, columns)))
        for item, file in zip(self.items, self.files):
            matches = self.match_file(file, tff_format)
            for i, column in enumerate(columns):
                item.setText(i + 1, matches.get(column, ''))
        self.ui.files.header().resizeSections(QtWidgets.QHeaderView.ResizeToContents)
        self.ui.files.header().setStretchLastSection(True)

    def accept(self):
        tff_format, columns = self.parse_format()
        for file in self.files:
            metadata = self.match_file(file, tff_format)
            for name, value in metadata.items():
                file.metadata[name] = value
            file.update()
        config.persist["tags_from_filenames_format"] = self.ui.format.currentText()
        self.saveWindowState()
        QtWidgets.QDialog.accept(self)

    def reject(self):
        self.saveWindowState()
        QtWidgets.QDialog.reject(self)

    def closeEvent(self, event):
        self.saveWindowState()
        event.accept()

    def saveWindowState(self):
        pos = self.pos()
        if not pos.isNull():
            config.persist["tags_from_filenames_position"] = pos
        config.persist["tags_from_filenames_size"] = self.size()

    def restoreWindowState(self):
        pos = config.persist["tags_from_filenames_position"]
        if pos.x() > 0 and pos.y() > 0:
            self.move(pos)
        self.resize(config.persist["tags_from_filenames_size"])