Refactor to use new sort_keys function

This commit is contained in:
Charles Haley 2010-12-04 12:26:13 +00:00
parent 39447744f8
commit f8920d18bb
27 changed files with 104 additions and 84 deletions

View File

@ -13,6 +13,7 @@ from calibre.devices.interface import BookList as _BookList
from calibre.constants import preferred_encoding
from calibre import isbytestring
from calibre.utils.config import prefs, tweaks
from calibre.utils.icu import sort_key
class Book(Metadata):
def __init__(self, prefix, lpath, size=None, other=None):
@ -230,14 +231,16 @@ class CollectionsBookList(BookList):
x = xx[1]
y = yy[1]
if x is None and y is None:
# No sort_key needed here, because defaults are ascii
return cmp(xx[2], yy[2])
if x is None:
return 1
if y is None:
return -1
c = cmp(x, y)
c = cmp(sort_key(x), sort_key(y))
if c != 0:
return c
# same as above -- no sort_key needed here
return cmp(xx[2], yy[2])
for category, lpaths in collections.items():

View File

@ -16,6 +16,7 @@ from calibre.gui2.dialogs.metadata_bulk import MetadataBulkDialog
from calibre.gui2.dialogs.confirm_delete import confirm
from calibre.gui2.dialogs.tag_list_editor import TagListEditor
from calibre.gui2.actions import InterfaceAction
from calibre.utils.icu import sort_key
class EditMetadataAction(InterfaceAction):
@ -363,8 +364,7 @@ class EditMetadataAction(InterfaceAction):
def edit_device_collections(self, view, oncard=None):
model = view.model()
result = model.get_collections_with_ids()
compare = (lambda x,y:cmp(x.lower(), y.lower()))
d = TagListEditor(self.gui, tag_to_match=None, data=result, compare=compare)
d = TagListEditor(self.gui, tag_to_match=None, data=result, key=sort_key)
d.exec_()
if d.result() == d.Accepted:
to_rename = d.to_rename # dict of new text to old ids

View File

@ -19,6 +19,7 @@ from calibre.ebooks import BOOK_EXTENSIONS
from calibre.constants import preferred_encoding
from calibre.library.comments import comments_to_html
from calibre.gui2 import config, open_local_file
from calibre.utils.icu import sort_key
# render_rows(data) {{{
WEIGHTS = collections.defaultdict(lambda : 100)
@ -31,8 +32,8 @@ WEIGHTS[_('Tags')] = 4
def render_rows(data):
keys = data.keys()
# First sort by name. The WEIGHTS sort will preserve this sub-order
keys.sort(cmp=lambda x, y: cmp(x.lower(), y.lower()))
keys.sort(cmp=lambda x, y: cmp(WEIGHTS[x], WEIGHTS[y]))
keys.sort(key=sort_key)
keys.sort(key=lambda x: WEIGHTS[x])
rows = []
for key in keys:
txt = data[key]

View File

@ -17,6 +17,7 @@ from calibre.ebooks.metadata import authors_to_string, string_to_authors, \
from calibre.ebooks.metadata.opf2 import metadata_to_opf
from calibre.ptempfile import PersistentTemporaryFile
from calibre.gui2.convert import Widget
from calibre.utils.icu import sort_key
def create_opf_file(db, book_id):
mi = db.get_metadata(book_id, index_is_id=True)
@ -102,7 +103,7 @@ class MetadataWidget(Widget, Ui_Form):
def initalize_authors(self):
all_authors = self.db.all_authors()
all_authors.sort(cmp=lambda x, y : cmp(x[1], y[1]))
all_authors.sort(key=lambda x : sort_key(x[1]))
for i in all_authors:
id, name = i
@ -117,7 +118,7 @@ class MetadataWidget(Widget, Ui_Form):
def initialize_series(self):
all_series = self.db.all_series()
all_series.sort(cmp=lambda x, y : cmp(x[1], y[1]))
all_series.sort(key=lambda x : sort_key(x[1]))
for i in all_series:
id, name = i
@ -126,7 +127,7 @@ class MetadataWidget(Widget, Ui_Form):
def initialize_publisher(self):
all_publishers = self.db.all_publishers()
all_publishers.sort(cmp=lambda x, y : cmp(x[1], y[1]))
all_publishers.sort(key=lambda x : sort_key(x[1]))
for i in all_publishers:
id, name = i

View File

@ -17,6 +17,7 @@ from calibre.utils.date import qt_to_dt, now
from calibre.gui2.widgets import TagsLineEdit, EnComboBox
from calibre.gui2 import UNDEFINED_QDATE, error_dialog
from calibre.utils.config import tweaks
from calibre.utils.icu import sort_key
class Base(object):
@ -207,7 +208,7 @@ class Text(Base):
def setup_ui(self, parent):
values = self.all_values = list(self.db.all_custom(num=self.col_id))
values.sort(cmp = lambda x,y: cmp(x.lower(), y.lower()))
values.sort(key=sort_key)
if self.col_metadata['is_multiple']:
w = TagsLineEdit(parent, values)
w.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Preferred)
@ -256,7 +257,7 @@ class Series(Base):
def setup_ui(self, parent):
values = self.all_values = list(self.db.all_custom(num=self.col_id))
values.sort(cmp = lambda x,y: cmp(x.lower(), y.lower()))
values.sort(key=sort_key)
w = EnComboBox(parent)
w.setSizeAdjustPolicy(w.AdjustToMinimumContentsLengthWithIcon)
w.setMinimumContentsLength(25)
@ -369,7 +370,7 @@ def field_sort(y, z, x=None):
m1, m2 = x[y], x[z]
n1 = 'zzzzz' if m1['datatype'] == 'comments' else m1['name']
n2 = 'zzzzz' if m2['datatype'] == 'comments' else m2['name']
return cmp(n1.lower(), n2.lower())
return cmp(sort_key(n1), sort_key(n2))
def populate_metadata_page(layout, db, book_id, bulk=False, two_column=False, parent=None):
def widget_factory(type, col):
@ -526,7 +527,7 @@ class BulkSeries(BulkBase):
def setup_ui(self, parent):
values = self.all_values = list(self.db.all_custom(num=self.col_id))
values.sort(cmp = lambda x,y: cmp(x.lower(), y.lower()))
values.sort(key=sort_key)
w = EnComboBox(parent)
w.setSizeAdjustPolicy(w.AdjustToMinimumContentsLengthWithIcon)
w.setMinimumContentsLength(25)
@ -678,7 +679,7 @@ class BulkText(BulkBase):
def setup_ui(self, parent):
values = self.all_values = list(self.db.all_custom(num=self.col_id))
values.sort(cmp = lambda x,y: cmp(x.lower(), y.lower()))
values.sort(key=sort_key)
if self.col_metadata['is_multiple']:
w = TagsLineEdit(parent, values)
w.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Preferred)

View File

@ -17,6 +17,7 @@ from calibre.gui2 import error_dialog
from calibre.gui2.progress_indicator import ProgressIndicator
from calibre.utils.config import dynamic
from calibre.utils.titlecase import titlecase
from calibre.utils.icu import sort_key
class MyBlockingBusy(QDialog):
@ -594,7 +595,7 @@ class MetadataBulkDialog(QDialog, Ui_MetadataBulkDialog):
def initalize_authors(self):
all_authors = self.db.all_authors()
all_authors.sort(cmp=lambda x, y : cmp(x[1].lower(), y[1].lower()))
all_authors.sort(key=lambda x : sort_key(x[1]))
for i in all_authors:
id, name = i
@ -604,7 +605,7 @@ class MetadataBulkDialog(QDialog, Ui_MetadataBulkDialog):
def initialize_series(self):
all_series = self.db.all_series()
all_series.sort(cmp=lambda x, y : cmp(x[1], y[1]))
all_series.sort(key=lambda x : sort_key(x[1]))
for i in all_series:
id, name = i
@ -613,7 +614,7 @@ class MetadataBulkDialog(QDialog, Ui_MetadataBulkDialog):
def initialize_publisher(self):
all_publishers = self.db.all_publishers()
all_publishers.sort(cmp=lambda x, y : cmp(x[1], y[1]))
all_publishers.sort(key=lambda x : sort_key(x[1]))
for i in all_publishers:
id, name = i

View File

@ -28,6 +28,7 @@ from calibre.ebooks.metadata.meta import get_metadata
from calibre.ebooks.metadata import MetaInformation
from calibre.utils.config import prefs, tweaks
from calibre.utils.date import qt_to_dt, local_tz, utcfromtimestamp
from calibre.utils.icu import sort_key
from calibre.customize.ui import run_plugins_on_import, get_isbndb_key
from calibre.gui2.preferences.social import SocialMetadata
from calibre.gui2.custom_column_widgets import populate_metadata_page
@ -660,7 +661,7 @@ class MetadataSingleDialog(ResizableDialog, Ui_MetadataSingleDialog):
def initalize_authors(self):
all_authors = self.db.all_authors()
all_authors.sort(cmp=lambda x, y : cmp(x[1], y[1]))
all_authors.sort(key=lambda x : sort_key(x[1]))
for i in all_authors:
id, name = i
name = [name.strip().replace('|', ',') for n in name.split(',')]
@ -675,7 +676,7 @@ class MetadataSingleDialog(ResizableDialog, Ui_MetadataSingleDialog):
def initialize_series(self):
self.series.setSizeAdjustPolicy(self.series.AdjustToContentsOnFirstShow)
all_series = self.db.all_series()
all_series.sort(cmp=lambda x, y : cmp(x[1], y[1]))
all_series.sort(key=lambda x : sort_key(x[1]))
series_id = self.db.series_id(self.row)
idx, c = None, 0
for i in all_series:
@ -692,7 +693,7 @@ class MetadataSingleDialog(ResizableDialog, Ui_MetadataSingleDialog):
def initialize_publisher(self):
all_publishers = self.db.all_publishers()
all_publishers.sort(cmp=lambda x, y : cmp(x[1], y[1]))
all_publishers.sort(key=lambda x : sort_key(x[1]))
publisher_id = self.db.publisher_id(self.row)
idx, c = None, 0
for i in all_publishers:

View File

@ -8,6 +8,7 @@ from PyQt4.QtGui import QDialog
from calibre.gui2.dialogs.saved_search_editor_ui import Ui_SavedSearchEditor
from calibre.utils.search_query_parser import saved_searches
from calibre.utils.icu import sort_key
from calibre.gui2.dialogs.confirm_delete import confirm
class SavedSearchEditor(QDialog, Ui_SavedSearchEditor):
@ -34,7 +35,7 @@ class SavedSearchEditor(QDialog, Ui_SavedSearchEditor):
def populate_search_list(self):
self.search_name_box.clear()
for name in sorted(self.searches.keys()):
for name in sorted(self.searches.keys(), key=sort_key):
self.search_name_box.addItem(name)
def add_search(self):

View File

@ -8,6 +8,7 @@ from PyQt4.QtGui import QDialog, QDialogButtonBox
from calibre.gui2.dialogs.search_ui import Ui_Dialog
from calibre.library.caches import CONTAINS_MATCH, EQUALS_MATCH
from calibre.gui2 import gprefs
from calibre.utils.icu import sort_key
box_values = {}
@ -18,8 +19,7 @@ class SearchDialog(QDialog, Ui_Dialog):
self.setupUi(self)
self.mc = ''
searchables = sorted(db.field_metadata.searchable_fields(),
lambda x, y: cmp(x if x[0] != '#' else x[1:],
y if y[0] != '#' else y[1:]))
key=lambda x: sort_key(x if x[0] != '#' else x[1:]))
self.general_combo.addItems(searchables)
self.box_last_values = copy.deepcopy(box_values)

View File

@ -9,6 +9,7 @@ from PyQt4.QtGui import QDialog, QIcon, QListWidgetItem
from calibre.gui2.dialogs.tag_categories_ui import Ui_TagCategories
from calibre.gui2.dialogs.confirm_delete import confirm
from calibre.constants import islinux
from calibre.utils.icu import sort_key
class Item:
def __init__(self, name, label, index, icon, exists):
@ -85,7 +86,7 @@ class TagCategories(QDialog, Ui_TagCategories):
# remove any references to a category that no longer exists
del self.categories[cat][item]
self.all_items_sorted = sorted(self.all_items, cmp=lambda x,y: cmp(x.name.lower(), y.name.lower()))
self.all_items_sorted = sorted(self.all_items, key=lambda x: sort_key(x.name))
self.display_filtered_categories(0)
for v in category_names:
@ -135,7 +136,7 @@ class TagCategories(QDialog, Ui_TagCategories):
index = self.all_items[node.data(Qt.UserRole).toPyObject()].index
if index not in self.applied_items:
self.applied_items.append(index)
self.applied_items.sort(cmp=lambda x, y:cmp(self.all_items[x].name.lower(), self.all_items[y].name.lower()))
self.applied_items.sort(key=lambda x:sort_key(self.all_items[x]))
self.display_filtered_categories(None)
def unapply_tags(self, node=None):
@ -198,5 +199,5 @@ class TagCategories(QDialog, Ui_TagCategories):
self.categories[self.current_cat_name] = l
def populate_category_list(self):
for n in sorted(self.categories.keys(), cmp=lambda x,y: cmp(x.lower(), y.lower())):
for n in sorted(self.categories.keys(), key=sort_key):
self.category_box.addItem(n)

View File

@ -6,12 +6,10 @@ from PyQt4.QtGui import QDialog
from calibre.gui2.dialogs.tag_editor_ui import Ui_TagEditor
from calibre.gui2 import question_dialog, error_dialog
from calibre.constants import islinux
from calibre.utils.icu import sort_key
class TagEditor(QDialog, Ui_TagEditor):
def tag_cmp(self, x, y):
return cmp(x.lower(), y.lower())
def __init__(self, window, db, index=None):
QDialog.__init__(self, window)
Ui_TagEditor.__init__(self)
@ -25,7 +23,7 @@ class TagEditor(QDialog, Ui_TagEditor):
tags = []
if tags:
tags = [tag.strip() for tag in tags.split(',') if tag.strip()]
tags.sort(cmp=self.tag_cmp)
tags.sort(key=sort_key)
for tag in tags:
self.applied_tags.addItem(tag)
else:
@ -35,7 +33,7 @@ class TagEditor(QDialog, Ui_TagEditor):
all_tags = [tag for tag in self.db.all_tags()]
all_tags = list(set(all_tags))
all_tags.sort(cmp=self.tag_cmp)
all_tags.sort(key=sort_key)
for tag in all_tags:
if tag not in tags:
self.available_tags.addItem(tag)
@ -82,7 +80,7 @@ class TagEditor(QDialog, Ui_TagEditor):
self.tags.append(tag)
self.available_tags.takeItem(self.available_tags.row(item))
self.tags.sort(cmp=self.tag_cmp)
self.tags.sort(key=sort_key)
self.applied_tags.clear()
for tag in self.tags:
self.applied_tags.addItem(tag)
@ -96,14 +94,14 @@ class TagEditor(QDialog, Ui_TagEditor):
self.tags.remove(tag)
self.available_tags.addItem(tag)
self.tags.sort(cmp=self.tag_cmp)
self.tags.sort(key=sort_key)
self.applied_tags.clear()
for tag in self.tags:
self.applied_tags.addItem(tag)
items = [unicode(self.available_tags.item(x).text()) for x in
range(self.available_tags.count())]
items.sort(cmp=self.tag_cmp)
items.sort(key=sort_key)
self.available_tags.clear()
for item in items:
self.available_tags.addItem(item)
@ -117,7 +115,7 @@ class TagEditor(QDialog, Ui_TagEditor):
if tag not in self.tags:
self.tags.append(tag)
self.tags.sort(cmp=self.tag_cmp)
self.tags.sort(key=sort_key)
self.applied_tags.clear()
for tag in self.tags:
self.applied_tags.addItem(tag)

View File

@ -39,7 +39,7 @@ class ListWidgetItem(QListWidgetItem):
class TagListEditor(QDialog, Ui_TagListEditor):
def __init__(self, window, tag_to_match, data, compare):
def __init__(self, window, tag_to_match, data, key):
QDialog.__init__(self, window)
Ui_TagListEditor.__init__(self)
self.setupUi(self)
@ -54,7 +54,7 @@ class TagListEditor(QDialog, Ui_TagListEditor):
for k,v in data:
self.all_tags[v] = k
for tag in sorted(self.all_tags.keys(), cmp=compare):
for tag in sorted(self.all_tags.keys(), key=key):
item = ListWidgetItem(tag)
item.setData(Qt.UserRole, self.all_tags[tag])
self.available_tags.addItem(item)

View File

@ -13,6 +13,7 @@ from calibre.gui2 import error_dialog, question_dialog, open_url, \
choose_files, ResizableDialog, NONE
from calibre.gui2.widgets import PythonHighlighter
from calibre.ptempfile import PersistentTemporaryFile
from calibre.utils.icu import sort_key
class CustomRecipeModel(QAbstractListModel):
@ -256,7 +257,7 @@ class %(classname)s(%(base_class)s):
def add_builtin_recipe(self):
from calibre.web.feeds.recipes.collection import \
get_builtin_recipe_by_title, get_builtin_recipe_titles
items = sorted(get_builtin_recipe_titles())
items = sorted(get_builtin_recipe_titles(), key=sort_key)
title, ok = QInputDialog.getItem(self, _('Pick recipe'), _('Pick the recipe to customize'),

View File

@ -20,6 +20,7 @@ from calibre.gui2.widgets import EnLineEdit, TagsLineEdit
from calibre.utils.date import now, format_date
from calibre.utils.config import tweaks
from calibre.utils.formatter import validation_formatter
from calibre.utils.icu import sort_key
from calibre.gui2.dialogs.comments_dialog import CommentsDialog
class RatingDelegate(QStyledItemDelegate): # {{{
@ -173,7 +174,8 @@ class TagsDelegate(QStyledItemDelegate): # {{{
editor = TagsLineEdit(parent, self.db.all_tags())
else:
editor = TagsLineEdit(parent,
sorted(list(self.db.all_custom(label=self.db.field_metadata.key_to_label(col)))))
sorted(list(self.db.all_custom(label=self.db.field_metadata.key_to_label(col))),
key=sort_key))
return editor
else:
editor = EnLineEdit(parent)
@ -245,7 +247,8 @@ class CcTextDelegate(QStyledItemDelegate): # {{{
editor.setDecimals(2)
else:
editor = EnLineEdit(parent)
complete_items = sorted(list(m.db.all_custom(label=m.db.field_metadata.key_to_label(col))))
complete_items = sorted(list(m.db.all_custom(label=m.db.field_metadata.key_to_label(col))),
key=sort_key)
completer = QCompleter(complete_items, self)
completer.setCaseSensitivity(Qt.CaseInsensitive)
completer.setCompletionMode(QCompleter.PopupCompletion)

View File

@ -18,6 +18,7 @@ from calibre.ebooks.metadata import fmt_sidx, authors_to_string, string_to_autho
from calibre.ptempfile import PersistentTemporaryFile
from calibre.utils.config import tweaks, prefs
from calibre.utils.date import dt_factory, qt_to_dt, isoformat
from calibre.utils.icu import sort_key
from calibre.ebooks.metadata.meta import set_metadata as _set_metadata
from calibre.utils.search_query_parser import SearchQueryParser
from calibre.library.caches import _match, CONTAINS_MATCH, EQUALS_MATCH, \
@ -305,9 +306,10 @@ class BooksModel(QAbstractTableModel): # {{{
cdata = self.cover(idx)
if cdata:
data['cover'] = cdata
tags = self.db.tags(idx)
tags = list(self.db.get_tags(self.db.id(idx)))
if tags:
tags = tags.replace(',', ', ')
tags.sort(key=sort_key)
tags = ', '.join(tags)
else:
tags = _('None')
data[_('Tags')] = tags
@ -544,7 +546,7 @@ class BooksModel(QAbstractTableModel): # {{{
def tags(r, idx=-1):
tags = self.db.data[r][idx]
if tags:
return QVariant(', '.join(sorted(tags.split(','))))
return QVariant(', '.join(sorted(tags.split(','), key=sort_key)))
return None
def series_type(r, idx=-1, siix=-1):
@ -595,7 +597,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('|'))))
return QVariant(', '.join(sorted(text.split('|'),key=sort_key)))
return QVariant(text)
def number_type(r, idx=-1):
@ -1033,8 +1035,8 @@ class DeviceBooksModel(BooksModel): # {{{
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', []))).lower()
y = ','.join(sorted(getattr(self.db[y], 'device_collections', []))).lower()
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
@ -1211,7 +1213,7 @@ class DeviceBooksModel(BooksModel): # {{{
elif cname == 'collections':
tags = self.db[self.map[row]].device_collections
if tags:
tags.sort(cmp=lambda x,y: cmp(x.lower(), y.lower()))
tags.sort(key=sort_key)
return QVariant(', '.join(tags))
elif DEBUG and cname == 'inlibrary':
return QVariant(self.db[self.map[row]].in_library)

View File

@ -19,6 +19,7 @@ from calibre.utils.search_query_parser import saved_searches
from calibre.ebooks import BOOK_EXTENSIONS
from calibre.ebooks.oeb.iterator import is_supported
from calibre.constants import iswindows
from calibre.utils.icu import sort_key
class ConfigWidget(ConfigWidgetBase, Ui_Form):
@ -45,8 +46,7 @@ class ConfigWidget(ConfigWidgetBase, Ui_Form):
choices = [(x.upper(), x) for x in output_formats]
r('output_format', prefs, choices=choices)
restrictions = sorted(saved_searches().names(),
cmp=lambda x,y: cmp(x.lower(), y.lower()))
restrictions = sorted(saved_searches().names(), key=sort_key)
choices = [('', '')] + [(x, x) for x in restrictions]
r('gui_restriction', db.prefs, choices=choices)
r('new_book_tags', prefs, setting=CommaSeparatedList)

View File

@ -17,6 +17,7 @@ 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.search_query_parser import saved_searches
from calibre.utils.icu import sort_key
class SearchLineEdit(QLineEdit): # {{{
key_pressed = pyqtSignal(object)
@ -417,7 +418,7 @@ class SavedSearchBoxMixin(object): # {{{
b.setStatusTip(b.toolTip())
def saved_searches_changed(self):
p = sorted(saved_searches().names(), cmp=lambda x,y: cmp(x.lower(), y.lower()))
p = sorted(saved_searches().names(), key=sort_key)
t = unicode(self.search_restriction.currentText())
# rebuild the restrictions combobox using current saved searches
self.search_restriction.clear()

View File

@ -14,6 +14,7 @@ from PyQt4.Qt import QAbstractListModel, Qt, QKeySequence, QListView, \
from calibre.gui2 import NONE, error_dialog
from calibre.utils.config import XMLConfig
from calibre.utils.icu import sort_key
from calibre.gui2.shortcuts_ui import Ui_Frame
DEFAULTS = Qt.UserRole
@ -175,8 +176,7 @@ class Shortcuts(QAbstractListModel):
for k, v in shortcuts.items():
self.keys[k] = v[0]
self.order = list(shortcuts)
self.order.sort(cmp=lambda x,y : cmp(self.descriptions[x],
self.descriptions[y]))
self.order.sort(key=lambda x : sort_key(self.descriptions[x]))
self.sequences = {}
for k, v in self.keys.items():
self.sequences[k] = [QKeySequence(x) for x in v]

View File

@ -18,6 +18,7 @@ from PyQt4.Qt import Qt, QTreeView, QApplication, pyqtSignal, \
from calibre.ebooks.metadata import title_sort
from calibre.gui2 import config, NONE
from calibre.library.field_metadata import TagsIcons, category_icon_map
from calibre.utils.icu import sort_key
from calibre.utils.search_query_parser import saved_searches
from calibre.gui2 import error_dialog
from calibre.gui2.dialogs.confirm_delete import confirm
@ -225,7 +226,7 @@ class TagsView(QTreeView): # {{{
partial(self.context_menu_handler, action='hide', category=category))
if self.hidden_categories:
m = self.context_menu.addMenu(_('Show category'))
for col in sorted(self.hidden_categories, cmp=lambda x,y: cmp(x.lower(), y.lower())):
for col in sorted(self.hidden_categories, key=sort_key):
m.addAction(col,
partial(self.context_menu_handler, action='show', category=col))
@ -599,7 +600,8 @@ class TagsModel(QAbstractItemModel): # {{{
# Reconstruct the user categories, putting them into metadata
self.db.field_metadata.remove_dynamic_categories()
tb_cats = self.db.field_metadata
for user_cat in sorted(self.db.prefs.get('user_categories', {}).keys()):
for user_cat in sorted(self.db.prefs.get('user_categories', {}).keys(),
key=sort_key):
cat_name = user_cat+':' # add the ':' to avoid name collision
tb_cats.add_user_category(label=cat_name, name=user_cat)
if len(saved_searches().names()):
@ -878,13 +880,13 @@ class TagBrowserMixin(object): # {{{
db=self.library_view.model().db
if category == 'tags':
result = db.get_tags_with_ids()
compare = (lambda x,y:cmp(x.lower(), y.lower()))
key = sort_key
elif category == 'series':
result = db.get_series_with_ids()
compare = (lambda x,y:cmp(title_sort(x).lower(), title_sort(y).lower()))
key = lambda x:sort_key(title_sort(x))
elif category == 'publisher':
result = db.get_publishers_with_ids()
compare = (lambda x,y:cmp(x.lower(), y.lower()))
key = sort_key
else: # should be a custom field
cc_label = None
if category in db.field_metadata:
@ -892,9 +894,9 @@ class TagBrowserMixin(object): # {{{
result = db.get_custom_items_with_ids(label=cc_label)
else:
result = []
compare = (lambda x,y:cmp(x.lower(), y.lower()))
key = sort_key
d = TagListEditor(self, tag_to_match=tag, data=result, compare=compare)
d = TagListEditor(self, tag_to_match=tag, data=result, key=key)
d.exec_()
if d.result() == d.Accepted:
to_rename = d.to_rename # dict of new text to old id

View File

@ -14,6 +14,7 @@ from operator import itemgetter
from PyQt4.QtGui import QImage
from calibre.ebooks.metadata import title_sort, author_to_author_sort
from calibre.ebooks.metadata.opf2 import metadata_to_opf
from calibre.library.database import LibraryDatabase
@ -33,6 +34,7 @@ from calibre import isbytestring
from calibre.utils.filenames import ascii_filename
from calibre.utils.date import utcnow, now as nowf, utcfromtimestamp
from calibre.utils.config import prefs, tweaks
from calibre.utils.icu import sort_key
from calibre.utils.search_query_parser import saved_searches, set_saved_searches
from calibre.ebooks import BOOK_EXTENSIONS, check_ebook_format
from calibre.utils.magick.draw import save_cover_data_to
@ -287,7 +289,7 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
# Assumption is that someone else will fix them if they change.
self.field_metadata.remove_dynamic_categories()
tb_cats = self.field_metadata
for user_cat in sorted(self.prefs.get('user_categories', {}).keys()):
for user_cat in sorted(self.prefs.get('user_categories', {}).keys(), key=sort_key):
cat_name = user_cat+':' # add the ':' to avoid name collision
tb_cats.add_user_category(label=cat_name, name=user_cat)
if len(saved_searches().names()):
@ -1065,7 +1067,7 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
if sort == 'popularity':
query += ' ORDER BY count DESC, sort ASC'
elif sort == 'name':
query += ' ORDER BY sort ASC'
query += ' ORDER BY sort COLLATE icucollate'
else:
query += ' ORDER BY avg_rating DESC, sort ASC'
data = self.conn.get(query)
@ -1137,6 +1139,7 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
if sort == 'popularity':
categories['formats'].sort(key=lambda x: x.count, reverse=True)
else: # no ratings exist to sort on
# No need for ICU here.
categories['formats'].sort(key = lambda x:x.name)
#### Now do the user-defined categories. ####
@ -1151,7 +1154,7 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
for c in categories.keys():
taglist[c] = dict(map(lambda t:(t.name, t), categories[c]))
for user_cat in sorted(user_categories.keys()):
for user_cat in sorted(user_categories.keys(), key=sort_key):
items = []
for (name,label,ign) in user_categories[user_cat]:
if label in taglist and name in taglist[label]:
@ -1167,7 +1170,7 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
sorted(items, key=lambda x: x.count, reverse=True)
elif sort == 'name':
categories[cat_name] = \
sorted(items, key=lambda x: x.sort.lower())
sorted(items, key=lambda x: sort_key(x.sort))
else:
categories[cat_name] = \
sorted(items, key=lambda x:x.avg_rating, reverse=True)

View File

@ -16,6 +16,7 @@ from calibre import isbytestring, force_unicode, fit_image, \
from calibre.utils.ordered_dict import OrderedDict
from calibre.utils.filenames import ascii_filename
from calibre.utils.config import prefs
from calibre.utils.icu import sort_key
from calibre.utils.magick import Image
from calibre.library.comments import comments_to_html
from calibre.library.server import custom_fields_to_display
@ -273,7 +274,7 @@ class BrowseServer(object):
opts = ['<option %svalue="%s">%s</option>' % (
'selected="selected" ' if k==sort else '',
xml(k), xml(n), ) for k, n in
sorted(sort_opts, key=operator.itemgetter(1)) if k and n]
sorted(sort_opts, key=lambda x: sort_key(operator.itemgetter(1)(x))) if k and n]
ans = ans.replace('{sort_select_options}', ('\n'+' '*20).join(opts))
lp = self.db.library_path
if isbytestring(lp):
@ -337,8 +338,7 @@ class BrowseServer(object):
return category_meta[x]['name'].lower()
displayed_custom_fields = custom_fields_to_display(self.db)
for category in sorted(categories,
cmp=lambda x,y: cmp(getter(x), getter(y))):
for category in sorted(categories, key=lambda x: sort_key(getter(x))):
if len(categories[category]) == 0:
continue
if category == 'formats':
@ -375,12 +375,7 @@ class BrowseServer(object):
def browse_sort_categories(self, items, sort):
if sort not in ('rating', 'name', 'popularity'):
sort = 'name'
def sorter(x):
ans = getattr(x, 'sort', x.name)
if hasattr(ans, 'upper'):
ans = ans.upper()
return ans
items.sort(key=sorter)
items.sort(key=lambda x: sort_key(getattr(x, 'sort', x.name)))
if sort == 'popularity':
items.sort(key=operator.attrgetter('count'), reverse=True)
elif sort == 'rating':
@ -703,7 +698,7 @@ class BrowseServer(object):
args[field]
fields.append((m['name'], r))
fields.sort(key=lambda x: x[0].lower())
fields.sort(key=lambda x: sort_key(x[0]))
fields = [u'<div class="field">{0}</div>'.format(f[1]) for f in
fields]
fields = u'<div class="fields">%s</div>'%('\n\n'.join(fields))

View File

@ -21,6 +21,7 @@ from calibre.constants import __appname__
from calibre import human_readable, isbytestring
from calibre.utils.date import utcfromtimestamp
from calibre.utils.filenames import ascii_filename
from calibre.utils.icu import sort_key
def CLASS(*args, **kwargs): # class is a reserved word in Python
kwargs['class'] = ' '.join(args)
@ -211,8 +212,7 @@ class MobileServer(object):
CFM = self.db.field_metadata
CKEYS = [key for key in sorted(custom_fields_to_display(self.db),
cmp=lambda x,y: cmp(CFM[x]['name'].lower(),
CFM[y]['name'].lower()))]
key=lambda x:sort_key(CFM[x]['name']))]
# This method uses its own book dict, not the Metadata dict. The loop
# below could be changed to use db.get_metadata instead of reading
# info directly from the record made by the view, but it doesn't seem

View File

@ -20,6 +20,7 @@ from calibre.library.comments import comments_to_html
from calibre.library.server import custom_fields_to_display
from calibre.library.server.utils import format_tag_string, Offsets
from calibre import guess_type
from calibre.utils.icu import sort_key
from calibre.utils.ordered_dict import OrderedDict
BASE_HREFS = {
@ -279,8 +280,7 @@ class AcquisitionFeed(NavFeed):
NavFeed.__init__(self, id_, updated, version, offsets, page_url, up_url)
CFM = db.field_metadata
CKEYS = [key for key in sorted(custom_fields_to_display(db),
cmp=lambda x,y: cmp(CFM[x]['name'].lower(),
CFM[y]['name'].lower()))]
key=lambda x: sort_key(CFM[x]['name']))]
for item in items:
self.root.append(ACQUISITION_ENTRY(item, version, db, updated,
CFM, CKEYS, prefix))
@ -492,7 +492,7 @@ class OPDSServer(object):
val = 'A'
starts.add(val[0].upper())
category_groups = OrderedDict()
for x in sorted(starts, cmp=lambda x,y:cmp(x.lower(), y.lower())):
for x in sorted(starts, key=sort_key):
category_groups[x] = len([y for y in items if
getattr(y, 'sort', y.name).startswith(x)])
items = [Group(x, y) for x, y in category_groups.items()]
@ -571,8 +571,7 @@ class OPDSServer(object):
]
def getter(x):
return category_meta[x]['name'].lower()
for category in sorted(categories,
cmp=lambda x,y: cmp(getter(x), getter(y))):
for category in sorted(categories, key=lambda x: sort_key(getter(x))):
if len(categories[category]) == 0:
continue
if category == 'formats':

View File

@ -13,6 +13,7 @@ import cherrypy
from calibre import strftime as _strftime, prints, isbytestring
from calibre.utils.date import now as nowf
from calibre.utils.config import tweaks
from calibre.utils.icu import sort_key
class Offsets(object):
'Calculate offsets for a paginated view'
@ -73,7 +74,7 @@ def format_tag_string(tags, sep, ignore_max=False, no_tag_count=False):
tlist = [t.strip() for t in tags.split(sep)]
else:
tlist = []
tlist.sort(cmp=lambda x,y:cmp(x.lower(), y.lower()))
tlist.sort(key=sort_key)
if len(tlist) > MAX:
tlist = tlist[:MAX]+['...']
if no_tag_count:

View File

@ -17,6 +17,7 @@ from calibre.ebooks.metadata import fmt_sidx
from calibre.constants import preferred_encoding
from calibre import isbytestring
from calibre.utils.filenames import ascii_filename
from calibre.utils.icu import sort_key
E = ElementMaker()
@ -101,8 +102,7 @@ class XMLServer(object):
CFM = self.db.field_metadata
CKEYS = [key for key in sorted(custom_fields_to_display(self.db),
cmp=lambda x,y: cmp(CFM[x]['name'].lower(),
CFM[y]['name'].lower()))]
key=lambda x: sort_key(CFM[x]['name']))]
custcols = []
for key in CKEYS:
def concat(name, val):

View File

@ -115,6 +115,9 @@ def pynocase(one, two, encoding='utf-8'):
pass
return cmp(one.lower(), two.lower())
def icu_collator(s1, s2, func=None):
return cmp(func(unicode(s1)), func(unicode(s2)))
def load_c_extensions(conn, debug=DEBUG):
try:
conn.enable_load_extension(True)
@ -166,6 +169,8 @@ class DBThread(Thread):
self.conn.create_function('uuid4', 0, lambda : str(uuid.uuid4()))
# Dummy functions for dynamically created filters
self.conn.create_function('books_list_filter', 1, lambda x: 1)
from calibre.utils.icu import sort_key
self.conn.create_collation('icucollate', partial(icu_collator, func=sort_key))
def run(self):
try:

View File

@ -22,6 +22,7 @@ from calibre.utils.pyparsing import CaselessKeyword, Group, Forward, \
CharsNotIn, Suppress, OneOrMore, MatchFirst, CaselessLiteral, \
Optional, NoMatch, ParseException, QuotedString
from calibre.constants import preferred_encoding
from calibre.utils.icu import sort_key
@ -65,8 +66,7 @@ class SavedSearchQueries(object):
self.db.prefs[self.opt_name] = self.queries
def names(self):
return sorted(self.queries.keys(),
cmp=lambda x,y: cmp(x.lower(), y.lower()))
return sorted(self.queries.keys(),key=sort_key)
'''
Create a global instance of the saved searches. It is global so that the searches