From ccc0c02c67dceca4dcfe527bf080bf08161d456b Mon Sep 17 00:00:00 2001 From: Charles Haley <> Date: Wed, 12 Jan 2011 16:43:47 +0000 Subject: [PATCH 1/3] Add arbitrary python function evaluation to formatter --- src/calibre/utils/formatter.py | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/src/calibre/utils/formatter.py b/src/calibre/utils/formatter.py index 40760bf91b..0b5f1d1f52 100644 --- a/src/calibre/utils/formatter.py +++ b/src/calibre/utils/formatter.py @@ -18,6 +18,24 @@ class _Parser(object): LEX_NUM = 4 LEX_EOF = 5 + def _python(self, func): + locals = {} + exec func in locals + if 'evaluate' not in locals: + self.error('no evaluate function in python') + try: + result = locals['evaluate'](self.parent.kwargs) + if isinstance(result, (float, int)): + result = unicode(result) + elif isinstance(result, list): + result = ','.join(result) + elif isinstance(result, str): + result = unicode(result) + return result + except Exception as e: + self.error('python function threw exception: ' + e.msg) + + def _strcmp(self, x, y, lt, eq, gt): v = strcmp(x, y) if v < 0: @@ -79,6 +97,7 @@ class _Parser(object): 'field' : (1, lambda s, x: s.parent.get_value(x, [], s.parent.kwargs)), 'multiply' : (2, partial(_math, op='*')), 'print' : (-1, _print), + 'python' : (1, _python), 'strcat' : (-1, _concat), 'strcmp' : (5, _strcmp), 'substr' : (3, lambda s, x, y, z: x[int(y): len(x) if int(z) == 0 else int(z)]), @@ -362,7 +381,7 @@ class TemplateFormatter(string.Formatter): (r'\'.*?((? Date: Wed, 12 Jan 2011 17:18:06 +0000 Subject: [PATCH 2/3] Remember the state of the highlight_only check box. Scroll to first matching row. --- src/calibre/gui2/library/models.py | 12 +++++++++--- src/calibre/gui2/library/views.py | 2 ++ src/calibre/gui2/search_box.py | 4 ++++ 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/src/calibre/gui2/library/models.py b/src/calibre/gui2/library/models.py index 98e61acf33..38a4b28744 100644 --- a/src/calibre/gui2/library/models.py +++ b/src/calibre/gui2/library/models.py @@ -94,6 +94,7 @@ class BooksModel(QAbstractTableModel): # {{{ self.bool_blank_icon = QIcon(I('blank.png')) self.device_connected = False self.rows_matching = set() + self.lowest_row_matching = None self.highlight_only = False self.read_config() @@ -233,7 +234,8 @@ class BooksModel(QAbstractTableModel): # {{{ def set_highlight_only(self, toWhat): self.highlight_only = toWhat - self.research() + if self.last_search: + self.research() def search(self, text, reset=True): try: @@ -241,11 +243,15 @@ class BooksModel(QAbstractTableModel): # {{{ self.db.search('') if not text: self.rows_matching = set() + self.lowest_row_matching = None else: - self.rows_matching = set(self.db.search(text, - return_matches=True)) + self.rows_matching = self.db.search(text, return_matches=True) + if self.rows_matching: + self.lowest_row_matching = self.db.row(self.rows_matching[0]) + self.rows_matching = set(self.rows_matching) else: self.rows_matching = set() + self.lowest_row_matching = None self.db.search(text) except ParseException as e: self.searched.emit(e.msg) diff --git a/src/calibre/gui2/library/views.py b/src/calibre/gui2/library/views.py index 357b48d1de..07c3cc21e4 100644 --- a/src/calibre/gui2/library/views.py +++ b/src/calibre/gui2/library/views.py @@ -682,6 +682,8 @@ class BooksView(QTableView): # {{{ def search_proxy(self, txt): self._model.search(txt) + if self._model.lowest_row_matching: + self.scroll_to_row(self._model.lowest_row_matching) self.setFocus(Qt.OtherFocusReason) def connect_to_search_box(self, sb, search_done): diff --git a/src/calibre/gui2/search_box.py b/src/calibre/gui2/search_box.py index 5808a2dc46..e4073a01c9 100644 --- a/src/calibre/gui2/search_box.py +++ b/src/calibre/gui2/search_box.py @@ -16,6 +16,7 @@ from calibre.gui2 import config from calibre.gui2.dialogs.confirm_delete import confirm from calibre.gui2.dialogs.saved_search_editor import SavedSearchEditor from calibre.gui2.dialogs.search import SearchDialog +from calibre.utils.config import dynamic from calibre.utils.search_query_parser import saved_searches from calibre.utils.icu import sort_key @@ -376,6 +377,8 @@ class SearchBoxMixin(object): # {{{ self.advanced_search_button.setStatusTip(self.advanced_search_button.toolTip()) self.clear_button.setStatusTip(self.clear_button.toolTip()) self.search_highlight_only.stateChanged.connect(self.highlight_only_changed) + self.search_highlight_only.setChecked( + dynamic.get('search_highlight_only', False)) def focus_search_box(self, *args): self.search.setFocus(Qt.OtherFocusReason) @@ -403,6 +406,7 @@ class SearchBoxMixin(object): # {{{ self.current_view().setFocus(Qt.OtherFocusReason) def highlight_only_changed(self, toWhat): + dynamic.set('search_highlight_only', toWhat) self.current_view().model().set_highlight_only(toWhat) self.focus_to_library() From 2fca19878162b49847ae3a855c7a4d4d95822c19 Mon Sep 17 00:00:00 2001 From: Charles Haley <> Date: Wed, 12 Jan 2011 17:28:12 +0000 Subject: [PATCH 3/3] Select the row when scrolling to it --- src/calibre/gui2/library/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/calibre/gui2/library/views.py b/src/calibre/gui2/library/views.py index 07c3cc21e4..e72d0c32a1 100644 --- a/src/calibre/gui2/library/views.py +++ b/src/calibre/gui2/library/views.py @@ -683,7 +683,7 @@ class BooksView(QTableView): # {{{ def search_proxy(self, txt): self._model.search(txt) if self._model.lowest_row_matching: - self.scroll_to_row(self._model.lowest_row_matching) + self.select_rows([self._model.lowest_row_matching], using_ids=False) self.setFocus(Qt.OtherFocusReason) def connect_to_search_box(self, sb, search_done):