diff --git a/src/calibre/gui2/library/models.py b/src/calibre/gui2/library/models.py index 49cb1ce182..6a48aef9be 100644 --- a/src/calibre/gui2/library/models.py +++ b/src/calibre/gui2/library/models.py @@ -526,7 +526,7 @@ class BooksModel(QAbstractTableModel): # {{{ def tags(r, idx=-1): tags = self.db.data[r][idx] if tags: - return QVariant(', '.join(sorted(tags.split(','), key=sort_key))) + return QVariant(', '.join(tags.split(','))) return None def series_type(r, idx=-1, siix=-1): @@ -577,7 +577,7 @@ class BooksModel(QAbstractTableModel): # {{{ def text_type(r, mult=False, idx=-1): text = self.db.data[r][idx] if text and mult: - return QVariant(', '.join(sorted(text.split('|'),key=sort_key))) + return QVariant(', '.join(text.split('|'))) return QVariant(text) def number_type(r, idx=-1): diff --git a/src/calibre/library/custom_columns.py b/src/calibre/library/custom_columns.py index 07ea407460..558f3b8fc9 100644 --- a/src/calibre/library/custom_columns.py +++ b/src/calibre/library/custom_columns.py @@ -14,6 +14,7 @@ from calibre.constants import preferred_encoding from calibre.library.field_metadata import FieldMetadata from calibre.utils.date import parse_date from calibre.utils.config import tweaks +from calibre.utils.icu import sort_key class CustomColumns(object): @@ -181,8 +182,8 @@ class CustomColumns(object): ans = row[self.FIELD_MAP[data['num']]] if data['is_multiple'] and data['datatype'] == 'text': ans = ans.split('|') if ans else [] - if data['display'].get('sort_alpha', False): - ans.sort(cmp=lambda x,y:cmp(x.lower(), y.lower())) + if data['display'].get('sort_alpha', True): + ans.sort(key=sort_key) return ans def get_custom_extra(self, idx, label=None, num=None, index_is_id=False): @@ -534,8 +535,8 @@ class CustomColumns(object): if data['normalized']: query = '%s.value' if data['is_multiple']: - query = 'group_concat(%s.value, "|")' - if not display.get('sort_alpha', False): + query = 'cc_sortconcat(%s.value)' + if not display.get('sort_alpha', True): query = 'sort_concat(link.id, %s.value)' line = '''(SELECT {query} FROM {lt} AS link INNER JOIN {table} ON(link.value={table}.id) WHERE link.book=books.id) diff --git a/src/calibre/library/database2.py b/src/calibre/library/database2.py index 611aa1cc89..0b1c6a6cfb 100644 --- a/src/calibre/library/database2.py +++ b/src/calibre/library/database2.py @@ -242,7 +242,7 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns): 'timestamp', '(SELECT MAX(uncompressed_size) FROM data WHERE book=books.id) size', ('rating', 'ratings', 'rating', 'ratings.rating'), - ('tags', 'tags', 'tag', 'group_concat(name)'), + ('tags', 'tags', 'tag', 'tags_sortconcat(name)'), '(SELECT text FROM comments WHERE book=books.id) comments', ('series', 'series', 'series', 'name'), ('publisher', 'publishers', 'publisher', 'name'), diff --git a/src/calibre/library/sqlite.py b/src/calibre/library/sqlite.py index 0458ada27b..0c3ae487ea 100644 --- a/src/calibre/library/sqlite.py +++ b/src/calibre/library/sqlite.py @@ -19,7 +19,7 @@ from calibre.ebooks.metadata import title_sort, author_to_author_sort from calibre.utils.date import parse_date, isoformat from calibre import isbytestring, force_unicode from calibre.constants import iswindows, DEBUG -from calibre.utils.icu import strcmp +from calibre.utils.icu import strcmp, sort_key global_lock = RLock() @@ -69,6 +69,25 @@ class Concatenate(object): return None return self.sep.join(self.ans) +class TagsSortConcatenate(object): + '''Sorted string concatenation aggregator for sqlite''' + def __init__(self, sep=','): + self.sep = sep + self.ans = [] + + def step(self, value): + if value is not None: + self.ans.append(value) + + def finalize(self): + if not self.ans: + return None + return self.sep.join(sorted(self.ans, key=sort_key)) + +class CcSortConcatenate(TagsSortConcatenate): + def __init__(self): + TagsSortConcatenate.__init__(self, sep='|') + class SortedConcatenate(object): '''String concatenation aggregator for sqlite, sorted by supplied index''' sep = ',' @@ -155,6 +174,8 @@ class DBThread(Thread): c_ext_loaded = load_c_extensions(self.conn) self.conn.row_factory = sqlite.Row if self.row_factory else lambda cursor, row : list(row) self.conn.create_aggregate('concat', 1, Concatenate) + self.conn.create_aggregate('tags_sortconcat', 1, TagsSortConcatenate) + self.conn.create_aggregate('cc_sortconcat', 1, CcSortConcatenate) if not c_ext_loaded: self.conn.create_aggregate('sortconcat', 2, SortedConcatenate) self.conn.create_aggregate('sort_concat', 2, SafeSortedConcatenate)