Store: Search allows for main window location and boolean filtering.

This commit is contained in:
John Schember 2011-04-18 18:52:14 -04:00
parent 66beba7708
commit b6f44d0b7c

View File

@ -8,6 +8,7 @@ __docformat__ = 'restructuredtext en'
import re import re
import time import time
import traceback
from contextlib import closing from contextlib import closing
from random import shuffle from random import shuffle
from threading import Thread from threading import Thread
@ -20,9 +21,12 @@ from calibre import browser
from calibre.gui2 import NONE from calibre.gui2 import NONE
from calibre.gui2.progress_indicator import ProgressIndicator from calibre.gui2.progress_indicator import ProgressIndicator
from calibre.gui2.store.search_ui import Ui_Dialog from calibre.gui2.store.search_ui import Ui_Dialog
from calibre.library.caches import _match, CONTAINS_MATCH, EQUALS_MATCH, \
REGEXP_MATCH
from calibre.utils.config import DynamicConfig from calibre.utils.config import DynamicConfig
from calibre.utils.icu import sort_key from calibre.utils.icu import sort_key
from calibre.utils.magick.draw import thumbnail from calibre.utils.magick.draw import thumbnail
from calibre.utils.search_query_parser import SearchQueryParser
HANG_TIME = 75000 # milliseconds seconds HANG_TIME = 75000 # milliseconds seconds
TIMEOUT = 75 # seconds TIMEOUT = 75 # seconds
@ -290,10 +294,14 @@ class SearchThread(Thread):
while self._run and not self.tasks.empty(): while self._run and not self.tasks.empty():
try: try:
query, store_name, store_plugin, timeout = self.tasks.get() query, store_name, store_plugin, timeout = self.tasks.get()
for res in store_plugin.search(query, timeout=timeout): squery = query
for loc in SearchFilter.USABLE_LOCATIONS:
squery = re.sub(r'%s:"?(?P<a>[^\s"]+)"?' % loc, '\g<a>', squery)
for res in store_plugin.search(squery, timeout=timeout):
if not self._run: if not self._run:
return return
res.store_name = store_name res.store_name = store_name
if SearchFilter(res).parse(query):
self.results.put(res) self.results.put(res)
self.tasks.task_done() self.tasks.task_done()
except: except:
@ -450,3 +458,82 @@ class Matches(QAbstractItemModel):
if reset: if reset:
self.reset() self.reset()
class SearchFilter(SearchQueryParser):
USABLE_LOCATIONS = [
'all',
'author',
'authors',
'cover',
'price',
'title',
'store',
]
def __init__(self, search_result):
SearchQueryParser.__init__(self, locations=self.USABLE_LOCATIONS)
self.search_result = search_result
def universal_set(self):
return set([self.search_result])
def get_matches(self, location, query):
location = location.lower().strip()
if location == 'authors':
location = 'author'
matchkind = CONTAINS_MATCH
if len(query) > 1:
if query.startswith('\\'):
query = query[1:]
elif query.startswith('='):
matchkind = EQUALS_MATCH
query = query[1:]
elif query.startswith('~'):
matchkind = REGEXP_MATCH
query = query[1:]
if matchkind != REGEXP_MATCH: ### leave case in regexps because it can be significant e.g. \S \W \D
query = query.lower()
if location not in self.USABLE_LOCATIONS:
return set([])
matches = set([])
all_locs = set(self.USABLE_LOCATIONS) - set(['all'])
locations = all_locs if location == 'all' else [location]
q = {
'author': self.search_result.author.lower(),
'cover': self.search_result.cover_url,
'format': '',
'price': self.search_result.price,
'store': self.search_result.store_name.lower(),
'title': self.search_result.title.lower(),
}
for x in ('author', 'format'):
q[x+'s'] = q[x]
for locvalue in locations:
ac_val = q[locvalue]
if query == 'true':
if ac_val is not None:
matches.add(self.search_result)
continue
if query == 'false':
if ac_val is None:
matches.add(self.search_result)
continue
try:
### Can't separate authors because comma is used for name sep and author sep
### Exact match might not get what you want. For that reason, turn author
### exactmatch searches into contains searches.
if locvalue == 'author' and matchkind == EQUALS_MATCH:
m = CONTAINS_MATCH
else:
m = matchkind
vals = [ac_val]
if _match(query, vals, m):
matches.add(self.search_result)
break
except ValueError: # Unicode errors
traceback.print_exc()
return matches