Store: Filter in Matches model.

This commit is contained in:
John Schember 2011-04-20 07:46:27 -04:00
parent f9a931dbfb
commit b415c44cb6

View File

@ -112,6 +112,9 @@ class SearchDialog(QDialog, Ui_Dialog):
query = unicode(self.search_edit.text()) query = unicode(self.search_edit.text())
if not query.strip(): if not query.strip():
return return
# Give the query to the results model so it can do
# futher filtering.
self.results_view.model().set_query(query)
# Plugins are in alphebetic order. Randomize the # Plugins are in alphebetic order. Randomize the
# order of plugin names. This way plugins closer # order of plugin names. This way plugins closer
@ -304,13 +307,12 @@ 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()
squery = self._clean_query(query) query = self._clean_query(query)
for res in store_plugin.search(squery, timeout=timeout): for res in store_plugin.search(query, 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:
traceback.print_exc() traceback.print_exc()
@ -390,7 +392,14 @@ class Matches(QAbstractItemModel):
self.DRM_UNLOCKED_ICON = QPixmap(I('drm-unlocked.png')).scaledToHeight(64) self.DRM_UNLOCKED_ICON = QPixmap(I('drm-unlocked.png')).scaledToHeight(64)
self.DRM_UNKNOWN_ICON = QPixmap(I('dialog_warning.png')).scaledToHeight(64) self.DRM_UNKNOWN_ICON = QPixmap(I('dialog_warning.png')).scaledToHeight(64)
# All matches. Used to determine the order to display
# self.matches because the SearchFilter returns
# matches unordered.
self.all_matches = []
# Only the showing matches.
self.matches = [] self.matches = []
self.query = ''
self.search_filter = SearchFilter()
self.cover_pool = CoverThreadPool(CoverThread, 2) self.cover_pool = CoverThreadPool(CoverThread, 2)
self.cover_pool.start_threads() self.cover_pool.start_threads()
@ -398,15 +407,21 @@ class Matches(QAbstractItemModel):
self.cover_pool.abort() self.cover_pool.abort()
def clear_results(self): def clear_results(self):
self.all_matches = []
self.matches = [] self.matches = []
self.all_matches = []
self.search_filter.clear_search_results()
self.query = ''
self.cover_pool.abort() self.cover_pool.abort()
self.cover_pool.start_threads() self.cover_pool.start_threads()
self.reset() self.reset()
def add_result(self, result): def add_result(self, result):
self.layoutAboutToBeChanged.emit() self.layoutAboutToBeChanged.emit()
self.matches.append(result) self.all_matches.append(result)
self.cover_pool.add_task(result, self.update_result) self.search_filter.add_search_result(result)
self.cover_pool.add_task(result, self.filter_results)
self.filter_results()
self.layoutChanged.emit() self.layoutChanged.emit()
def get_result(self, index): def get_result(self, index):
@ -415,10 +430,18 @@ class Matches(QAbstractItemModel):
return self.matches[row] return self.matches[row]
else: else:
return None return None
def update_result(self): def filter_results(self):
self.layoutAboutToBeChanged.emit() self.layoutAboutToBeChanged.emit()
self.layoutChanged.emit() if self.query:
self.matches = list(self.search_filter.parse(self.query))
else:
self.matches = list(self.search_filter.universal_set())
self.reorder_matches()
self.layoutAboutToBeChanged.emit()
def set_query(self, query):
self.query = query
def index(self, row, column, parent=QModelIndex()): def index(self, row, column, parent=QModelIndex()):
return self.createIndex(row, column) return self.createIndex(row, column)
@ -497,11 +520,15 @@ class Matches(QAbstractItemModel):
if not self.matches: if not self.matches:
return return
descending = order == Qt.DescendingOrder descending = order == Qt.DescendingOrder
self.matches.sort(None, self.all_matches.sort(None,
lambda x: sort_key(unicode(self.data_as_text(x, col))), lambda x: sort_key(unicode(self.data_as_text(x, col))),
descending) descending)
self.reorder_matches()
if reset: if reset:
self.reset() self.reset()
def reorder_matches(self):
self.matches = sorted(self.matches, key=lambda x: self.all_matches.index(x))
class SearchFilter(SearchQueryParser): class SearchFilter(SearchQueryParser):
@ -517,12 +544,18 @@ class SearchFilter(SearchQueryParser):
'store', 'store',
] ]
def __init__(self, search_result): def __init__(self):
SearchQueryParser.__init__(self, locations=self.USABLE_LOCATIONS) SearchQueryParser.__init__(self, locations=self.USABLE_LOCATIONS)
self.search_result = search_result self.srs = set([])
def add_search_result(self, search_result):
self.srs.add(search_result)
def clear_search_results(self):
self.srs = set([])
def universal_set(self): def universal_set(self):
return set([self.search_result]) return self.srs
def get_matches(self, location, query): def get_matches(self, location, query):
location = location.lower().strip() location = location.lower().strip()
@ -548,50 +581,51 @@ class SearchFilter(SearchQueryParser):
all_locs = set(self.USABLE_LOCATIONS) - set(['all']) all_locs = set(self.USABLE_LOCATIONS) - set(['all'])
locations = all_locs if location == 'all' else [location] locations = all_locs if location == 'all' else [location]
q = { q = {
'author': self.search_result.author.lower(), 'author': lambda x: x.author.lower(),
'cover': self.search_result.cover_url, 'cover': lambda x: x.cover_url,
'drm': self.search_result.drm, 'drm': lambda x: x.drm,
'format': '', 'format': '',
'price': comparable_price(self.search_result.price), 'price': lambda x: comparable_price(x.price),
'store': self.search_result.store_name.lower(), 'store': lambda x: x.store_name.lower(),
'title': self.search_result.title.lower(), 'title': lambda x: x.title.lower(),
} }
for x in ('author', 'format'): for x in ('author', 'format'):
q[x+'s'] = q[x] q[x+'s'] = q[x]
for locvalue in locations: for sr in self.srs:
ac_val = q[locvalue] for locvalue in locations:
if query == 'true': accessor = q[locvalue]
if query == 'true':
if locvalue == 'drm':
if accessor(sr) == True:
matches.add(sr)
else:
if accessor(sr) is not None:
matches.add(sr)
continue
if query == 'false':
if locvalue == 'drm':
if accessor(sr) == False:
matches.add(sr)
else:
if accessor(sr) is None:
matches.add(sr)
continue
# this is bool, so can't match below
if locvalue == 'drm': if locvalue == 'drm':
if ac_val == True: continue
matches.add(self.search_result) try:
else: ### Can't separate authors because comma is used for name sep and author sep
if ac_val is not None: ### Exact match might not get what you want. For that reason, turn author
matches.add(self.search_result) ### exactmatch searches into contains searches.
continue if locvalue == 'author' and matchkind == EQUALS_MATCH:
if query == 'false': m = CONTAINS_MATCH
if locvalue == 'drm': else:
if ac_val == False: m = matchkind
matches.add(self.search_result)
else: vals = [accessor(sr)]
if ac_val is None: if _match(query, vals, m):
matches.add(self.search_result) matches.add(sr)
continue break
# this is bool, so can't match below except ValueError: # Unicode errors
if locvalue == 'drm': traceback.print_exc()
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 return matches