mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Bug #2002195: Search breaks if non-number used in numeric-sorted column.
This fix is really an enhancement, adding better error presentation to the GUI search box.
This commit is contained in:
parent
0ebd840d6a
commit
ff1952b8b7
@ -56,36 +56,36 @@ def _match(query, value, matchkind, use_primary_find_in_search=True, case_sensit
|
||||
else:
|
||||
internal_match_ok = False
|
||||
for t in value:
|
||||
try: # ignore regexp exceptions, required because search-ahead tries before typing is finished
|
||||
if not case_sensitive:
|
||||
t = icu_lower(t)
|
||||
if (matchkind == EQUALS_MATCH):
|
||||
if internal_match_ok:
|
||||
if query == t:
|
||||
return True
|
||||
return sq in [c.strip() for c in t.split('.') if c.strip()]
|
||||
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:
|
||||
if not case_sensitive:
|
||||
t = icu_lower(t)
|
||||
if (matchkind == EQUALS_MATCH):
|
||||
if internal_match_ok:
|
||||
if query == t:
|
||||
return True
|
||||
elif matchkind == REGEXP_MATCH:
|
||||
flags = regex.UNICODE | regex.VERSION1 | regex.FULLCASE | (0 if case_sensitive else regex.IGNORECASE)
|
||||
return sq in [c.strip() for c in t.split('.') if c.strip()]
|
||||
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:
|
||||
flags = regex.UNICODE | regex.VERSION1 | regex.FULLCASE | (0 if case_sensitive else regex.IGNORECASE)
|
||||
try:
|
||||
if regex.search(query, t, flags) is not None:
|
||||
return True
|
||||
elif matchkind == ACCENT_MATCH:
|
||||
if primary_contains(query, t):
|
||||
except regex.error as e:
|
||||
raise ParseException(_('Invalid regular expression: {}').format(str(e)))
|
||||
elif matchkind == ACCENT_MATCH:
|
||||
if primary_contains(query, t):
|
||||
return True
|
||||
elif matchkind == CONTAINS_MATCH:
|
||||
if not case_sensitive and use_primary_find_in_search:
|
||||
if primary_no_punc_contains(query, t):
|
||||
return True
|
||||
elif matchkind == CONTAINS_MATCH:
|
||||
if not case_sensitive and use_primary_find_in_search:
|
||||
if primary_no_punc_contains(query, t):
|
||||
return True
|
||||
elif query in t:
|
||||
return True
|
||||
except regex.error:
|
||||
pass
|
||||
elif query in t:
|
||||
return True
|
||||
return False
|
||||
# }}}
|
||||
|
||||
@ -298,7 +298,8 @@ class NumericSearch: # {{{
|
||||
try:
|
||||
v = cast(val)
|
||||
except Exception:
|
||||
v = None
|
||||
raise ParseException(
|
||||
_('Non-numeric value in column {0}: {1}').format(location, val))
|
||||
if v:
|
||||
v = adjust(v)
|
||||
if relop(v, q):
|
||||
|
@ -242,6 +242,11 @@ class SearchBar(QFrame): # {{{
|
||||
_('Advanced search'), default_keys=("Shift+Ctrl+F",),
|
||||
action=ac)
|
||||
|
||||
# This error icon will be placed after the clear button icon
|
||||
parent.search.parse_error_action = ac = parent.search.add_action('dialog_error.png', QLineEdit.ActionPosition.TrailingPosition)
|
||||
parent.addAction(ac)
|
||||
ac.setVisible(False)
|
||||
|
||||
self.search_button = QToolButton()
|
||||
self.search_button.setToolButtonStyle(Qt.ToolButtonStyle.ToolButtonTextOnly)
|
||||
self.search_button.setIcon(QIcon.ic('search.png'))
|
||||
|
@ -142,6 +142,7 @@ class SearchBox2(QComboBox): # {{{
|
||||
self.setMinimumContentsLength(25)
|
||||
self._in_a_search = False
|
||||
self.tool_tip_text = self.toolTip()
|
||||
self.parse_error_action = None
|
||||
|
||||
def add_action(self, icon, position=QLineEdit.ActionPosition.TrailingPosition):
|
||||
if not isinstance(icon, QIcon):
|
||||
@ -180,6 +181,7 @@ class SearchBox2(QComboBox): # {{{
|
||||
return self.currentText()
|
||||
|
||||
def clear(self, emit_search=True):
|
||||
self.show_parse_error_action(False)
|
||||
self.normalize_state()
|
||||
self.setEditText('')
|
||||
if emit_search:
|
||||
@ -191,9 +193,17 @@ class SearchBox2(QComboBox): # {{{
|
||||
self.clear()
|
||||
self.setFocus(Qt.FocusReason.OtherFocusReason)
|
||||
|
||||
def show_parse_error_action(self, to_show, tooltip=''):
|
||||
try:
|
||||
self.parse_error_action.setVisible(to_show)
|
||||
self.parse_error_action.setToolTip(tooltip)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
def search_done(self, ok):
|
||||
if isinstance(ok, string_or_bytes):
|
||||
self.setToolTip(ok)
|
||||
self.show_parse_error_action(True, tooltip=ok)
|
||||
ok = False
|
||||
if not str(self.currentText()).strip():
|
||||
self.clear(emit_search=False)
|
||||
@ -223,6 +233,7 @@ class SearchBox2(QComboBox): # {{{
|
||||
|
||||
# Comes from the combobox itself
|
||||
def keyPressEvent(self, event):
|
||||
self.show_parse_error_action(False)
|
||||
k = event.key()
|
||||
if k in (Qt.Key.Key_Enter, Qt.Key.Key_Return):
|
||||
return self.do_search()
|
||||
|
Loading…
x
Reference in New Issue
Block a user