From 3e05f786378caf20685d9b0d51a4fdc3052e9002 Mon Sep 17 00:00:00 2001 From: Charles Haley <> Date: Fri, 15 Apr 2011 08:18:59 +0100 Subject: [PATCH 1/5] Position the selected line on the library view in the center instead of at the edge --- 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 e87e7226e1..2f237b54e3 100644 --- a/src/calibre/gui2/library/views.py +++ b/src/calibre/gui2/library/views.py @@ -631,7 +631,7 @@ class BooksView(QTableView): # {{{ h = self.horizontalHeader() for i in range(h.count()): if not h.isSectionHidden(i) and h.sectionViewportPosition(i) >= 0: - self.scrollTo(self.model().index(row, i)) + self.scrollTo(self.model().index(row, i), self.PositionAtCenter) break def set_current_row(self, row, select=True): From b77127798597aaf0e469505cf9021563daa9b3c1 Mon Sep 17 00:00:00 2001 From: Charles Haley <> Date: Fri, 15 Apr 2011 08:25:27 +0100 Subject: [PATCH 2/5] Back out change to raise exceptions if the lookup key doesn't exist. Breaks naked searching for items containing colons. --- src/calibre/library/caches.py | 3 ++- src/calibre/utils/search_query_parser.py | 21 ++++++++------------- 2 files changed, 10 insertions(+), 14 deletions(-) diff --git a/src/calibre/library/caches.py b/src/calibre/library/caches.py index 4d696afe91..5b22ad6787 100644 --- a/src/calibre/library/caches.py +++ b/src/calibre/library/caches.py @@ -592,7 +592,8 @@ class ResultCache(SearchQueryParser): # {{{ candidates = self.universal_set() if len(candidates) == 0: return matches - self.test_location_is_valid(location, query) + if location not in self.all_search_locations: + return matches if len(location) > 2 and location.startswith('@') and \ location[1:] in self.db_prefs['grouped_search_terms']: diff --git a/src/calibre/utils/search_query_parser.py b/src/calibre/utils/search_query_parser.py index 10d8b64a0d..597d24d2a4 100644 --- a/src/calibre/utils/search_query_parser.py +++ b/src/calibre/utils/search_query_parser.py @@ -19,8 +19,8 @@ If this module is run, it will perform a series of unit tests. import sys, string, operator from calibre.utils.pyparsing import CaselessKeyword, Group, Forward, \ - CharsNotIn, Suppress, OneOrMore, MatchFirst, alphas, alphanums, \ - Optional, ParseException, QuotedString, Word + CharsNotIn, Suppress, OneOrMore, MatchFirst, CaselessLiteral, \ + Optional, NoMatch, ParseException, QuotedString from calibre.constants import preferred_encoding from calibre.utils.icu import sort_key @@ -128,9 +128,12 @@ class SearchQueryParser(object): self._tests_failed = False self.optimize = optimize # Define a token - self.standard_locations = locations - location = Optional(Word(alphas+'#', bodyChars=alphanums+'_')+Suppress(':'), - default='all') + standard_locations = map(lambda x : CaselessLiteral(x)+Suppress(':'), + locations) + location = NoMatch() + for l in standard_locations: + location |= l + location = Optional(location, default='all') word_query = CharsNotIn(string.whitespace + '()') #quoted_query = Suppress('"')+CharsNotIn('"')+Suppress('"') quoted_query = QuotedString('"', escChar='\\') @@ -247,14 +250,7 @@ class SearchQueryParser(object): raise ParseException(query, len(query), 'undefined saved search', self) return self._get_matches(location, query, candidates) - def test_location_is_valid(self, location, query): - if location not in self.standard_locations: - raise ParseException(query, len(query), - _('No column exists with lookup name ') + location, self) - def _get_matches(self, location, query, candidates): - location = location.lower() - self.test_location_is_valid(location, query) if self.optimize: return self.get_matches(location, query, candidates=candidates) else: @@ -658,4 +654,3 @@ if __name__ == '__main__': sys.exit(main()) # }}} - From e2a6ab16a7eb1566da4d4dfaf174836eb3ff128b Mon Sep 17 00:00:00 2001 From: Charles Haley <> Date: Fri, 15 Apr 2011 08:31:39 +0100 Subject: [PATCH 3/5] ... --- src/calibre/utils/search_query_parser.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/calibre/utils/search_query_parser.py b/src/calibre/utils/search_query_parser.py index 597d24d2a4..a50ca20fc1 100644 --- a/src/calibre/utils/search_query_parser.py +++ b/src/calibre/utils/search_query_parser.py @@ -654,3 +654,4 @@ if __name__ == '__main__': sys.exit(main()) # }}} + From 8157ad817ce61f35489540139c0d41adaccab0ce Mon Sep 17 00:00:00 2001 From: Charles Haley <> Date: Fri, 15 Apr 2011 13:12:49 +0100 Subject: [PATCH 4/5] Add multi-column search. --- src/calibre/gui2/library/models.py | 2 +- src/calibre/gui2/library/views.py | 29 +++++++++++++++++++++++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/src/calibre/gui2/library/models.py b/src/calibre/gui2/library/models.py index 0a4b7a26ba..8d89ec76ed 100644 --- a/src/calibre/gui2/library/models.py +++ b/src/calibre/gui2/library/models.py @@ -310,7 +310,6 @@ class BooksModel(QAbstractTableModel): # {{{ def sort(self, col, order, reset=True): if not self.db: return - self.about_to_be_sorted.emit(self.db.id) if not isinstance(order, bool): order = order == Qt.AscendingOrder label = self.column_map[col] @@ -321,6 +320,7 @@ class BooksModel(QAbstractTableModel): # {{{ self._sort(field, order, reset) def _sort(self, label, order, reset): + self.about_to_be_sorted.emit(self.db.id) self.db.sort(label, order) if reset: self.reset() diff --git a/src/calibre/gui2/library/views.py b/src/calibre/gui2/library/views.py index 2f237b54e3..840db906d6 100644 --- a/src/calibre/gui2/library/views.py +++ b/src/calibre/gui2/library/views.py @@ -246,6 +246,35 @@ class BooksView(QTableView): # {{{ self.sortByColumn(idx, Qt.DescendingOrder) else: self._model.sort_by_named_field(field, order, reset) + + def multisort(self, fields, reset=True, only_if_different=False): + if len(fields) == 0: + return + sh = self.cleanup_sort_history(self._model.sort_history) + if only_if_different and len(sh) >= len(fields): + ret=True + for i,t in enumerate(fields): + if t[0] != sh[i][0]: + ret = False + break + if ret: + return + + for n,d in reversed(fields): + if n in self._model.db.field_metadata.keys(): + sh.insert(0, (n, d)) + sh = self.cleanup_sort_history(sh) + self._model.sort_history = [tuple(x) for x in sh] + self._model.resort(reset=reset) + col = fields[0][0] + dir = Qt.AscendingOrder if fields[0][1] else Qt.DescendingOrder + if col in self.column_map: + col = self.column_map.index(col) + hdrs = self.horizontalHeader() + try: + hdrs.setSortIndicator(col, dir) + except: + pass # }}} # Ondevice column {{{ From 00937e80c462b4faf3a3eb0285cbd75c9d3a4da7 Mon Sep 17 00:00:00 2001 From: Charles Haley <> Date: Fri, 15 Apr 2011 13:22:46 +0100 Subject: [PATCH 5/5] ... --- src/calibre/gui2/library/views.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/calibre/gui2/library/views.py b/src/calibre/gui2/library/views.py index 840db906d6..48fbfb7291 100644 --- a/src/calibre/gui2/library/views.py +++ b/src/calibre/gui2/library/views.py @@ -250,7 +250,8 @@ class BooksView(QTableView): # {{{ def multisort(self, fields, reset=True, only_if_different=False): if len(fields) == 0: return - sh = self.cleanup_sort_history(self._model.sort_history) + sh = self.cleanup_sort_history(self._model.sort_history, + ignore_column_map=True) if only_if_different and len(sh) >= len(fields): ret=True for i,t in enumerate(fields): @@ -263,7 +264,7 @@ class BooksView(QTableView): # {{{ for n,d in reversed(fields): if n in self._model.db.field_metadata.keys(): sh.insert(0, (n, d)) - sh = self.cleanup_sort_history(sh) + sh = self.cleanup_sort_history(sh, ignore_column_map=True) self._model.sort_history = [tuple(x) for x in sh] self._model.resort(reset=reset) col = fields[0][0] @@ -319,14 +320,14 @@ class BooksView(QTableView): # {{{ state = self.get_state() self.write_state(state) - def cleanup_sort_history(self, sort_history): + def cleanup_sort_history(self, sort_history, ignore_column_map=False): history = [] for col, order in sort_history: if not isinstance(order, bool): continue if col == 'date': col = 'timestamp' - if col in self.column_map: + if ignore_column_map or col in self.column_map: if (not history or history[-1][0] != col): history.append([col, order]) return history