mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Make sorting on the device view faster and more robust. Fixes #742626 (Error when transferring to iTunes)
This commit is contained in:
parent
671022e3c2
commit
df6fabfff4
@ -7,7 +7,6 @@ __docformat__ = 'restructuredtext en'
|
|||||||
|
|
||||||
import shutil, functools, re, os, traceback
|
import shutil, functools, re, os, traceback
|
||||||
from contextlib import closing
|
from contextlib import closing
|
||||||
from operator import attrgetter
|
|
||||||
|
|
||||||
from PyQt4.Qt import QAbstractTableModel, Qt, pyqtSignal, QIcon, QImage, \
|
from PyQt4.Qt import QAbstractTableModel, Qt, pyqtSignal, QIcon, QImage, \
|
||||||
QModelIndex, QVariant, QDate, QColor
|
QModelIndex, QVariant, QDate, QColor
|
||||||
@ -18,7 +17,7 @@ from calibre.ebooks.metadata import fmt_sidx, authors_to_string, string_to_autho
|
|||||||
from calibre.ptempfile import PersistentTemporaryFile
|
from calibre.ptempfile import PersistentTemporaryFile
|
||||||
from calibre.utils.config import tweaks, prefs
|
from calibre.utils.config import tweaks, prefs
|
||||||
from calibre.utils.date import dt_factory, qt_to_dt, isoformat
|
from calibre.utils.date import dt_factory, qt_to_dt, isoformat
|
||||||
from calibre.utils.icu import sort_key, strcmp as icu_strcmp
|
from calibre.utils.icu import sort_key
|
||||||
from calibre.ebooks.metadata.meta import set_metadata as _set_metadata
|
from calibre.ebooks.metadata.meta import set_metadata as _set_metadata
|
||||||
from calibre.utils.search_query_parser import SearchQueryParser
|
from calibre.utils.search_query_parser import SearchQueryParser
|
||||||
from calibre.library.caches import _match, CONTAINS_MATCH, EQUALS_MATCH, \
|
from calibre.library.caches import _match, CONTAINS_MATCH, EQUALS_MATCH, \
|
||||||
@ -984,6 +983,21 @@ class OnDeviceSearch(SearchQueryParser): # {{{
|
|||||||
|
|
||||||
# }}}
|
# }}}
|
||||||
|
|
||||||
|
class DeviceDBSortKeyGen(object): # {{{
|
||||||
|
|
||||||
|
def __init__(self, attr, keyfunc, db):
|
||||||
|
self.attr = attr
|
||||||
|
self.db = db
|
||||||
|
self.keyfunc = keyfunc
|
||||||
|
|
||||||
|
def __call__(self, x):
|
||||||
|
try:
|
||||||
|
ans = self.keyfunc(getattr(self.db[x], self.attr))
|
||||||
|
except:
|
||||||
|
ans = None
|
||||||
|
return ans
|
||||||
|
# }}}
|
||||||
|
|
||||||
class DeviceBooksModel(BooksModel): # {{{
|
class DeviceBooksModel(BooksModel): # {{{
|
||||||
|
|
||||||
booklist_dirtied = pyqtSignal()
|
booklist_dirtied = pyqtSignal()
|
||||||
@ -1089,59 +1103,40 @@ class DeviceBooksModel(BooksModel): # {{{
|
|||||||
|
|
||||||
def sort(self, col, order, reset=True):
|
def sort(self, col, order, reset=True):
|
||||||
descending = order != Qt.AscendingOrder
|
descending = order != Qt.AscendingOrder
|
||||||
def strcmp(attr):
|
|
||||||
ag = attrgetter(attr)
|
|
||||||
def _strcmp(x, y):
|
|
||||||
x = ag(self.db[x])
|
|
||||||
y = ag(self.db[y])
|
|
||||||
if x == None:
|
|
||||||
x = ''
|
|
||||||
if y == None:
|
|
||||||
y = ''
|
|
||||||
return icu_strcmp(x.strip(), y.strip())
|
|
||||||
return _strcmp
|
|
||||||
def datecmp(x, y):
|
|
||||||
x = self.db[x].datetime
|
|
||||||
y = self.db[y].datetime
|
|
||||||
return cmp(dt_factory(x, assume_utc=True), dt_factory(y,
|
|
||||||
assume_utc=True))
|
|
||||||
def sizecmp(x, y):
|
|
||||||
x, y = int(self.db[x].size), int(self.db[y].size)
|
|
||||||
return cmp(x, y)
|
|
||||||
def tagscmp(x, y):
|
|
||||||
x = ','.join(sorted(getattr(self.db[x], 'device_collections', []),key=sort_key))
|
|
||||||
y = ','.join(sorted(getattr(self.db[y], 'device_collections', []),key=sort_key))
|
|
||||||
return cmp(x, y)
|
|
||||||
def libcmp(x, y):
|
|
||||||
x, y = self.db[x].in_library, self.db[y].in_library
|
|
||||||
return cmp(x, y)
|
|
||||||
def authorcmp(x, y):
|
|
||||||
ax = getattr(self.db[x], 'author_sort', None)
|
|
||||||
ay = getattr(self.db[y], 'author_sort', None)
|
|
||||||
if ax and ay:
|
|
||||||
x = ax
|
|
||||||
y = ay
|
|
||||||
else:
|
|
||||||
x, y = authors_to_string(self.db[x].authors), \
|
|
||||||
authors_to_string(self.db[y].authors)
|
|
||||||
return cmp(x, y)
|
|
||||||
cname = self.column_map[col]
|
cname = self.column_map[col]
|
||||||
fcmp = {
|
def author_key(x):
|
||||||
'title': strcmp('title_sorter'),
|
try:
|
||||||
'authors' : authorcmp,
|
ax = self.db[x].author_sort
|
||||||
'size' : sizecmp,
|
if not ax:
|
||||||
'timestamp': datecmp,
|
raise Exception('')
|
||||||
'collections': tagscmp,
|
except:
|
||||||
'inlibrary': libcmp,
|
try:
|
||||||
|
ax = authors_to_string(self.db[x].authors)
|
||||||
|
except:
|
||||||
|
ax = ''
|
||||||
|
return ax
|
||||||
|
|
||||||
|
keygen = {
|
||||||
|
'title': ('title_sorter', lambda x: sort_key(x) if x else ''),
|
||||||
|
'authors' : author_key,
|
||||||
|
'size' : ('size', int),
|
||||||
|
'timestamp': ('datetime', functools.partial(dt_factory, assume_utc=True)),
|
||||||
|
'collections': ('device_collections', lambda x:sorted(x,
|
||||||
|
key=sort_key)),
|
||||||
|
'inlibrary': ('in_library', lambda x: x),
|
||||||
}[cname]
|
}[cname]
|
||||||
self.map.sort(cmp=fcmp, reverse=descending)
|
keygen = keygen if callable(keygen) else DeviceDBSortKeyGen(
|
||||||
|
keygen[0], keygen[1], self.db)
|
||||||
|
self.map.sort(key=keygen, reverse=descending)
|
||||||
if len(self.map) == len(self.db):
|
if len(self.map) == len(self.db):
|
||||||
self.sorted_map = list(self.map)
|
self.sorted_map = list(self.map)
|
||||||
else:
|
else:
|
||||||
self.sorted_map = list(range(len(self.db)))
|
self.sorted_map = list(range(len(self.db)))
|
||||||
self.sorted_map.sort(cmp=fcmp, reverse=descending)
|
self.sorted_map.sort(cmp=keygen, reverse=descending)
|
||||||
self.sorted_on = (self.column_map[col], order)
|
self.sorted_on = (self.column_map[col], order)
|
||||||
self.sort_history.insert(0, self.sorted_on)
|
self.sort_history.insert(0, self.sorted_on)
|
||||||
|
if hasattr(keygen, 'db'):
|
||||||
|
keygen.db = None
|
||||||
if reset:
|
if reset:
|
||||||
self.reset()
|
self.reset()
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user