From db5f63bcac8a0112022e4bafb54939804b1e1f1e Mon Sep 17 00:00:00 2001 From: bulislaw Date: Sat, 22 Jan 2011 17:44:09 +0000 Subject: [PATCH 1/4] Persistent Search & Replace query UI proposal --- src/calibre/gui2/dialogs/metadata_bulk.ui | 135 ++++++++++++++++++---- 1 file changed, 113 insertions(+), 22 deletions(-) diff --git a/src/calibre/gui2/dialogs/metadata_bulk.ui b/src/calibre/gui2/dialogs/metadata_bulk.ui index f8ae926be6..a1e1d8c550 100644 --- a/src/calibre/gui2/dialogs/metadata_bulk.ui +++ b/src/calibre/gui2/dialogs/metadata_bulk.ui @@ -44,8 +44,8 @@ 0 0 - 842 - 589 + 832 + 574 @@ -55,7 +55,7 @@ - 0 + 2 @@ -574,7 +574,7 @@ Future conversion of these books will use the default settings. QLayout::SetMinimumSize - + true @@ -591,7 +591,7 @@ Future conversion of these books will use the default settings. - + Search &field: @@ -601,14 +601,14 @@ Future conversion of these books will use the default settings. - + The name of the field that you want to search - + @@ -642,7 +642,7 @@ Future conversion of these books will use the default settings. - + Te&mplate: @@ -652,7 +652,7 @@ Future conversion of these books will use the default settings. - + @@ -665,7 +665,7 @@ Future conversion of these books will use the default settings. - + &Search for: @@ -675,7 +675,7 @@ Future conversion of these books will use the default settings. - + @@ -688,7 +688,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 @@ -701,7 +701,7 @@ Future conversion of these books will use the default settings. - + &Replace with: @@ -711,14 +711,14 @@ Future conversion of these books will use the default settings. - + The replacement text. The matched search text will be replaced with this string - + @@ -753,7 +753,7 @@ field is processed. In regular expression mode, only the matched text is process - + &Destination field: @@ -763,7 +763,7 @@ 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. @@ -771,7 +771,7 @@ If blank, the source field is used if the field is modifiable - + @@ -820,7 +820,7 @@ not multiple and the destination field is multiple - + @@ -906,7 +906,7 @@ not multiple and the destination field is multiple - + QFrame::NoFrame @@ -919,8 +919,8 @@ not multiple and the destination field is multiple 0 0 - 197 - 60 + 810 + 264 @@ -968,6 +968,77 @@ not multiple and the destination field is multiple + + + + Load query: + + + search_field + + + + + + + The name of the field that you want to search + + + + + + + Qt::Horizontal + + + + + + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 20 + 20 + + + + + + + + Save + + + + + + + Remove + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + @@ -1030,6 +1101,9 @@ not multiple and the destination field is multiple series_numbering_restarts series_start_number button_box + query_field + save_button + remove_button search_field search_mode s_r_template @@ -1045,6 +1119,23 @@ not multiple and the destination field is multiple multiple_separator test_text test_result + scrollArea + central_widget + swap_title_and_author + clear_series + adddate + clear_adddate_button + apply_adddate + pubdate + clear_pubdate_button + apply_pubdate + remove_format + change_title_to_title_case + remove_conversion_settings + cover_generate + cover_remove + cover_from_fmt + scrollArea11 From f202d4b99d8a617442fee7d41ad2c5bd2f29c0c5 Mon Sep 17 00:00:00 2001 From: bulislaw Date: Sun, 23 Jan 2011 21:57:48 +0000 Subject: [PATCH 2/4] Add saving/loading search and replace queries --- src/calibre/gui2/dialogs/metadata_bulk.py | 119 +++++++++++++++++++++- src/calibre/gui2/dialogs/metadata_bulk.ui | 8 +- 2 files changed, 124 insertions(+), 3 deletions(-) diff --git a/src/calibre/gui2/dialogs/metadata_bulk.py b/src/calibre/gui2/dialogs/metadata_bulk.py index 6e6b553dba..1f7a8ac16c 100644 --- a/src/calibre/gui2/dialogs/metadata_bulk.py +++ b/src/calibre/gui2/dialogs/metadata_bulk.py @@ -6,7 +6,8 @@ __copyright__ = '2008, Kovid Goyal ' import re, os from PyQt4.Qt import Qt, QDialog, QGridLayout, QVBoxLayout, QFont, QLabel, \ - pyqtSignal, QDialogButtonBox + pyqtSignal, QDialogButtonBox, QInputDialog, QLineEdit, \ + QMessageBox from PyQt4 import QtGui from calibre.gui2.dialogs.metadata_bulk_ui import Ui_MetadataBulkDialog @@ -17,7 +18,7 @@ from calibre.ebooks.metadata.meta import get_metadata from calibre.gui2.custom_column_widgets import populate_metadata_page from calibre.gui2 import error_dialog, ResizableDialog, UNDEFINED_QDATE from calibre.gui2.progress_indicator import ProgressIndicator -from calibre.utils.config import dynamic +from calibre.utils.config import dynamic, JSONConfig from calibre.utils.titlecase import titlecase from calibre.utils.icu import sort_key, capitalize from calibre.utils.config import prefs, tweaks @@ -451,6 +452,18 @@ class MetadataBulkDialog(ResizableDialog, Ui_MetadataBulkDialog): self.results_count.valueChanged[int].connect(self.s_r_display_bounds_changed) self.starting_from.valueChanged[int].connect(self.s_r_display_bounds_changed) + self.save_button.clicked.connect(self.save_query) + self.remove_button.clicked.connect(self.remove_query) + self.query_field.currentIndexChanged[str].connect(self.query_change) + + self.queries = JSONConfig("queries") + + self.query_field.addItem("") + for item in self.queries: + self.query_field.addItem(item) + + self.query_field.setCurrentIndex(0) + def s_r_get_field(self, mi, field): if field: if field == '{template}': @@ -862,3 +875,105 @@ class MetadataBulkDialog(ResizableDialog, Ui_MetadataBulkDialog): def series_changed(self, *args): self.write_series = True + def remove_query(self, *args): + if not self.query_field.currentText(): + return + + ret = QMessageBox.question(self, _("Delete query"), + _("Selected query will be deleted. Are You sure?"), + QMessageBox.Ok, QMessageBox.Cancel) + + if ret == QMessageBox.Cancel: + return + + item_id = self.query_field.currentIndex() + item_name = self.query_field.currentText() + + self.query_field.removeItem(item_id) + + if item_name in self.queries.keys(): + del(self.queries[str(item_name)]) + self.queries.commit() + + def save_query(self, *args): + query = {} + query['name'], ok = QInputDialog.getText(self, _('Save query'), + _('Query name:')) + if not ok: + return + query['name'] = str(query['name']) + + new = True + if query['name'] in self.queries.keys(): + ret = QMessageBox.question(self, _("Save query"), + _("Query already exists, old one would be overwritten." \ + " Are You sure?"), + QMessageBox.Ok, QMessageBox.Cancel) + if ret == QMessageBox.Cancel: + return + new = False + + query['search_field'] = str(self.search_field.currentText()) + query['search_mode'] = str(self.search_mode.currentText()) + query['s_r_template'] = str(self.s_r_template.text()) + query['search_for'] = str(self.search_for.text()) + query['case_sensitive'] = self.case_sensitive.isChecked() + query['replace_with'] = str(self.replace_with.text()) + query['replace_func'] = str(self.replace_func.currentText()) + query['destination_field'] = str(self.destination_field. \ + currentText()) + query['replace_mode'] = str(self.replace_mode.currentText()) + query['comma_separated'] = self.comma_separated.isChecked() + query['results_count'] = self.results_count.value() + query['starting_from'] = self.starting_from.value() + query['multiple_separator'] = str(self.multiple_separator.text()) + + self.queries[query['name']] = query + self.queries.commit() + + if new: + self.query_field.addItem(query['name']) + self.query_field.setCurrentIndex(self.query_field.findText(query['name'])) + + def query_change(self, item_name): + item = self.queries.get(str(item_name), None) + if item is None: + self.reset_query_fields() + return + + self.search_field.setCurrentIndex( + self.search_field.findText(item['search_field'])) + self.search_mode.setEditText(item['search_mode']) + self.search_mode.setCurrentIndex( + self.search_mode.findText(item['search_mode'])) + self.s_r_template.setText(item['search_mode']) + self.search_for.setText(item['search_for']) + self.case_sensitive.setChecked(item['case_sensitive']) + self.replace_with.setText(item['replace_with']) + self.replace_func.setCurrentIndex( + self.replace_func.findText(item['replace_func'])) + self.destination_field.setCurrentIndex( + self.destination_field.findText(item['destination_field'])) + self.replace_mode.setCurrentIndex( + self.replace_mode.findText(item['replace_mode'])) + self.comma_separated.setChecked(item['comma_separated']) + self.results_count.setValue(int(item['results_count'])) + self.starting_from.setValue(int(item['starting_from'])) + self.multiple_separator.setText(item['multiple_separator']) + + def reset_query_fields(self): + self.search_field.setCurrentIndex(0) + self.search_mode.setEditText("") + self.search_mode.setCurrentIndex(0) + self.s_r_template.setText("") + self.search_for.setText("") + self.case_sensitive.setChecked(False) + self.replace_with.setText("") + self.replace_func.setCurrentIndex(0) + self.destination_field.setCurrentIndex(0) + self.replace_mode.setCurrentIndex(0) + self.comma_separated.setChecked(True) + self.results_count.setValue(999) + self.starting_from.setValue(1) + self.multiple_separator.setText(" ::: ") + diff --git a/src/calibre/gui2/dialogs/metadata_bulk.ui b/src/calibre/gui2/dialogs/metadata_bulk.ui index a1e1d8c550..04bf9e364c 100644 --- a/src/calibre/gui2/dialogs/metadata_bulk.ui +++ b/src/calibre/gui2/dialogs/metadata_bulk.ui @@ -981,7 +981,7 @@ not multiple and the destination field is multiple - The name of the field that you want to search + Select query to load. @@ -1012,6 +1012,9 @@ not multiple and the destination field is multiple + + Save current query. + Save @@ -1019,6 +1022,9 @@ not multiple and the destination field is multiple + + Remove loadded query. + Remove From 65e6102e3317d3e20d118837eff41efbd3e28b2e Mon Sep 17 00:00:00 2001 From: Charles Haley <> Date: Mon, 24 Jan 2011 09:15:05 +0000 Subject: [PATCH 3/4] Add right-click category search support to the tags browser --- src/calibre/gui2/tag_view.py | 14 +++++++++++++- src/calibre/library/caches.py | 25 ++++++++++++++++++++++++- src/calibre/library/database2.py | 2 +- src/calibre/library/field_metadata.py | 11 +++++++---- 4 files changed, 45 insertions(+), 7 deletions(-) diff --git a/src/calibre/gui2/tag_view.py b/src/calibre/gui2/tag_view.py index d68be3b7d6..8b574948ff 100644 --- a/src/calibre/gui2/tag_view.py +++ b/src/calibre/gui2/tag_view.py @@ -186,7 +186,7 @@ class TagsView(QTreeView): # {{{ self.clear() def context_menu_handler(self, action=None, category=None, - key=None, index=None): + key=None, index=None, negate=None): if not action: return try: @@ -199,6 +199,9 @@ class TagsView(QTreeView): # {{{ if action == 'manage_categories': self.user_category_edit.emit(category) return + if action == 'search_category': + self.tags_marked.emit(category + ':' + str(not negate)) + return if action == 'manage_searches': self.saved_search_edit.emit(category) return @@ -268,6 +271,15 @@ class TagsView(QTreeView): # {{{ m.addAction(col, partial(self.context_menu_handler, action='show', category=col)) + # search by category + self.context_menu.addAction( + _('Search for books in category %s')%category, + partial(self.context_menu_handler, action='search_category', + category=key, negate=False)) + self.context_menu.addAction( + _('Search for books not in category %s')%category, + partial(self.context_menu_handler, action='search_category', + category=key, negate=True)) # Offer specific editors for tags/series/publishers/saved searches self.context_menu.addSeparator() if key in ['tags', 'publisher', 'series'] or \ diff --git a/src/calibre/library/caches.py b/src/calibre/library/caches.py index 291d71f572..9f10d9f890 100644 --- a/src/calibre/library/caches.py +++ b/src/calibre/library/caches.py @@ -172,8 +172,9 @@ class ResultCache(SearchQueryParser): # {{{ ''' Stores sorted and filtered metadata in memory. ''' - def __init__(self, FIELD_MAP, field_metadata): + def __init__(self, FIELD_MAP, field_metadata, db_prefs = None): self.FIELD_MAP = FIELD_MAP + self.db_prefs = db_prefs self.composites = {} for key in field_metadata: if field_metadata[key]['datatype'] == 'composite': @@ -405,6 +406,22 @@ class ResultCache(SearchQueryParser): # {{{ matches.add(item[0]) return matches + def get_user_category_matches(self, location, query, candidates): + res = set([]) + if self.db_prefs is None: + return res + user_cats = self.db_prefs['user_categories'] + if location not in user_cats: + return res + c = set(candidates) + for (item, category, ign) in user_cats[location]: + s = self.get_matches(category, '=' + item, candidates=c) + c -= s + res |= s + if query == 'false': + return candidates - res + return res + def get_matches(self, location, query, allow_recursion=True, candidates=None): matches = set([]) if candidates is None: @@ -443,6 +460,10 @@ class ResultCache(SearchQueryParser): # {{{ return self.get_numeric_matches(location, query[1:], candidates, val_func=vf) + # check for user categories + if len(location) >= 2 and location.startswith('@'): + return self.get_user_category_matches(location[1:], query.lower(), + candidates) # everything else, or 'all' matches matchkind = CONTAINS_MATCH if (len(query) > 1): @@ -468,6 +489,8 @@ class ResultCache(SearchQueryParser): # {{{ for x in range(len(self.FIELD_MAP)): col_datatype.append('') for x in self.field_metadata: + if x.startswith('@'): + continue if len(self.field_metadata[x]['search_terms']): db_col[x] = self.field_metadata[x]['rec_index'] if self.field_metadata[x]['datatype'] not in \ diff --git a/src/calibre/library/database2.py b/src/calibre/library/database2.py index 5638bad1ee..f2b2c94e31 100644 --- a/src/calibre/library/database2.py +++ b/src/calibre/library/database2.py @@ -332,7 +332,7 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns): traceback.print_exc() self.book_on_device_func = None - self.data = ResultCache(self.FIELD_MAP, self.field_metadata) + self.data = ResultCache(self.FIELD_MAP, self.field_metadata, db_prefs=self.prefs) self.search = self.data.search self.search_getting_ids = self.data.search_getting_ids self.refresh = functools.partial(self.data.refresh, self) diff --git a/src/calibre/library/field_metadata.py b/src/calibre/library/field_metadata.py index e9402d1227..78fe899fa8 100644 --- a/src/calibre/library/field_metadata.py +++ b/src/calibre/library/field_metadata.py @@ -475,6 +475,8 @@ class FieldMetadata(dict): val = self._tb_cats[key] if val['is_category'] and val['kind'] in ('user', 'search'): del self._tb_cats[key] + if key in self._search_term_map: + del self._search_term_map[key] def cc_series_index_column_for(self, key): return self._tb_cats[key]['rec_index'] + 1 @@ -482,11 +484,12 @@ class FieldMetadata(dict): def add_user_category(self, label, name): if label in self._tb_cats: raise ValueError('Duplicate user field [%s]'%(label)) - self._tb_cats[label] = {'table':None, 'column':None, - 'datatype':None, 'is_multiple':None, - 'kind':'user', 'name':name, - 'search_terms':[], 'is_custom':False, + self._tb_cats[label] = {'table':None, 'column':None, + 'datatype':None, 'is_multiple':None, + 'kind':'user', 'name':name, + 'search_terms':[label],'is_custom':False, 'is_category':True} + self._add_search_terms_to_map(label, [label]) def add_search_category(self, label, name): if label in self._tb_cats: From 2012f5cc0a28a322b41ee43bfe6bea579f0a8773 Mon Sep 17 00:00:00 2001 From: Charles Haley <> Date: Mon, 24 Jan 2011 11:15:57 +0000 Subject: [PATCH 4/4] Saved queries after review --- src/calibre/gui2/dialogs/metadata_bulk.py | 119 +++++++------- src/calibre/gui2/dialogs/metadata_bulk.ui | 190 +++++++++++----------- 2 files changed, 159 insertions(+), 150 deletions(-) diff --git a/src/calibre/gui2/dialogs/metadata_bulk.py b/src/calibre/gui2/dialogs/metadata_bulk.py index dc801a048e..3944bdbe18 100644 --- a/src/calibre/gui2/dialogs/metadata_bulk.py +++ b/src/calibre/gui2/dialogs/metadata_bulk.py @@ -452,16 +452,13 @@ class MetadataBulkDialog(ResizableDialog, Ui_MetadataBulkDialog): self.results_count.valueChanged[int].connect(self.s_r_display_bounds_changed) self.starting_from.valueChanged[int].connect(self.s_r_display_bounds_changed) - self.save_button.clicked.connect(self.save_query) - self.remove_button.clicked.connect(self.remove_query) - self.query_field.currentIndexChanged[str].connect(self.query_change) - - self.queries = JSONConfig("queries") + self.save_button.clicked.connect(self.s_r_save_query) + self.remove_button.clicked.connect(self.s_r_remove_query) + self.queries = JSONConfig("search_replace_queries") self.query_field.addItem("") - for item in self.queries: - self.query_field.addItem(item) - + self.query_field.addItems(sorted([q for q in self.queries], key=sort_key)) + self.query_field.currentIndexChanged[str].connect(self.s_r_query_change) self.query_field.setCurrentIndex(0) def s_r_get_field(self, mi, field): @@ -875,96 +872,108 @@ class MetadataBulkDialog(ResizableDialog, Ui_MetadataBulkDialog): def series_changed(self, *args): self.write_series = True - def remove_query(self, *args): - if not self.query_field.currentText(): + def s_r_remove_query(self, *args): + if self.query_field.currentIndex() == 0: return - ret = QMessageBox.question(self, _("Delete query"), - _("Selected query will be deleted. Are You sure?"), + ret = QMessageBox.question(self, _("Delete saved search/replace"), + _("The selected saved search/replace will be deleted. " + "Are you sure?"), QMessageBox.Ok, QMessageBox.Cancel) if ret == QMessageBox.Cancel: return item_id = self.query_field.currentIndex() - item_name = self.query_field.currentText() - + item_name = unicode(self.query_field.currentText()) + + self.query_field.blockSignals(True) self.query_field.removeItem(item_id) + self.query_field.blockSignals(False) + self.query_field.setCurrentIndex(0) if item_name in self.queries.keys(): - del(self.queries[str(item_name)]) + del(self.queries[item_name]) self.queries.commit() - def save_query(self, *args): - query = {} - query['name'], ok = QInputDialog.getText(self, _('Save query'), - _('Query name:')) + def s_r_save_query(self, *args): + name, ok = QInputDialog.getText(self, _('Save search/replace'), + _('Search/replace name:')) if not ok: return - query['name'] = str(query['name']) new = True - if query['name'] in self.queries.keys(): - ret = QMessageBox.question(self, _("Save query"), - _("Query already exists, old one would be overwritten." \ - " Are You sure?"), + name = unicode(name) + if name in self.queries.keys(): + ret = QMessageBox.question(self, _("Save search/replace"), + _("That saved search/replace already exists and will be overwritten. " + "Are you sure?"), QMessageBox.Ok, QMessageBox.Cancel) if ret == QMessageBox.Cancel: return new = False - query['search_field'] = str(self.search_field.currentText()) - query['search_mode'] = str(self.search_mode.currentText()) - query['s_r_template'] = str(self.s_r_template.text()) - query['search_for'] = str(self.search_for.text()) + query = {} + query['name'] = name + query['search_field'] = unicode(self.search_field.currentText()) + query['search_mode'] = unicode(self.search_mode.currentText()) + query['s_r_template'] = unicode(self.s_r_template.text()) + query['search_for'] = unicode(self.search_for.text()) query['case_sensitive'] = self.case_sensitive.isChecked() - query['replace_with'] = str(self.replace_with.text()) - query['replace_func'] = str(self.replace_func.currentText()) - query['destination_field'] = str(self.destination_field. \ - currentText()) - query['replace_mode'] = str(self.replace_mode.currentText()) + query['replace_with'] = unicode(self.replace_with.text()) + query['replace_func'] = unicode(self.replace_func.currentText()) + query['destination_field'] = unicode(self.destination_field.currentText()) + query['replace_mode'] = unicode(self.replace_mode.currentText()) query['comma_separated'] = self.comma_separated.isChecked() query['results_count'] = self.results_count.value() query['starting_from'] = self.starting_from.value() - query['multiple_separator'] = str(self.multiple_separator.text()) + query['multiple_separator'] = unicode(self.multiple_separator.text()) - self.queries[query['name']] = query + self.queries[name] = query self.queries.commit() if new: - self.query_field.addItem(query['name']) - self.query_field.setCurrentIndex(self.query_field.findText(query['name'])) + self.query_field.blockSignals(True) + self.query_field.clear() + self.query_field.addItem('') + self.query_field.addItems(sorted([q for q in self.queries], key=sort_key)) + self.query_field.blockSignals(False) + self.query_field.setCurrentIndex(self.query_field.findText(name)) - def query_change(self, item_name): - item = self.queries.get(str(item_name), None) + def s_r_query_change(self, item_name): + if not item_name: + self.s_r_reset_query_fields() + return + item = self.queries.get(unicode(item_name), None) if item is None: - self.reset_query_fields() + self.s_r_reset_query_fields() return - self.search_field.setCurrentIndex( - self.search_field.findText(item['search_field'])) - self.search_mode.setEditText(item['search_mode']) - self.search_mode.setCurrentIndex( - self.search_mode.findText(item['search_mode'])) - self.s_r_template.setText(item['search_mode']) + def set_index(attr, txt): + try: + attr.setCurrentIndex(attr.findText(txt)) + except: + attr.setCurrentIndex(0) + + set_index(self.search_mode, item['search_mode']) + set_index(self.search_field, item['search_field']) + self.s_r_template.setText(item['s_r_template']) + self.s_r_template_changed() #simulate gain/loss of focus self.search_for.setText(item['search_for']) self.case_sensitive.setChecked(item['case_sensitive']) self.replace_with.setText(item['replace_with']) - self.replace_func.setCurrentIndex( - self.replace_func.findText(item['replace_func'])) - self.destination_field.setCurrentIndex( - self.destination_field.findText(item['destination_field'])) - self.replace_mode.setCurrentIndex( - self.replace_mode.findText(item['replace_mode'])) + set_index(self.replace_func, item['replace_func']) + set_index(self.destination_field, item['destination_field']) + set_index(self.replace_mode, item['replace_mode']) self.comma_separated.setChecked(item['comma_separated']) self.results_count.setValue(int(item['results_count'])) self.starting_from.setValue(int(item['starting_from'])) self.multiple_separator.setText(item['multiple_separator']) - def reset_query_fields(self): + def s_r_reset_query_fields(self): + # Don't reset the search mode. The user will probably want to use it + # as it was self.search_field.setCurrentIndex(0) - self.search_mode.setEditText("") - self.search_mode.setCurrentIndex(0) self.s_r_template.setText("") self.search_for.setText("") self.case_sensitive.setChecked(False) diff --git a/src/calibre/gui2/dialogs/metadata_bulk.ui b/src/calibre/gui2/dialogs/metadata_bulk.ui index 04bf9e364c..3d64a89bb8 100644 --- a/src/calibre/gui2/dialogs/metadata_bulk.ui +++ b/src/calibre/gui2/dialogs/metadata_bulk.ui @@ -574,7 +574,7 @@ Future conversion of these books will use the default settings. QLayout::SetMinimumSize - + true @@ -584,14 +584,91 @@ Future conversion of these books will use the default settings. - + - + + + + Qt::Horizontal + + + + + + + Load searc&h/replace: + + + search_field + + + + + + + Select saved search/replace to load. + + + + + + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 20 + 20 + + + + + + + + Save current search/replace + + + Sa&ve + + + + + + + Delete saved search/replace + + + Delete + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + Search &field: @@ -601,14 +678,14 @@ Future conversion of these books will use the default settings. - + The name of the field that you want to search - + @@ -642,7 +719,7 @@ Future conversion of these books will use the default settings. - + Te&mplate: @@ -652,7 +729,7 @@ Future conversion of these books will use the default settings. - + @@ -665,7 +742,7 @@ Future conversion of these books will use the default settings. - + &Search for: @@ -675,7 +752,7 @@ Future conversion of these books will use the default settings. - + @@ -688,7 +765,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 @@ -701,7 +778,7 @@ Future conversion of these books will use the default settings. - + &Replace with: @@ -711,14 +788,14 @@ Future conversion of these books will use the default settings. - + The replacement text. The matched search text will be replaced with this string - + @@ -753,7 +830,7 @@ field is processed. In regular expression mode, only the matched text is process - + &Destination field: @@ -763,7 +840,7 @@ 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. @@ -771,7 +848,7 @@ If blank, the source field is used if the field is modifiable - + @@ -820,7 +897,7 @@ not multiple and the destination field is multiple - + @@ -906,7 +983,7 @@ not multiple and the destination field is multiple - + QFrame::NoFrame @@ -968,83 +1045,6 @@ not multiple and the destination field is multiple - - - - Load query: - - - search_field - - - - - - - Select query to load. - - - - - - - Qt::Horizontal - - - - - - - - - Qt::Horizontal - - - QSizePolicy::Fixed - - - - 20 - 20 - - - - - - - - Save current query. - - - Save - - - - - - - Remove loadded query. - - - Remove - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - -