mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
API for multicol sort
This commit is contained in:
commit
388a5bb3c9
@ -310,7 +310,6 @@ class BooksModel(QAbstractTableModel): # {{{
|
|||||||
def sort(self, col, order, reset=True):
|
def sort(self, col, order, reset=True):
|
||||||
if not self.db:
|
if not self.db:
|
||||||
return
|
return
|
||||||
self.about_to_be_sorted.emit(self.db.id)
|
|
||||||
if not isinstance(order, bool):
|
if not isinstance(order, bool):
|
||||||
order = order == Qt.AscendingOrder
|
order = order == Qt.AscendingOrder
|
||||||
label = self.column_map[col]
|
label = self.column_map[col]
|
||||||
@ -321,6 +320,7 @@ class BooksModel(QAbstractTableModel): # {{{
|
|||||||
self._sort(field, order, reset)
|
self._sort(field, order, reset)
|
||||||
|
|
||||||
def _sort(self, label, order, reset):
|
def _sort(self, label, order, reset):
|
||||||
|
self.about_to_be_sorted.emit(self.db.id)
|
||||||
self.db.sort(label, order)
|
self.db.sort(label, order)
|
||||||
if reset:
|
if reset:
|
||||||
self.reset()
|
self.reset()
|
||||||
|
@ -246,6 +246,36 @@ class BooksView(QTableView): # {{{
|
|||||||
self.sortByColumn(idx, Qt.DescendingOrder)
|
self.sortByColumn(idx, Qt.DescendingOrder)
|
||||||
else:
|
else:
|
||||||
self._model.sort_by_named_field(field, order, reset)
|
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,
|
||||||
|
ignore_column_map=True)
|
||||||
|
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, ignore_column_map=True)
|
||||||
|
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 {{{
|
# Ondevice column {{{
|
||||||
@ -290,14 +320,14 @@ class BooksView(QTableView): # {{{
|
|||||||
state = self.get_state()
|
state = self.get_state()
|
||||||
self.write_state(state)
|
self.write_state(state)
|
||||||
|
|
||||||
def cleanup_sort_history(self, sort_history):
|
def cleanup_sort_history(self, sort_history, ignore_column_map=False):
|
||||||
history = []
|
history = []
|
||||||
for col, order in sort_history:
|
for col, order in sort_history:
|
||||||
if not isinstance(order, bool):
|
if not isinstance(order, bool):
|
||||||
continue
|
continue
|
||||||
if col == 'date':
|
if col == 'date':
|
||||||
col = 'timestamp'
|
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):
|
if (not history or history[-1][0] != col):
|
||||||
history.append([col, order])
|
history.append([col, order])
|
||||||
return history
|
return history
|
||||||
|
@ -592,7 +592,8 @@ class ResultCache(SearchQueryParser): # {{{
|
|||||||
candidates = self.universal_set()
|
candidates = self.universal_set()
|
||||||
if len(candidates) == 0:
|
if len(candidates) == 0:
|
||||||
return matches
|
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 \
|
if len(location) > 2 and location.startswith('@') and \
|
||||||
location[1:] in self.db_prefs['grouped_search_terms']:
|
location[1:] in self.db_prefs['grouped_search_terms']:
|
||||||
|
@ -19,8 +19,8 @@ If this module is run, it will perform a series of unit tests.
|
|||||||
import sys, string, operator
|
import sys, string, operator
|
||||||
|
|
||||||
from calibre.utils.pyparsing import CaselessKeyword, Group, Forward, \
|
from calibre.utils.pyparsing import CaselessKeyword, Group, Forward, \
|
||||||
CharsNotIn, Suppress, OneOrMore, MatchFirst, alphas, alphanums, \
|
CharsNotIn, Suppress, OneOrMore, MatchFirst, CaselessLiteral, \
|
||||||
Optional, ParseException, QuotedString, Word
|
Optional, NoMatch, ParseException, QuotedString
|
||||||
from calibre.constants import preferred_encoding
|
from calibre.constants import preferred_encoding
|
||||||
from calibre.utils.icu import sort_key
|
from calibre.utils.icu import sort_key
|
||||||
|
|
||||||
@ -128,9 +128,12 @@ class SearchQueryParser(object):
|
|||||||
self._tests_failed = False
|
self._tests_failed = False
|
||||||
self.optimize = optimize
|
self.optimize = optimize
|
||||||
# Define a token
|
# Define a token
|
||||||
self.standard_locations = locations
|
standard_locations = map(lambda x : CaselessLiteral(x)+Suppress(':'),
|
||||||
location = Optional(Word(alphas+'#', bodyChars=alphanums+'_')+Suppress(':'),
|
locations)
|
||||||
default='all')
|
location = NoMatch()
|
||||||
|
for l in standard_locations:
|
||||||
|
location |= l
|
||||||
|
location = Optional(location, default='all')
|
||||||
word_query = CharsNotIn(string.whitespace + '()')
|
word_query = CharsNotIn(string.whitespace + '()')
|
||||||
#quoted_query = Suppress('"')+CharsNotIn('"')+Suppress('"')
|
#quoted_query = Suppress('"')+CharsNotIn('"')+Suppress('"')
|
||||||
quoted_query = QuotedString('"', escChar='\\')
|
quoted_query = QuotedString('"', escChar='\\')
|
||||||
@ -247,14 +250,7 @@ class SearchQueryParser(object):
|
|||||||
raise ParseException(query, len(query), 'undefined saved search', self)
|
raise ParseException(query, len(query), 'undefined saved search', self)
|
||||||
return self._get_matches(location, query, candidates)
|
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):
|
def _get_matches(self, location, query, candidates):
|
||||||
location = location.lower()
|
|
||||||
self.test_location_is_valid(location, query)
|
|
||||||
if self.optimize:
|
if self.optimize:
|
||||||
return self.get_matches(location, query, candidates=candidates)
|
return self.get_matches(location, query, candidates=candidates)
|
||||||
else:
|
else:
|
||||||
|
Loading…
x
Reference in New Issue
Block a user