mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Search replace: Add ability to manipulate number and boolean columns. Add type ahead completion to the advanced search dialog. Fixes #8035 (Advanced Search, Titel/Author?series/Tag - Type Ahead Word Lists)
This commit is contained in:
parent
2787419445
commit
7e309d5d28
@ -321,7 +321,8 @@ class MetadataBulkDialog(QDialog, Ui_MetadataBulkDialog):
|
|||||||
if (f in ['author_sort'] or
|
if (f in ['author_sort'] or
|
||||||
(fm[f]['datatype'] in ['text', 'series', 'enumeration']
|
(fm[f]['datatype'] in ['text', 'series', 'enumeration']
|
||||||
and fm[f].get('search_terms', None)
|
and fm[f].get('search_terms', None)
|
||||||
and f not in ['formats', 'ondevice', 'sort'])):
|
and f not in ['formats', 'ondevice', 'sort']) or
|
||||||
|
fm[f]['datatype'] in ['int', 'float', 'bool'] ):
|
||||||
self.all_fields.append(f)
|
self.all_fields.append(f)
|
||||||
self.writable_fields.append(f)
|
self.writable_fields.append(f)
|
||||||
if f in ['sort'] or fm[f]['datatype'] == 'composite':
|
if f in ['sort'] or fm[f]['datatype'] == 'composite':
|
||||||
@ -431,6 +432,8 @@ class MetadataBulkDialog(QDialog, Ui_MetadataBulkDialog):
|
|||||||
val = mi.get('title_sort', None)
|
val = mi.get('title_sort', None)
|
||||||
else:
|
else:
|
||||||
val = mi.get(field, None)
|
val = mi.get(field, None)
|
||||||
|
if isinstance(val, (int, float, bool)):
|
||||||
|
val = str(val)
|
||||||
if val is None:
|
if val is None:
|
||||||
val = [] if fm['is_multiple'] else ['']
|
val = [] if fm['is_multiple'] else ['']
|
||||||
elif not fm['is_multiple']:
|
elif not fm['is_multiple']:
|
||||||
|
@ -3,7 +3,7 @@ __copyright__ = '2008, Kovid Goyal <kovid at kovidgoyal.net>'
|
|||||||
|
|
||||||
import re, copy
|
import re, copy
|
||||||
|
|
||||||
from PyQt4.QtGui import QDialog, QDialogButtonBox
|
from PyQt4.Qt import QDialog, QDialogButtonBox, QCompleter, Qt
|
||||||
|
|
||||||
from calibre.gui2.dialogs.search_ui import Ui_Dialog
|
from calibre.gui2.dialogs.search_ui import Ui_Dialog
|
||||||
from calibre.library.caches import CONTAINS_MATCH, EQUALS_MATCH
|
from calibre.library.caches import CONTAINS_MATCH, EQUALS_MATCH
|
||||||
@ -22,6 +22,28 @@ class SearchDialog(QDialog, Ui_Dialog):
|
|||||||
key=lambda x: sort_key(x if x[0] != '#' else x[1:]))
|
key=lambda x: sort_key(x if x[0] != '#' else x[1:]))
|
||||||
self.general_combo.addItems(searchables)
|
self.general_combo.addItems(searchables)
|
||||||
|
|
||||||
|
all_authors = db.all_authors()
|
||||||
|
all_authors.sort(key=lambda x : sort_key(x[1]))
|
||||||
|
for i in all_authors:
|
||||||
|
id, name = i
|
||||||
|
name = name.strip().replace('|', ',')
|
||||||
|
self.authors_box.addItem(name)
|
||||||
|
self.authors_box.setEditText('')
|
||||||
|
self.authors_box.completer().setCompletionMode(QCompleter.PopupCompletion)
|
||||||
|
self.authors_box.setAutoCompletionCaseSensitivity(Qt.CaseInsensitive)
|
||||||
|
|
||||||
|
all_series = db.all_series()
|
||||||
|
all_series.sort(key=lambda x : sort_key(x[1]))
|
||||||
|
for i in all_series:
|
||||||
|
id, name = i
|
||||||
|
self.series_box.addItem(name)
|
||||||
|
self.series_box.setEditText('')
|
||||||
|
self.series_box.completer().setCompletionMode(QCompleter.PopupCompletion)
|
||||||
|
self.series_box.setAutoCompletionCaseSensitivity(Qt.CaseInsensitive)
|
||||||
|
|
||||||
|
all_tags = db.all_tags()
|
||||||
|
self.tags_box.update_tags_cache(all_tags)
|
||||||
|
|
||||||
self.box_last_values = copy.deepcopy(box_values)
|
self.box_last_values = copy.deepcopy(box_values)
|
||||||
if self.box_last_values:
|
if self.box_last_values:
|
||||||
for k,v in self.box_last_values.items():
|
for k,v in self.box_last_values.items():
|
||||||
@ -121,26 +143,34 @@ class SearchDialog(QDialog, Ui_Dialog):
|
|||||||
return tok
|
return tok
|
||||||
|
|
||||||
def box_search_string(self):
|
def box_search_string(self):
|
||||||
|
mk = self.matchkind.currentIndex()
|
||||||
|
if mk == CONTAINS_MATCH:
|
||||||
|
self.mc = ''
|
||||||
|
elif mk == EQUALS_MATCH:
|
||||||
|
self.mc = '='
|
||||||
|
else:
|
||||||
|
self.mc = '~'
|
||||||
|
|
||||||
ans = []
|
ans = []
|
||||||
self.box_last_values = {}
|
self.box_last_values = {}
|
||||||
title = unicode(self.title_box.text()).strip()
|
title = unicode(self.title_box.text()).strip()
|
||||||
self.box_last_values['title_box'] = title
|
self.box_last_values['title_box'] = title
|
||||||
if title:
|
if title:
|
||||||
ans.append('title:"' + title + '"')
|
ans.append('title:"' + self.mc + title + '"')
|
||||||
author = unicode(self.authors_box.text()).strip()
|
author = unicode(self.authors_box.text()).strip()
|
||||||
self.box_last_values['authors_box'] = author
|
self.box_last_values['authors_box'] = author
|
||||||
if author:
|
if author:
|
||||||
ans.append('author:"' + author + '"')
|
ans.append('author:"' + self.mc + author + '"')
|
||||||
series = unicode(self.series_box.text()).strip()
|
series = unicode(self.series_box.text()).strip()
|
||||||
self.box_last_values['series_box'] = series
|
self.box_last_values['series_box'] = series
|
||||||
if series:
|
if series:
|
||||||
ans.append('series:"' + series + '"')
|
ans.append('series:"' + self.mc + series + '"')
|
||||||
self.mc = '='
|
|
||||||
tags = unicode(self.tags_box.text())
|
tags = unicode(self.tags_box.text())
|
||||||
self.box_last_values['tags_box'] = tags
|
self.box_last_values['tags_box'] = tags
|
||||||
tags = self.tokens(tags)
|
tags = [t.strip() for t in tags.split(',') if t.strip()]
|
||||||
if tags:
|
if tags:
|
||||||
tags = ['tags:' + t for t in tags]
|
tags = ['tags:"=' + t + '"' for t in tags]
|
||||||
ans.append('(' + ' or '.join(tags) + ')')
|
ans.append('(' + ' or '.join(tags) + ')')
|
||||||
general = unicode(self.general_box.text())
|
general = unicode(self.general_box.text())
|
||||||
self.box_last_values['general_box'] = general
|
self.box_last_values['general_box'] = general
|
||||||
|
@ -21,7 +21,7 @@
|
|||||||
<item row="0" column="0">
|
<item row="0" column="0">
|
||||||
<widget class="QLabel" name="label_5">
|
<widget class="QLabel" name="label_5">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>What kind of match to use:</string>
|
<string>&What kind of match to use:</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="buddy">
|
<property name="buddy">
|
||||||
<cstring>matchkind</cstring>
|
<cstring>matchkind</cstring>
|
||||||
@ -228,7 +228,7 @@
|
|||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="1" column="1">
|
<item row="1" column="1">
|
||||||
<widget class="QLineEdit" name="title_box">
|
<widget class="EnLineEdit" name="title_box">
|
||||||
<property name="toolTip">
|
<property name="toolTip">
|
||||||
<string>Enter the title.</string>
|
<string>Enter the title.</string>
|
||||||
</property>
|
</property>
|
||||||
@ -265,21 +265,21 @@
|
|||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="2" column="1">
|
<item row="2" column="1">
|
||||||
<widget class="QLineEdit" name="authors_box">
|
<widget class="EnComboBox" name="authors_box">
|
||||||
<property name="toolTip">
|
<property name="toolTip">
|
||||||
<string>Enter an author's name. Only one author can be used.</string>
|
<string>Enter an author's name. Only one author can be used.</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="3" column="1">
|
<item row="3" column="1">
|
||||||
<widget class="QLineEdit" name="series_box">
|
<widget class="EnComboBox" name="series_box">
|
||||||
<property name="toolTip">
|
<property name="toolTip">
|
||||||
<string>Enter a series name, without an index. Only one series name can be used.</string>
|
<string>Enter a series name, without an index. Only one series name can be used.</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="4" column="1">
|
<item row="4" column="1">
|
||||||
<widget class="QLineEdit" name="tags_box">
|
<widget class="TagsLineEdit" name="tags_box">
|
||||||
<property name="toolTip">
|
<property name="toolTip">
|
||||||
<string>Enter tags separated by spaces</string>
|
<string>Enter tags separated by spaces</string>
|
||||||
</property>
|
</property>
|
||||||
@ -348,6 +348,23 @@
|
|||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
|
<customwidgets>
|
||||||
|
<customwidget>
|
||||||
|
<class>EnLineEdit</class>
|
||||||
|
<extends>QLineEdit</extends>
|
||||||
|
<header>widgets.h</header>
|
||||||
|
</customwidget>
|
||||||
|
<customwidget>
|
||||||
|
<class>EnComboBox</class>
|
||||||
|
<extends>QComboBox</extends>
|
||||||
|
<header>widgets.h</header>
|
||||||
|
</customwidget>
|
||||||
|
<customwidget>
|
||||||
|
<class>TagsLineEdit</class>
|
||||||
|
<extends>QLineEdit</extends>
|
||||||
|
<header>widgets.h</header>
|
||||||
|
</customwidget>
|
||||||
|
</customwidgets>
|
||||||
<tabstops>
|
<tabstops>
|
||||||
<tabstop>all</tabstop>
|
<tabstop>all</tabstop>
|
||||||
<tabstop>phrase</tabstop>
|
<tabstop>phrase</tabstop>
|
||||||
|
@ -133,6 +133,14 @@ class CustomColumns(object):
|
|||||||
|
|
||||||
def adapt_bool(x, d):
|
def adapt_bool(x, d):
|
||||||
if isinstance(x, (str, unicode, bytes)):
|
if isinstance(x, (str, unicode, bytes)):
|
||||||
|
x = x.lower()
|
||||||
|
if x == 'true':
|
||||||
|
x = True
|
||||||
|
elif x == 'false':
|
||||||
|
x = False
|
||||||
|
elif x == 'none':
|
||||||
|
x = None
|
||||||
|
else:
|
||||||
x = bool(int(x))
|
x = bool(int(x))
|
||||||
return x
|
return x
|
||||||
|
|
||||||
@ -142,9 +150,17 @@ class CustomColumns(object):
|
|||||||
v = None
|
v = None
|
||||||
return v
|
return v
|
||||||
|
|
||||||
|
def adapt_number(x, d):
|
||||||
|
if isinstance(x, (str, unicode, bytes)):
|
||||||
|
if x.lower() == 'none':
|
||||||
|
return None
|
||||||
|
if d['datatype'] == 'int':
|
||||||
|
return int(x)
|
||||||
|
return float(x)
|
||||||
|
|
||||||
self.custom_data_adapters = {
|
self.custom_data_adapters = {
|
||||||
'float': lambda x,d : x if x is None else float(x),
|
'float': adapt_number,
|
||||||
'int': lambda x,d : x if x is None else int(x),
|
'int': adapt_number,
|
||||||
'rating':lambda x,d : x if x is None else min(10., max(0., float(x))),
|
'rating':lambda x,d : x if x is None else min(10., max(0., float(x))),
|
||||||
'bool': adapt_bool,
|
'bool': adapt_bool,
|
||||||
'comments': lambda x,d: adapt_text(x, {'is_multiple':False}),
|
'comments': lambda x,d: adapt_text(x, {'is_multiple':False}),
|
||||||
|
Loading…
x
Reference in New Issue
Block a user