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:
Kovid Goyal 2011-01-05 11:00:24 -07:00
parent 2787419445
commit 7e309d5d28
4 changed files with 82 additions and 16 deletions

View File

@ -321,7 +321,8 @@ class MetadataBulkDialog(QDialog, Ui_MetadataBulkDialog):
if (f in ['author_sort'] or
(fm[f]['datatype'] in ['text', 'series', 'enumeration']
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.writable_fields.append(f)
if f in ['sort'] or fm[f]['datatype'] == 'composite':
@ -431,6 +432,8 @@ class MetadataBulkDialog(QDialog, Ui_MetadataBulkDialog):
val = mi.get('title_sort', None)
else:
val = mi.get(field, None)
if isinstance(val, (int, float, bool)):
val = str(val)
if val is None:
val = [] if fm['is_multiple'] else ['']
elif not fm['is_multiple']:

View File

@ -3,7 +3,7 @@ __copyright__ = '2008, Kovid Goyal <kovid at kovidgoyal.net>'
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.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:]))
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)
if self.box_last_values:
for k,v in self.box_last_values.items():
@ -121,26 +143,34 @@ class SearchDialog(QDialog, Ui_Dialog):
return tok
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 = []
self.box_last_values = {}
title = unicode(self.title_box.text()).strip()
self.box_last_values['title_box'] = title
if title:
ans.append('title:"' + title + '"')
ans.append('title:"' + self.mc + title + '"')
author = unicode(self.authors_box.text()).strip()
self.box_last_values['authors_box'] = author
if author:
ans.append('author:"' + author + '"')
ans.append('author:"' + self.mc + author + '"')
series = unicode(self.series_box.text()).strip()
self.box_last_values['series_box'] = series
if series:
ans.append('series:"' + series + '"')
self.mc = '='
ans.append('series:"' + self.mc + series + '"')
tags = unicode(self.tags_box.text())
self.box_last_values['tags_box'] = tags
tags = self.tokens(tags)
tags = [t.strip() for t in tags.split(',') if t.strip()]
if tags:
tags = ['tags:' + t for t in tags]
tags = ['tags:"=' + t + '"' for t in tags]
ans.append('(' + ' or '.join(tags) + ')')
general = unicode(self.general_box.text())
self.box_last_values['general_box'] = general

View File

@ -21,7 +21,7 @@
<item row="0" column="0">
<widget class="QLabel" name="label_5">
<property name="text">
<string>What kind of match to use:</string>
<string>&amp;What kind of match to use:</string>
</property>
<property name="buddy">
<cstring>matchkind</cstring>
@ -228,7 +228,7 @@
</widget>
</item>
<item row="1" column="1">
<widget class="QLineEdit" name="title_box">
<widget class="EnLineEdit" name="title_box">
<property name="toolTip">
<string>Enter the title.</string>
</property>
@ -265,21 +265,21 @@
</widget>
</item>
<item row="2" column="1">
<widget class="QLineEdit" name="authors_box">
<widget class="EnComboBox" name="authors_box">
<property name="toolTip">
<string>Enter an author's name. Only one author can be used.</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QLineEdit" name="series_box">
<widget class="EnComboBox" name="series_box">
<property name="toolTip">
<string>Enter a series name, without an index. Only one series name can be used.</string>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QLineEdit" name="tags_box">
<widget class="TagsLineEdit" name="tags_box">
<property name="toolTip">
<string>Enter tags separated by spaces</string>
</property>
@ -348,6 +348,23 @@
</item>
</layout>
</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>
<tabstop>all</tabstop>
<tabstop>phrase</tabstop>

View File

@ -133,7 +133,15 @@ class CustomColumns(object):
def adapt_bool(x, d):
if isinstance(x, (str, unicode, bytes)):
x = bool(int(x))
x = x.lower()
if x == 'true':
x = True
elif x == 'false':
x = False
elif x == 'none':
x = None
else:
x = bool(int(x))
return x
def adapt_enum(x, d):
@ -142,9 +150,17 @@ class CustomColumns(object):
v = None
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 = {
'float': lambda x,d : x if x is None else float(x),
'int': lambda x,d : x if x is None else int(x),
'float': adapt_number,
'int': adapt_number,
'rating':lambda x,d : x if x is None else min(10., max(0., float(x))),
'bool': adapt_bool,
'comments': lambda x,d: adapt_text(x, {'is_multiple':False}),