diff --git a/src/calibre/ebooks/metadata/__init__.py b/src/calibre/ebooks/metadata/__init__.py
index fe8ad7fbb5..8a08817450 100644
--- a/src/calibre/ebooks/metadata/__init__.py
+++ b/src/calibre/ebooks/metadata/__init__.py
@@ -394,9 +394,9 @@ def check_doi(doi):
return doi_check.group()
return None
-def rating_to_stars(value, allow_half_star=False, star=u'★', half=u'½'):
+def rating_to_stars(value, allow_half_stars=False, star=u'★', half=u'½'):
r = max(0, min(int(value), 10))
- if allow_half_star:
+ if allow_half_stars:
ans = u'★' * (r // 2)
if r % 2:
ans += u'½'
diff --git a/src/calibre/gui2/custom_column_widgets.py b/src/calibre/gui2/custom_column_widgets.py
index 951c00694c..b334c72db9 100644
--- a/src/calibre/gui2/custom_column_widgets.py
+++ b/src/calibre/gui2/custom_column_widgets.py
@@ -824,25 +824,16 @@ class BulkFloat(BulkInt):
class BulkRating(BulkBase):
def setup_ui(self, parent):
- self.make_widgets(parent, QSpinBox)
- self.main_widget.setRange(0, 5)
- self.main_widget.setSuffix(' '+_('star(s)'))
- self.main_widget.setSpecialValueText(_('Not rated'))
- self.main_widget.setSingleStep(1)
+ allow_half_stars = self.col_metadata['display'].get('allow_half_stars', False)
+ self.make_widgets(parent, partial(RatingEditor, is_half_star=allow_half_stars))
def setter(self, val):
- if val is None:
- val = 0
- self.main_widget.setValue(int(round(val/2.)))
+ val = max(0, min(int(val or 0), 10))
+ self.main_widget.rating_value = val
self.ignore_change_signals = False
def getter(self):
- val = self.main_widget.value()
- if val == 0:
- val = None
- else:
- val *= 2
- return val
+ return self.main_widget.rating_value or None
class BulkDateTime(BulkBase):
diff --git a/src/calibre/gui2/dialogs/metadata_bulk.py b/src/calibre/gui2/dialogs/metadata_bulk.py
index 52ee3a5e5b..cc09b80a06 100644
--- a/src/calibre/gui2/dialogs/metadata_bulk.py
+++ b/src/calibre/gui2/dialogs/metadata_bulk.py
@@ -231,7 +231,7 @@ class MyBlockingBusy(QDialog): # {{{
# Various fields
if args.rating != -1:
- cache.set_field('rating', {bid:args.rating*2 for bid in self.ids})
+ cache.set_field('rating', {bid:args.rating for bid in self.ids})
if args.clear_pub:
cache.set_field('publisher', {bid:'' for bid in self.ids})
@@ -341,6 +341,7 @@ class MetadataBulkDialog(QDialog, Ui_MetadataBulkDialog):
self.remove_format.setCurrentIndex(-1)
self.series.currentIndexChanged[int].connect(self.series_changed)
+ self.rating.currentIndexChanged.connect(lambda:self.apply_rating.setChecked(True))
self.series.editTextChanged.connect(self.series_changed)
self.tag_editor_button.clicked.connect(self.tag_editor)
self.autonumber_series.stateChanged[int].connect(self.auto_number_changed)
@@ -981,7 +982,9 @@ class MetadataBulkDialog(QDialog, Ui_MetadataBulkDialog):
au = unicode(self.authors.text())
aus = unicode(self.author_sort.text())
do_aus = self.author_sort.isEnabled()
- rating = self.rating.value()
+ rating = self.rating.rating_value
+ if not self.apply_rating.isChecked():
+ rating = -1
pub = unicode(self.publisher.text())
do_series = self.write_series
clear_series = self.clear_series.isChecked()
diff --git a/src/calibre/gui2/dialogs/metadata_bulk.ui b/src/calibre/gui2/dialogs/metadata_bulk.ui
index 8bc0ac79cb..555e092e31 100644
--- a/src/calibre/gui2/dialogs/metadata_bulk.ui
+++ b/src/calibre/gui2/dialogs/metadata_bulk.ui
@@ -61,6 +61,13 @@
&Basic metadata
+ -
+
+
+ &Apply date
+
+
+
-
@@ -74,14 +81,14 @@
- -
+
-
true
- -
+
-
-
@@ -118,7 +125,7 @@
- -
+
-
Specify how the author(s) of this book should be sorted. For example Charles Dickens should be sorted as Dickens, Charles.
@@ -138,34 +145,6 @@
- -
-
-
- Rating of this book. 0-5 stars
-
-
- Rating of this book. 0-5 stars
-
-
- QAbstractSpinBox::PlusMinus
-
-
- No change
-
-
- stars
-
-
- -1
-
-
- 5
-
-
- -1
-
-
-
-
@@ -179,14 +158,14 @@
- -
+
-
true
- -
+
-
If checked, the publisher will be cleared
@@ -209,14 +188,14 @@
- -
+
-
Tags categorize the book. This is particularly useful while searching. <br><br>They can be any words or phrases, separated by commas.
- -
+
-
Open Tag Editor
@@ -243,14 +222,14 @@
- -
+
-
Comma separated list of tags to remove from the books.
- -
+
-
Check this box to remove all tags from the books.
@@ -276,7 +255,7 @@
- -
+
-
@@ -304,7 +283,7 @@
- -
+
-
If checked, the series will be cleared
@@ -314,7 +293,7 @@
- -
+
-
-
@@ -397,7 +376,47 @@ from the value in the box
- -
+
-
+
+
-
+
+
+ Control how the default generated covers are created
+
+
+ Configure co&ver generation
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ Set the co&mments for all selected books
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+
+
+ -
-
@@ -422,7 +441,7 @@ from the value in the box
- -
+
-
&Apply date
@@ -442,7 +461,7 @@ from the value in the box
- -
+
-
-
@@ -470,13 +489,6 @@ from the value in the box
- -
-
-
- &Apply date
-
-
-
-
@@ -490,10 +502,10 @@ from the value in the box
- -
+
-
- -
+
-
Remove &all
@@ -510,7 +522,7 @@ from the value in the box
- -
+
-
-
@@ -567,7 +579,7 @@ for e.g., EPUB to EPUB, calibre saves the original EPUB
- -
+
-
-
@@ -617,7 +629,7 @@ Future conversion of these books will use the default settings.
- -
+
-
Change &cover
@@ -670,46 +682,6 @@ as that of the first selected book.
- -
-
-
-
-
-
- Control how the default generated covers are created
-
-
- Configure co&ver generation
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
- Set the co&mments for all selected books
-
-
-
- -
-
-
- Qt::Horizontal
-
-
-
- 40
- 20
-
-
-
-
-
-
-
@@ -723,6 +695,16 @@ as that of the first selected book.
+ -
+
+
+ -
+
+
+ &Apply rating
+
+
+
@@ -1209,8 +1191,8 @@ not multiple and the destination field is multiple
0
0
- 922
- 268
+ 210
+ 66
@@ -1325,6 +1307,11 @@ is completed. This can be slow on large libraries.
QComboBox
+
+ RatingEditor
+ QComboBox
+
+
authors
diff --git a/src/calibre/gui2/widgets2.py b/src/calibre/gui2/widgets2.py
index c3ad2c01cc..e168388199 100644
--- a/src/calibre/gui2/widgets2.py
+++ b/src/calibre/gui2/widgets2.py
@@ -192,6 +192,7 @@ class RatingModel(QAbstractListModel):
QAbstractListModel.__init__(self, parent)
self.is_half_star = is_half_star
self.rating_font = QFont(rating_font())
+ self.null_text = _('Not rated')
def rowCount(self, parent=QModelIndex()):
return 11 if self.is_half_star else 6
@@ -199,7 +200,7 @@ class RatingModel(QAbstractListModel):
def data(self, index, role=Qt.DisplayRole):
if role == Qt.DisplayRole:
val = index.row() * (1 if self.is_half_star else 2)
- return rating_to_stars(val, self.is_half_star) or _('Not rated')
+ return rating_to_stars(val, self.is_half_star) or self.null_text
if role == Qt.FontRole:
return QApplication.instance().font() if index.row() == 0 else self.rating_font
@@ -235,6 +236,15 @@ class RatingEditor(QComboBox):
self.setMaxVisibleItems(self.count())
self.currentIndexChanged.connect(self.update_font)
+ @property
+ def null_text(self):
+ return self._model.null_text
+
+ @null_text.setter
+ def null_text(self, val):
+ self._model.null_text = val
+ self._model.dataChanged.emit(self._model.index(0, 0), self._model.index(0, 0))
+
def update_font(self):
if self.currentIndex() == 0:
self.setFont(QApplication.instance().font())