diff --git a/src/calibre/gui2/icon_theme.py b/src/calibre/gui2/icon_theme.py
index 5760bcce10..710bbad3bc 100644
--- a/src/calibre/gui2/icon_theme.py
+++ b/src/calibre/gui2/icon_theme.py
@@ -15,12 +15,12 @@ from threading import Thread
from PyQt5.Qt import (
QImageReader, QFormLayout, QVBoxLayout, QSplitter, QGroupBox, QListWidget,
QLineEdit, QSpinBox, QTextEdit, QSize, QListWidgetItem, QIcon, QImage,
- QCursor, pyqtSignal, QStackedLayout, QWidget, QLabel, Qt, QComboBox,
- QPixmap, QGridLayout, QStyledItemDelegate, QModelIndex, QApplication,
- QStaticText, QStyle, QPen
+ pyqtSignal, QStackedLayout, QWidget, QLabel, Qt, QComboBox, QPixmap,
+ QGridLayout, QStyledItemDelegate, QModelIndex, QApplication, QStaticText,
+ QStyle, QPen
)
-from calibre import walk, fit_image
+from calibre import walk, fit_image, human_readable
from calibre.constants import cache_dir, config_dir
from calibre.customize.ui import interface_actions
from calibre.gui2 import must_use_qt, gprefs, choose_dir, error_dialog, choose_save_file, question_dialog
@@ -415,13 +415,15 @@ class Delegate(QStyledItemDelegate):
bottom = option.rect.bottom() - 2
painter.drawLine(0, bottom, option.rect.right(), bottom)
if 'static-text' not in theme:
- theme['static-text'] = QStaticText(
+ theme['static-text'] = QStaticText(_(
'''
{title}
- by {author} with {number} icons
+ by {author} with {number} icons [{size}]
{description}
+ Version: {version}
'''.format(title=theme.get('title', _('Unknown')), author=theme.get('author', _('Unknown')),
- number=theme.get('number', 0), description=theme.get('description', '')))
+ number=theme.get('number', 0), description=theme.get('description', ''),
+ size=human_readable(theme.get('compressed-size', 0)), version=theme.get('version', 1))))
painter.drawStaticText(COVER_SIZE[0] + self.SPACING, option.rect.top() + self.SPACING, theme['static-text'])
painter.restore()
@@ -457,11 +459,12 @@ class ChooseTheme(Dialog):
self.current_theme = json.loads(I('icon-theme.json', data=True))['title']
except Exception:
self.current_theme = None
- self.changed = False
Dialog.__init__(self, _('Choose an icon theme'), 'choose-icon-theme-dialog', parent)
self.themes_downloaded.connect(self.show_themes, type=Qt.QueuedConnection)
self.cover_downloaded.connect(self.set_cover, type=Qt.QueuedConnection)
self.keep_downloading = True
+ self.commit_changes = None
+ self.new_theme_title = None
def sizeHint(self):
desktop = QApplication.instance().desktop()
@@ -603,8 +606,7 @@ class ChooseTheme(Dialog):
'Are you sure you want to remove the %s icon theme'
' and return to the stock icons?') % self.current_theme):
return
- self.changed = True
- remove_icon_theme()
+ self.commit_changes = remove_icon_theme
Dialog.accept(self)
def accept(self):
@@ -614,7 +616,7 @@ class ChooseTheme(Dialog):
theme = self.theme_list.currentItem().data(Qt.UserRole)
url = BASE_URL + theme['icons-url']
size = theme['compressed-size']
- theme = {k:theme.get(k, '') for k in 'name title'.split()}
+ theme = {k:theme.get(k, '') for k in 'name title version'.split()}
self.keep_downloading = True
d = DownloadProgress(self, size)
d.canceled_signal.connect(lambda : setattr(self, 'keep_downloading', False))
@@ -626,7 +628,7 @@ class ChooseTheme(Dialog):
try:
response = get_https_resource_securely(url, get_response=True)
while self.keep_downloading:
- raw = response.read(100)
+ raw = response.read(1024)
if not raw:
break
buf.write(raw)
@@ -647,23 +649,17 @@ class ChooseTheme(Dialog):
'Failed to download icon theme, click "Show Details" for more information.'), show=True, det_msg=self.downloaded_theme)
if ret == d.Rejected or not self.keep_downloading or d.canceled or self.downloaded_theme is None:
return
- self.changed = True
- with BusyCursor():
- self.downloaded_theme.seek(0)
- f = decompress(self.downloaded_theme)
+ dt = self.downloaded_theme
+ def commit_changes():
+ dt.seek(0)
+ f = decompress(dt)
f.seek(0)
remove_icon_theme()
install_icon_theme(theme, f)
+ self.commit_changes = commit_changes
+ self.new_theme_title = theme['title']
return Dialog.accept(self)
-class BusyCursor(object):
-
- def __enter__(self):
- QApplication.setOverrideCursor(QCursor(Qt.WaitCursor))
-
- def __exit__(self, *args):
- QApplication.restoreOverrideCursor()
-
# }}}
def remove_icon_theme():
@@ -709,5 +705,7 @@ if __name__ == '__main__':
from calibre.gui2 import Application
app = Application([])
# create_theme('.')
- ChooseTheme().exec_()
+ d = ChooseTheme()
+ if d.exec_() == d.Accepted and d.commit_changes is not None:
+ d.commit_changes()
del app
diff --git a/src/calibre/gui2/preferences/look_feel.py b/src/calibre/gui2/preferences/look_feel.py
index 5e2bc3b45d..308877e0c0 100644
--- a/src/calibre/gui2/preferences/look_feel.py
+++ b/src/calibre/gui2/preferences/look_feel.py
@@ -5,12 +5,14 @@ __license__ = 'GPL v3'
__copyright__ = '2010, Kovid Goyal '
__docformat__ = 'restructuredtext en'
+import json
+
from threading import Thread
from functools import partial
from PyQt5.Qt import (
QApplication, QFont, QFontInfo, QFontDialog, QColorDialog, QPainter,
- QAbstractListModel, Qt, QIcon, QKeySequence, QColor, pyqtSignal,
+ QAbstractListModel, Qt, QIcon, QKeySequence, QColor, pyqtSignal, QCursor,
QWidget, QSizePolicy, QBrush, QPixmap, QSize, QPushButton, QVBoxLayout)
from calibre import human_readable
@@ -25,6 +27,14 @@ from calibre.gui2.book_details import get_field_list
from calibre.gui2.preferences.coloring import EditRules
from calibre.gui2.library.alternate_views import auto_height, CM_TO_INCH
+class BusyCursor(object):
+
+ def __enter__(self):
+ QApplication.setOverrideCursor(QCursor(Qt.WaitCursor))
+
+ def __exit__(self, *args):
+ QApplication.restoreOverrideCursor()
+
class DisplayedFields(QAbstractListModel): # {{{
def __init__(self, db, parent=None):
@@ -136,6 +146,13 @@ class ConfigWidget(ConfigWidgetBase, Ui_Form):
r = self.register
+ try:
+ self.icon_theme_title = json.loads(I('icon-theme.json', data=True))['name']
+ except Exception:
+ self.icon_theme_title = _('Default icons')
+ self.icon_theme.setText(_('Icon theme: %s') % self.icon_theme_title)
+ self.commit_icon_theme = None
+ self.icon_theme_button.clicked.connect(self.choose_icon_theme)
r('gui_layout', config, restart_required=True, choices=[(_('Wide'), 'wide'), (_('Narrow'), 'narrow')])
r('ui_style', gprefs, restart_required=True, choices=[(_('System default'), 'system'), (_('Calibre style'),
'calibre')])
@@ -207,8 +224,7 @@ class ConfigWidget(ConfigWidgetBase, Ui_Form):
choices = set([k for k in db.field_metadata.all_field_keys()
if (db.field_metadata[k]['is_category'] and
(db.field_metadata[k]['datatype'] in ['text', 'series', 'enumeration']) and
- not db.field_metadata[k]['display'].get('is_names', False))
- or
+ not db.field_metadata[k]['display'].get('is_names', False)) or
(db.field_metadata[k]['datatype'] in ['composite'] and
db.field_metadata[k]['display'].get('make_category', False))])
choices -= set(['authors', 'publisher', 'formats', 'news', 'identifiers'])
@@ -281,6 +297,15 @@ class ConfigWidget(ConfigWidgetBase, Ui_Form):
self.opt_cover_grid_width.valueChanged.connect(self.update_aspect_ratio)
self.opt_cover_grid_height.valueChanged.connect(self.update_aspect_ratio)
+ def choose_icon_theme(self):
+ from calibre.gui2.icon_theme import ChooseTheme
+ d = ChooseTheme(self)
+ if d.exec_() == d.Accepted:
+ self.commit_icon_theme = d.commit_changes
+ self.icon_theme_title = d.new_theme_title or _('Default icons')
+ self.icon_theme.setText(_('Icon theme: %s') % self.icon_theme_title)
+ self.changed_signal.emit()
+
@property
def current_cover_size(self):
cval = self.opt_cover_grid_height.value()
@@ -448,20 +473,24 @@ class ConfigWidget(ConfigWidgetBase, Ui_Form):
self.changed_signal.emit()
def commit(self, *args):
- rr = ConfigWidgetBase.commit(self, *args)
- if self.current_font != self.initial_font:
- gprefs['font'] = (self.current_font[:4] if self.current_font else
- None)
- gprefs['font_stretch'] = (self.current_font[4] if self.current_font
- is not None else QFont.Unstretched)
- QApplication.setFont(self.font_display.font())
- rr = True
- self.display_model.commit()
- self.edit_rules.commit(self.gui.current_db.prefs)
- self.icon_rules.commit(self.gui.current_db.prefs)
- self.grid_rules.commit(self.gui.current_db.prefs)
- gprefs['cover_grid_color'] = tuple(self.cg_bg_widget.bcol.getRgb())[:3]
- gprefs['cover_grid_texture'] = self.cg_bg_widget.btex
+ with BusyCursor():
+ rr = ConfigWidgetBase.commit(self, *args)
+ if self.current_font != self.initial_font:
+ gprefs['font'] = (self.current_font[:4] if self.current_font else
+ None)
+ gprefs['font_stretch'] = (self.current_font[4] if self.current_font
+ is not None else QFont.Unstretched)
+ QApplication.setFont(self.font_display.font())
+ rr = True
+ self.display_model.commit()
+ self.edit_rules.commit(self.gui.current_db.prefs)
+ self.icon_rules.commit(self.gui.current_db.prefs)
+ self.grid_rules.commit(self.gui.current_db.prefs)
+ gprefs['cover_grid_color'] = tuple(self.cg_bg_widget.bcol.getRgb())[:3]
+ gprefs['cover_grid_texture'] = self.cg_bg_widget.btex
+ if self.commit_icon_theme is not None:
+ self.commit_icon_theme()
+ rr = True
return rr
def refresh_gui(self, gui):
diff --git a/src/calibre/gui2/preferences/look_feel.ui b/src/calibre/gui2/preferences/look_feel.ui
index f83dde019a..a65cdaaa19 100644
--- a/src/calibre/gui2/preferences/look_feel.ui
+++ b/src/calibre/gui2/preferences/look_feel.ui
@@ -28,125 +28,27 @@
Main Interface
- -
-
-
- QComboBox::AdjustToMinimumContentsLengthWithIcon
-
-
- 20
-
-
-
- -
-
-
- Enable system &tray icon (needs restart)
-
-
-
-
-
-
- Qt::Vertical
-
-
-
- 20
- 40
-
-
-
-
- -
-
+
- User Interface &layout (needs restart):
+ E&xtra spacing to add between rows in the book list (can be negative):
- opt_gui_layout
+ opt_book_list_extra_row_spacing
- -
-
-
-
- 250
- 16777215
-
+
-
+
+
+ px
-
- QComboBox::AdjustToMinimumContentsLengthWithIcon
-
-
- 20
+
+ -20
- -
-
-
- Disable all animations. Useful if you have a slow/old computer.
-
-
- Disable &animations
-
-
-
- -
-
-
- Disable ¬ifications in system tray
-
-
-
- -
-
-
- Show &splash screen at startup
-
-
-
- -
-
-
-
-
-
- Interface font:
-
-
- font_display
-
-
-
- -
-
-
- true
-
-
-
-
-
- -
-
-
- Change &font (needs restart)
-
-
-
- -
-
-
- User interface &style (needs restart):
-
-
- opt_ui_style
-
-
-
- -
+
-
&Toolbar
@@ -181,7 +83,60 @@
- -
+
-
+
+
+ -
+
+
+ Change &font (needs restart)
+
+
+
+ -
+
+
+
+ 250
+ 16777215
+
+
+
+ QComboBox::AdjustToMinimumContentsLengthWithIcon
+
+
+ 20
+
+
+
+ -
+
+
+ Show &tooltips in the book list
+
+
+
+ -
+
+
+ Qt::Vertical
+
+
+
+ 20
+ 40
+
+
+
+
+ -
+
+
+ Enable system &tray icon (needs restart)
+
+
+
+ -
Choose &language (requires restart):
@@ -191,33 +146,92 @@
- -
-
+
-
+
+
-
+
+
+ Interface font:
+
+
+ font_display
+
+
+
+ -
+
+
+ true
+
+
+
+
+
+ -
+
+
+
+
+
-
-
+
- Show &tooltips in the book list
+ Disable ¬ifications in system tray
- -
-
+
-
+
+
+ QComboBox::AdjustToMinimumContentsLengthWithIcon
+
+
+ 20
+
+
+
+ -
+
- Extra &spacing to add between rows in the book list (can be negative):
+ &User Interface layout (needs restart):
- opt_book_list_extra_row_spacing
+ opt_gui_layout
- -
-
-
- px
+
-
+
+
+ User interface style (&needs restart):
-
- -20
+
+ opt_ui_style
+
+
+
+ -
+
+
+ Disable all animations. Useful if you have a slow/old computer.
+
+
+ Disable &animations
+
+
+
+ -
+
+
+ Show &splash screen at startup
+
+
+
+ -
+
+
+ Change &icon theme (needs restart)
@@ -274,7 +288,7 @@
-
- &Field to show under the covers:
+ Field to show &under the covers:
opt_field_under_covers_in_grid
@@ -468,7 +482,7 @@ A value of zero means calculate automatically.
-
- &Size of the emblems (if any) shown next to the covers:
+ Size of the emblems (if any) shown &next to the covers:
opt_emblem_size
@@ -757,7 +771,7 @@ A value of zero means calculate automatically.
-
- Default author link template:
+ Default author &link template:
opt_default_author_link
@@ -804,7 +818,7 @@ Manage Authors. You can use the values {author} and
-
- &Collapse when more items than:
+ Co&llapse when more items than:
opt_tags_browser_collapse_at
@@ -825,7 +839,7 @@ up into subcategories. If the partition method is set to disable, this value is
-
- Categories not to partition:
+ Categories ¬ to partition:
opt_tag_browser_dont_collapse