diff --git a/src/calibre/gui2/dialogs/metadata_bulk.py b/src/calibre/gui2/dialogs/metadata_bulk.py index 2b70321539..4a6acf0a5e 100644 --- a/src/calibre/gui2/dialogs/metadata_bulk.py +++ b/src/calibre/gui2/dialogs/metadata_bulk.py @@ -12,6 +12,7 @@ from PyQt4 import QtGui from calibre.gui2.dialogs.metadata_bulk_ui import Ui_MetadataBulkDialog from calibre.gui2.dialogs.tag_editor import TagEditor from calibre.ebooks.metadata import string_to_authors, authors_to_string +from calibre.ebooks.metadata.book.base import composite_formatter from calibre.gui2.custom_column_widgets import populate_metadata_page from calibre.gui2 import error_dialog from calibre.gui2.progress_indicator import ProgressIndicator @@ -268,6 +269,7 @@ class MetadataBulkDialog(QDialog, Ui_MetadataBulkDialog): def prepare_search_and_replace(self): self.search_for.initialize('bulk_edit_search_for') self.replace_with.initialize('bulk_edit_replace_with') + self.s_r_template.initialize('bulk_edit_template') self.test_text.initialize('bulk_edit_test_test') self.all_fields = [''] self.writable_fields = [''] @@ -282,6 +284,7 @@ class MetadataBulkDialog(QDialog, Ui_MetadataBulkDialog): if f in ['sort'] or fm[f]['datatype'] == 'composite': self.all_fields.append(f) self.all_fields.sort() + self.all_fields.insert(1, '{template}') self.writable_fields.sort() self.search_field.setMaxVisibleItems(25) self.destination_field.setMaxVisibleItems(25) @@ -360,15 +363,21 @@ class MetadataBulkDialog(QDialog, Ui_MetadataBulkDialog): self.test_text.editTextChanged[str].connect(self.s_r_paint_results) self.comma_separated.stateChanged.connect(self.s_r_paint_results) self.case_sensitive.stateChanged.connect(self.s_r_paint_results) + self.s_r_template.lost_focus.connect(self.s_r_template_changed) self.central_widget.setCurrentIndex(0) self.search_for.completer().setCaseSensitivity(Qt.CaseSensitive) self.replace_with.completer().setCaseSensitivity(Qt.CaseSensitive) + self.s_r_template.completer().setCaseSensitivity(Qt.CaseSensitive) self.s_r_search_mode_changed(self.search_mode.currentIndex()) def s_r_get_field(self, mi, field): if field: + if field == '{template}': + v = composite_formatter.safe_format\ + (unicode(self.s_r_template.text()), mi, _('S/R TEMPLATE ERROR'), mi) + return [v] fm = self.db.metadata_for_field(field) if field == 'sort': val = mi.get('title_sort', None) @@ -384,7 +393,16 @@ class MetadataBulkDialog(QDialog, Ui_MetadataBulkDialog): val = [] return val + def s_r_template_changed(self): + self.s_r_search_field_changed(self.search_field.currentIndex()) + def s_r_search_field_changed(self, idx): + if self.search_mode.currentIndex() != 0 and idx == 1: # Template + self.s_r_template.setVisible(True) + self.template_label.setVisible(True) + else: + self.s_r_template.setVisible(False) + self.template_label.setVisible(False) for i in range(0, self.s_r_number_of_books): w = getattr(self, 'book_%d_text'%(i+1)) mi = self.db.get_metadata(self.ids[i], index_is_id=True) diff --git a/src/calibre/gui2/dialogs/metadata_bulk.ui b/src/calibre/gui2/dialogs/metadata_bulk.ui index ecb34d8e5b..8422c84ccb 100644 --- a/src/calibre/gui2/dialogs/metadata_bulk.ui +++ b/src/calibre/gui2/dialogs/metadata_bulk.ui @@ -501,6 +501,29 @@ Future conversion of these books will use the default settings. + + + Te&mplate: + + + s_r_template + + + + + + + + 100 + 0 + + + + Enter a template to be used as the source for the search/replace + + + + &Search for: @@ -510,7 +533,7 @@ Future conversion of these books will use the default settings. - + @@ -523,7 +546,7 @@ Future conversion of these books will use the default settings. - + Check this box if the search string must match exactly upper and lower case. Uncheck it if case is to be ignored @@ -536,7 +559,7 @@ Future conversion of these books will use the default settings. - + &Replace with: @@ -546,14 +569,14 @@ Future conversion of these books will use the default settings. - + The replacement text. The matched search text will be replaced with this string - + @@ -588,7 +611,7 @@ field is processed. In regular expression mode, only the matched text is process - + &Destination field: @@ -598,14 +621,15 @@ field is processed. In regular expression mode, only the matched text is process - + - The field that the text will be put into after all replacements. If blank, the source field is used. + The field that the text will be put into after all replacements. +If blank, the source field is used if the field is modifiable - + @@ -653,7 +677,7 @@ nothing should be put between the original text and the inserted text - + Test &text @@ -663,7 +687,7 @@ nothing should be put between the original text and the inserted text - + Test re&sult @@ -784,6 +808,7 @@ nothing should be put between the original text and the inserted text central_widget search_field search_mode + s_r_template search_for case_sensitive replace_with diff --git a/src/calibre/gui2/widgets.py b/src/calibre/gui2/widgets.py index 12d64bbbcd..8ca1df917c 100644 --- a/src/calibre/gui2/widgets.py +++ b/src/calibre/gui2/widgets.py @@ -524,6 +524,8 @@ class EnComboBox(QComboBox): class HistoryLineEdit(QComboBox): + lost_focus = pyqtSignal() + def __init__(self, *args): QComboBox.__init__(self, *args) self.setEditable(True) @@ -559,6 +561,10 @@ class HistoryLineEdit(QComboBox): def text(self): return self.currentText() + def focusOutEvent(self, e): + QComboBox.focusOutEvent(self, e) + self.lost_focus.emit() + class ComboBoxWithHelp(QComboBox): ''' A combobox where item 0 is help text. CurrentText will return '' for item 0.