mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Move _match to db.search module
This commit is contained in:
parent
e0df1634ab
commit
d915e49815
@ -13,9 +13,15 @@ from datetime import timedelta
|
||||
|
||||
from calibre.utils.config_base import prefs
|
||||
from calibre.utils.date import parse_date, UNDEFINED_DATE, now
|
||||
from calibre.utils.icu import primary_find
|
||||
from calibre.utils.search_query_parser import SearchQueryParser, ParseException
|
||||
|
||||
# TODO: Thread safety of saved searches
|
||||
CONTAINS_MATCH = 0
|
||||
EQUALS_MATCH = 1
|
||||
REGEXP_MATCH = 2
|
||||
|
||||
# Utils {{{
|
||||
|
||||
def force_to_bool(val):
|
||||
if isinstance(val, (str, unicode)):
|
||||
@ -33,6 +39,45 @@ def force_to_bool(val):
|
||||
val = None
|
||||
return val
|
||||
|
||||
def _match(query, value, matchkind, use_primary_find_in_search=True):
|
||||
if query.startswith('..'):
|
||||
query = query[1:]
|
||||
sq = query[1:]
|
||||
internal_match_ok = True
|
||||
else:
|
||||
internal_match_ok = False
|
||||
for t in value:
|
||||
try: ### ignore regexp exceptions, required because search-ahead tries before typing is finished
|
||||
t = icu_lower(t)
|
||||
if (matchkind == EQUALS_MATCH):
|
||||
if internal_match_ok:
|
||||
if query == t:
|
||||
return True
|
||||
comps = [c.strip() for c in t.split('.') if c.strip()]
|
||||
for comp in comps:
|
||||
if sq == comp:
|
||||
return True
|
||||
elif query[0] == '.':
|
||||
if t.startswith(query[1:]):
|
||||
ql = len(query) - 1
|
||||
if (len(t) == ql) or (t[ql:ql+1] == '.'):
|
||||
return True
|
||||
elif query == t:
|
||||
return True
|
||||
elif matchkind == REGEXP_MATCH:
|
||||
if re.search(query, t, re.I|re.UNICODE):
|
||||
return True
|
||||
elif matchkind == CONTAINS_MATCH:
|
||||
if use_primary_find_in_search:
|
||||
if primary_find(query, t)[0] != -1:
|
||||
return True
|
||||
elif query in t:
|
||||
return True
|
||||
except re.error:
|
||||
pass
|
||||
return False
|
||||
# }}}
|
||||
|
||||
class DateSearch(object): # {{{
|
||||
|
||||
def __init__(self):
|
||||
|
@ -16,12 +16,12 @@ from calibre.utils.pyparsing import ParseException
|
||||
from calibre.ebooks.metadata import fmt_sidx, authors_to_string, string_to_authors
|
||||
from calibre.ebooks.metadata.book.base import SafeFormat
|
||||
from calibre.ptempfile import PersistentTemporaryFile
|
||||
from calibre.utils.config import tweaks, device_prefs
|
||||
from calibre.utils.config import tweaks, device_prefs, prefs
|
||||
from calibre.utils.date import dt_factory, qt_to_dt, as_local_time
|
||||
from calibre.utils.icu import sort_key
|
||||
from calibre.utils.search_query_parser import SearchQueryParser
|
||||
from calibre.library.caches import (_match, CONTAINS_MATCH, EQUALS_MATCH,
|
||||
REGEXP_MATCH, MetadataBackup, force_to_bool)
|
||||
from calibre.db.search import _match, CONTAINS_MATCH, EQUALS_MATCH, REGEXP_MATCH
|
||||
from calibre.library.caches import (MetadataBackup, force_to_bool)
|
||||
from calibre.library.save_to_disk import find_plugboard
|
||||
from calibre import strftime, isbytestring
|
||||
from calibre.constants import filesystem_encoding, DEBUG
|
||||
@ -1037,6 +1037,7 @@ class OnDeviceSearch(SearchQueryParser): # {{{
|
||||
}
|
||||
for x in ('author', 'format'):
|
||||
q[x+'s'] = q[x]
|
||||
upf = prefs['use_primary_find_in_search']
|
||||
for index, row in enumerate(self.model.db):
|
||||
for locvalue in locations:
|
||||
accessor = q[locvalue]
|
||||
@ -1063,7 +1064,7 @@ class OnDeviceSearch(SearchQueryParser): # {{{
|
||||
vals = accessor(row).split(',')
|
||||
else:
|
||||
vals = [accessor(row)]
|
||||
if _match(query, vals, m):
|
||||
if _match(query, vals, m, use_primary_find_in_search=upf):
|
||||
matches.add(index)
|
||||
break
|
||||
except ValueError: # Unicode errors
|
||||
|
@ -10,8 +10,8 @@ from PyQt4.Qt import (Qt, QAbstractItemModel, QIcon, QVariant, QModelIndex, QSiz
|
||||
|
||||
from calibre.gui2 import NONE
|
||||
from calibre.customize.ui import is_disabled, disable_plugin, enable_plugin
|
||||
from calibre.library.caches import _match, CONTAINS_MATCH, EQUALS_MATCH, \
|
||||
REGEXP_MATCH
|
||||
from calibre.db.search import _match, CONTAINS_MATCH, EQUALS_MATCH, REGEXP_MATCH
|
||||
from calibre.utils.config_base import prefs
|
||||
from calibre.utils.icu import sort_key
|
||||
from calibre.utils.search_query_parser import SearchQueryParser
|
||||
|
||||
@ -60,13 +60,13 @@ class Matches(QAbstractItemModel):
|
||||
index = self.createIndex(i, 0)
|
||||
data = QVariant(True)
|
||||
self.setData(index, data, Qt.CheckStateRole)
|
||||
|
||||
|
||||
def enable_none(self):
|
||||
for i in xrange(len(self.matches)):
|
||||
index = self.createIndex(i, 0)
|
||||
data = QVariant(False)
|
||||
self.setData(index, data, Qt.CheckStateRole)
|
||||
|
||||
|
||||
def enable_invert(self):
|
||||
for i in xrange(len(self.matches)):
|
||||
self.toggle_plugin(self.createIndex(i, 0))
|
||||
@ -243,6 +243,7 @@ class SearchFilter(SearchQueryParser):
|
||||
'name': lambda x : x.name.lower(),
|
||||
}
|
||||
q['formats'] = q['format']
|
||||
upf = prefs['use_primary_find_in_search']
|
||||
for sr in self.srs:
|
||||
for locvalue in locations:
|
||||
accessor = q[locvalue]
|
||||
@ -276,7 +277,7 @@ class SearchFilter(SearchQueryParser):
|
||||
vals = accessor(sr).split(',')
|
||||
else:
|
||||
vals = [accessor(sr)]
|
||||
if _match(query, vals, m):
|
||||
if _match(query, vals, m, use_primary_find_in_search=upf):
|
||||
matches.add(sr)
|
||||
break
|
||||
except ValueError: # Unicode errors
|
||||
|
@ -11,13 +11,13 @@ from operator import attrgetter
|
||||
from PyQt4.Qt import (Qt, QAbstractItemModel, QModelIndex, QVariant, pyqtSignal)
|
||||
|
||||
from calibre.gui2 import NONE
|
||||
from calibre.library.caches import _match, CONTAINS_MATCH, EQUALS_MATCH, \
|
||||
REGEXP_MATCH
|
||||
from calibre.db.search import _match, CONTAINS_MATCH, EQUALS_MATCH, REGEXP_MATCH
|
||||
from calibre.utils.config_base import prefs
|
||||
from calibre.utils.icu import sort_key
|
||||
from calibre.utils.search_query_parser import SearchQueryParser
|
||||
|
||||
class BooksModel(QAbstractItemModel):
|
||||
|
||||
|
||||
total_changed = pyqtSignal(int)
|
||||
|
||||
HEADERS = [_('Title'), _('Author(s)'), _('Format')]
|
||||
@ -37,8 +37,8 @@ class BooksModel(QAbstractItemModel):
|
||||
return self.books[row]
|
||||
else:
|
||||
return None
|
||||
|
||||
def search(self, filter):
|
||||
|
||||
def search(self, filter):
|
||||
self.filter = filter.strip()
|
||||
if not self.filter:
|
||||
self.books = self.all_books
|
||||
@ -50,7 +50,7 @@ class BooksModel(QAbstractItemModel):
|
||||
self.layoutChanged.emit()
|
||||
self.sort(self.sort_col, self.sort_order)
|
||||
self.total_changed.emit(self.rowCount())
|
||||
|
||||
|
||||
def index(self, row, column, parent=QModelIndex()):
|
||||
return self.createIndex(row, column)
|
||||
|
||||
@ -64,7 +64,7 @@ class BooksModel(QAbstractItemModel):
|
||||
|
||||
def columnCount(self, *args):
|
||||
return len(self.HEADERS)
|
||||
|
||||
|
||||
def headerData(self, section, orientation, role):
|
||||
if role != Qt.DisplayRole:
|
||||
return NONE
|
||||
@ -112,7 +112,7 @@ class BooksModel(QAbstractItemModel):
|
||||
|
||||
|
||||
class SearchFilter(SearchQueryParser):
|
||||
|
||||
|
||||
USABLE_LOCATIONS = [
|
||||
'all',
|
||||
'author',
|
||||
@ -161,6 +161,7 @@ class SearchFilter(SearchQueryParser):
|
||||
}
|
||||
for x in ('author', 'format'):
|
||||
q[x+'s'] = q[x]
|
||||
upf = prefs['use_primary_find_in_search']
|
||||
for sr in self.srs:
|
||||
for locvalue in locations:
|
||||
accessor = q[locvalue]
|
||||
@ -182,7 +183,7 @@ class SearchFilter(SearchQueryParser):
|
||||
m = matchkind
|
||||
|
||||
vals = [accessor(sr)]
|
||||
if _match(query, vals, m):
|
||||
if _match(query, vals, m, use_primary_find_in_search=upf):
|
||||
matches.add(sr)
|
||||
break
|
||||
except ValueError: # Unicode errors
|
||||
|
@ -6,7 +6,7 @@ __license__ = 'GPL v3'
|
||||
__copyright__ = '2010, Kovid Goyal <kovid@kovidgoyal.net>'
|
||||
__docformat__ = 'restructuredtext en'
|
||||
|
||||
import re, itertools, time, traceback, locale
|
||||
import itertools, time, traceback, locale
|
||||
from itertools import repeat, izip, imap
|
||||
from datetime import timedelta
|
||||
from threading import Thread
|
||||
@ -16,10 +16,10 @@ from calibre.utils.date import parse_date, now, UNDEFINED_DATE, clean_date_for_s
|
||||
from calibre.utils.search_query_parser import SearchQueryParser
|
||||
from calibre.utils.pyparsing import ParseException
|
||||
from calibre.utils.localization import (canonicalize_lang, lang_map, get_udc)
|
||||
from calibre.db.search import CONTAINS_MATCH, EQUALS_MATCH, REGEXP_MATCH, _match
|
||||
from calibre.ebooks.metadata import title_sort, author_to_author_sort
|
||||
from calibre.ebooks.metadata.opf2 import metadata_to_opf
|
||||
from calibre import prints
|
||||
from calibre.utils.icu import primary_find
|
||||
|
||||
class MetadataBackup(Thread): # {{{
|
||||
'''
|
||||
@ -118,7 +118,6 @@ class MetadataBackup(Thread): # {{{
|
||||
|
||||
# }}}
|
||||
|
||||
|
||||
### Global utility function for get_match here and in gui2/library.py
|
||||
# This is a global for performance
|
||||
pref_use_primary_find_in_search = False
|
||||
@ -127,47 +126,6 @@ def set_use_primary_find_in_search(toWhat):
|
||||
global pref_use_primary_find_in_search
|
||||
pref_use_primary_find_in_search = toWhat
|
||||
|
||||
CONTAINS_MATCH = 0
|
||||
EQUALS_MATCH = 1
|
||||
REGEXP_MATCH = 2
|
||||
def _match(query, value, matchkind):
|
||||
if query.startswith('..'):
|
||||
query = query[1:]
|
||||
sq = query[1:]
|
||||
internal_match_ok = True
|
||||
else:
|
||||
internal_match_ok = False
|
||||
for t in value:
|
||||
try: ### ignore regexp exceptions, required because search-ahead tries before typing is finished
|
||||
t = icu_lower(t)
|
||||
if (matchkind == EQUALS_MATCH):
|
||||
if internal_match_ok:
|
||||
if query == t:
|
||||
return True
|
||||
comps = [c.strip() for c in t.split('.') if c.strip()]
|
||||
for comp in comps:
|
||||
if sq == comp:
|
||||
return True
|
||||
elif query[0] == '.':
|
||||
if t.startswith(query[1:]):
|
||||
ql = len(query) - 1
|
||||
if (len(t) == ql) or (t[ql:ql+1] == '.'):
|
||||
return True
|
||||
elif query == t:
|
||||
return True
|
||||
elif matchkind == REGEXP_MATCH:
|
||||
if re.search(query, t, re.I|re.UNICODE):
|
||||
return True
|
||||
elif matchkind == CONTAINS_MATCH:
|
||||
if pref_use_primary_find_in_search:
|
||||
if primary_find(query, t)[0] != -1:
|
||||
return True
|
||||
elif query in t:
|
||||
return True
|
||||
except re.error:
|
||||
pass
|
||||
return False
|
||||
|
||||
def force_to_bool(val):
|
||||
if isinstance(val, (str, unicode)):
|
||||
try:
|
||||
@ -576,7 +534,8 @@ class ResultCache(SearchQueryParser): # {{{
|
||||
continue
|
||||
k = parts[:1]
|
||||
v = parts[1:]
|
||||
if keyq and not _match(keyq, k, keyq_mkind):
|
||||
if keyq and not _match(keyq, k, keyq_mkind,
|
||||
use_primary_find_in_search=pref_use_primary_find_in_search):
|
||||
continue
|
||||
if valq:
|
||||
if valq == 'true':
|
||||
@ -586,7 +545,8 @@ class ResultCache(SearchQueryParser): # {{{
|
||||
if v:
|
||||
add_if_nothing_matches = False
|
||||
continue
|
||||
elif not _match(valq, v, valq_mkind):
|
||||
elif not _match(valq, v, valq_mkind,
|
||||
use_primary_find_in_search=pref_use_primary_find_in_search):
|
||||
continue
|
||||
matches.add(id_)
|
||||
|
||||
@ -851,7 +811,8 @@ class ResultCache(SearchQueryParser): # {{{
|
||||
vals = [v.strip() for v in item[loc].split(is_multiple_cols[loc])]
|
||||
else:
|
||||
vals = [item[loc]] ### make into list to make _match happy
|
||||
if _match(q, vals, matchkind):
|
||||
if _match(q, vals, matchkind,
|
||||
use_primary_find_in_search=pref_use_primary_find_in_search):
|
||||
matches.add(item[0])
|
||||
continue
|
||||
current_candidates -= matches
|
||||
|
Loading…
x
Reference in New Issue
Block a user