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:
|
else:
|
||||||
internal_match_ok = False
|
internal_match_ok = False
|
||||||
for t in value:
|
for t in value:
|
||||||
try: # ignore regexp exceptions, required because search-ahead tries before typing is finished
|
if not case_sensitive:
|
||||||
if not case_sensitive:
|
t = icu_lower(t)
|
||||||
t = icu_lower(t)
|
if (matchkind == EQUALS_MATCH):
|
||||||
if (matchkind == EQUALS_MATCH):
|
if internal_match_ok:
|
||||||
if internal_match_ok:
|
if query == t:
|
||||||
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:
|
|
||||||
return True
|
return True
|
||||||
elif matchkind == REGEXP_MATCH:
|
return sq in [c.strip() for c in t.split('.') if c.strip()]
|
||||||
flags = regex.UNICODE | regex.VERSION1 | regex.FULLCASE | (0 if case_sensitive else regex.IGNORECASE)
|
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:
|
if regex.search(query, t, flags) is not None:
|
||||||
return True
|
return True
|
||||||
elif matchkind == ACCENT_MATCH:
|
except regex.error as e:
|
||||||
if primary_contains(query, t):
|
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
|
return True
|
||||||
elif matchkind == CONTAINS_MATCH:
|
elif query in t:
|
||||||
if not case_sensitive and use_primary_find_in_search:
|
return True
|
||||||
if primary_no_punc_contains(query, t):
|
|
||||||
return True
|
|
||||||
elif query in t:
|
|
||||||
return True
|
|
||||||
except regex.error:
|
|
||||||
pass
|
|
||||||
return False
|
return False
|
||||||
# }}}
|
# }}}
|
||||||
|
|
||||||
@ -298,7 +298,8 @@ class NumericSearch: # {{{
|
|||||||
try:
|
try:
|
||||||
v = cast(val)
|
v = cast(val)
|
||||||
except Exception:
|
except Exception:
|
||||||
v = None
|
raise ParseException(
|
||||||
|
_('Non-numeric value in column {0}: {1}').format(location, val))
|
||||||
if v:
|
if v:
|
||||||
v = adjust(v)
|
v = adjust(v)
|
||||||
if relop(v, q):
|
if relop(v, q):
|
||||||
|
@ -242,6 +242,11 @@ class SearchBar(QFrame): # {{{
|
|||||||
_('Advanced search'), default_keys=("Shift+Ctrl+F",),
|
_('Advanced search'), default_keys=("Shift+Ctrl+F",),
|
||||||
action=ac)
|
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 = QToolButton()
|
||||||
self.search_button.setToolButtonStyle(Qt.ToolButtonStyle.ToolButtonTextOnly)
|
self.search_button.setToolButtonStyle(Qt.ToolButtonStyle.ToolButtonTextOnly)
|
||||||
self.search_button.setIcon(QIcon.ic('search.png'))
|
self.search_button.setIcon(QIcon.ic('search.png'))
|
||||||
|
@ -142,6 +142,7 @@ class SearchBox2(QComboBox): # {{{
|
|||||||
self.setMinimumContentsLength(25)
|
self.setMinimumContentsLength(25)
|
||||||
self._in_a_search = False
|
self._in_a_search = False
|
||||||
self.tool_tip_text = self.toolTip()
|
self.tool_tip_text = self.toolTip()
|
||||||
|
self.parse_error_action = None
|
||||||
|
|
||||||
def add_action(self, icon, position=QLineEdit.ActionPosition.TrailingPosition):
|
def add_action(self, icon, position=QLineEdit.ActionPosition.TrailingPosition):
|
||||||
if not isinstance(icon, QIcon):
|
if not isinstance(icon, QIcon):
|
||||||
@ -180,6 +181,7 @@ class SearchBox2(QComboBox): # {{{
|
|||||||
return self.currentText()
|
return self.currentText()
|
||||||
|
|
||||||
def clear(self, emit_search=True):
|
def clear(self, emit_search=True):
|
||||||
|
self.show_parse_error_action(False)
|
||||||
self.normalize_state()
|
self.normalize_state()
|
||||||
self.setEditText('')
|
self.setEditText('')
|
||||||
if emit_search:
|
if emit_search:
|
||||||
@ -191,9 +193,17 @@ class SearchBox2(QComboBox): # {{{
|
|||||||
self.clear()
|
self.clear()
|
||||||
self.setFocus(Qt.FocusReason.OtherFocusReason)
|
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):
|
def search_done(self, ok):
|
||||||
if isinstance(ok, string_or_bytes):
|
if isinstance(ok, string_or_bytes):
|
||||||
self.setToolTip(ok)
|
self.setToolTip(ok)
|
||||||
|
self.show_parse_error_action(True, tooltip=ok)
|
||||||
ok = False
|
ok = False
|
||||||
if not str(self.currentText()).strip():
|
if not str(self.currentText()).strip():
|
||||||
self.clear(emit_search=False)
|
self.clear(emit_search=False)
|
||||||
@ -223,6 +233,7 @@ class SearchBox2(QComboBox): # {{{
|
|||||||
|
|
||||||
# Comes from the combobox itself
|
# Comes from the combobox itself
|
||||||
def keyPressEvent(self, event):
|
def keyPressEvent(self, event):
|
||||||
|
self.show_parse_error_action(False)
|
||||||
k = event.key()
|
k = event.key()
|
||||||
if k in (Qt.Key.Key_Enter, Qt.Key.Key_Return):
|
if k in (Qt.Key.Key_Enter, Qt.Key.Key_Return):
|
||||||
return self.do_search()
|
return self.do_search()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user