diff --git a/src/calibre/db/fields.py b/src/calibre/db/fields.py index 4836502c81..bf27e5287c 100644 --- a/src/calibre/db/fields.py +++ b/src/calibre/db/fields.py @@ -77,7 +77,10 @@ class Field(object): self.default_value = {} if name == 'identifiers' else () if self.is_multiple else None self.category_formatter = type(u'') if dt == 'rating': - self.category_formatter = partial(rating_to_stars, allow_half_stars=self.metadata['display'].get('allow_half_stars', False)) + if self.metadata['display'].get('allow_half_stars', False): + self.category_formatter = lambda x: rating_to_stars(x, True) + else: + self.category_formatter = rating_to_stars elif name == 'languages': self.category_formatter = calibre_langcode_to_name self.writer = Writer(self) diff --git a/src/calibre/ebooks/metadata/__init__.py b/src/calibre/ebooks/metadata/__init__.py index 1b80da5d09..67ad6c5c92 100644 --- a/src/calibre/ebooks/metadata/__init__.py +++ b/src/calibre/ebooks/metadata/__init__.py @@ -397,11 +397,9 @@ def check_doi(doi): def rating_to_stars(value, allow_half_stars=False, star=u'★', half=u'½'): r = max(0, min(int(value or 0), 10)) if allow_half_stars: - ans = u'★' * (r // 2) + ans = star * (r // 2) if r % 2: - ans += u'½' + ans += half else: - ans = u'★' * int(r/2.0) + ans = star * int(r/2.0) return ans - - diff --git a/src/calibre/gui2/tag_browser/model.py b/src/calibre/gui2/tag_browser/model.py index 456004f126..e613a88ed3 100644 --- a/src/calibre/gui2/tag_browser/model.py +++ b/src/calibre/gui2/tag_browser/model.py @@ -15,6 +15,7 @@ from PyQt5.Qt import (QAbstractItemModel, QIcon, QFont, Qt, QMimeData, QModelIndex, pyqtSignal, QObject) from calibre.constants import config_dir +from calibre.ebooks.metadata import rating_to_stars from calibre.gui2 import gprefs, config, error_dialog, file_icon_provider from calibre.db.categories import Tag from calibre.utils.config import tweaks @@ -1294,6 +1295,7 @@ class TagsModel(QAbstractItemModel): # {{{ # They will be 'checked' in both places, but we want to put the node # into the search string only once. The nodes_seen set helps us do that nodes_seen = set() + stars = rating_to_stars(3, True) node_searches = {TAG_SEARCH_STATES['mark_plus'] : 'true', TAG_SEARCH_STATES['mark_plusplus'] : '.true', @@ -1351,8 +1353,11 @@ class TagsModel(QAbstractItemModel): # {{{ if self.db.field_metadata[tag.category]['is_csp']: add_colon = True - if tag.name and tag.name[0] in u'★½': # char is a star or a half. Assume rating - ans.append('%s%s:%s'%(prefix, category, len(tag.name))) + if tag.name and tag.name[0] in stars: # char is a star or a half. Assume rating + rnum = len(tag.name) + if tag.name.endswith(stars[-1]): + rnum = '%s.5' % (rnum - 1) + ans.append('%s%s:%s'%(prefix, category, rnum)) else: name = tag.original_name use_prefix = tag.state in [TAG_SEARCH_STATES['mark_plusplus'], diff --git a/src/pyj/book_list/search.pyj b/src/pyj/book_list/search.pyj index 8a53314365..4c3ccd6053 100644 --- a/src/pyj/book_list/search.pyj +++ b/src/pyj/book_list/search.pyj @@ -9,6 +9,7 @@ from elementmaker import E from gettext import gettext as _ from widgets import create_button, create_spinner, Breadcrumbs from modals import show_modal +from utils import rating_to_stars from book_list.globals import get_boss, get_session_data from book_list.theme import get_color, get_font_size @@ -224,6 +225,7 @@ class SearchPanel: return '' search_state = {'plus':'true', 'plusplus':'.true', 'minus':'false', 'minusminus':'.false'}[state] + stars = rating_to_stars(3, True) if item.is_category: category = item.category @@ -256,9 +258,12 @@ class SearchPanel: return expr category = 'tags' if item.category is 'news' else item.category - if item.name and item.name[0] in '★½': + if item.name and item.name[0] in stars: # Assume ratings - expr = '{}:{}'.format(category, item.name.length) + rnum = item.name.length + if item.name.endswith(stars[-1]): + rnum = '{}.5'.format(rnum - 1) + expr = '{}:{}'.format(category, rnum) else: fm = self.interface_data.field_metadata[item.category] suffix = ':' if fm and fm.is_csp else '' diff --git a/src/pyj/utils.pyj b/src/pyj/utils.pyj index f6905cdcf2..837f189736 100644 --- a/src/pyj/utils.pyj +++ b/src/pyj/utils.pyj @@ -69,6 +69,16 @@ def fmt_sidx(val, fmt='{:.2f}', use_roman=True): return int(val) + '' return fmt.format(float(val)) +def rating_to_stars(value, allow_half_stars=False, star='★', half='½'): + r = max(0, min(int(value or 0), 10)) + if allow_half_stars: + ans = star.repeat(r // 2) + if r % 2: + ans += half + else: + ans = star.repeat(int(r/2.0)) + return ans + def human_readable(size, sep=' '): divisor, suffix = 1, "B" for i, candidate in enumerate(('B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB')): @@ -142,5 +152,8 @@ def uniq(vals): return ans if __name__ is '__main__': + from pythonize import strings + strings() + print(rating_to_stars(3, True)) print(fmt_sidx(10), fmt_sidx(1.2)) print(list(map(human_readable, [1, 1024.0, 1025, 1024*1024*2.3])))