From 8ec93d806fb9b9c4c4476171e5384633023b16fe Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Sat, 11 Apr 2015 09:35:18 +0530 Subject: [PATCH] Edit Book: Make embedding fonts using the manage fonts dialog easier. You can now double click on a font family to see what faces for that family area available on your computer and install new fonts directly from the dialog. --- src/calibre/gui2/font_family_chooser.py | 56 +++++++------ src/calibre/gui2/tweak_book/manage_fonts.py | 93 ++++++++++++++++++--- 2 files changed, 115 insertions(+), 34 deletions(-) diff --git a/src/calibre/gui2/font_family_chooser.py b/src/calibre/gui2/font_family_chooser.py index 7d5e318315..b4ad3331c2 100644 --- a/src/calibre/gui2/font_family_chooser.py +++ b/src/calibre/gui2/font_family_chooser.py @@ -18,6 +18,34 @@ from PyQt5.Qt import (QFontInfo, QFontMetrics, Qt, QFont, QFontDatabase, QPen, from calibre.constants import config_dir from calibre.gui2 import choose_files, error_dialog, info_dialog + +def add_fonts(parent): + from calibre.utils.fonts.metadata import FontMetadata + files = choose_files(parent, 'add fonts to calibre', + _('Select font files'), filters=[(_('TrueType/OpenType Fonts'), + ['ttf', 'otf'])], all_files=False) + if not files: + return + families = set() + for f in files: + try: + with open(f, 'rb') as stream: + fm = FontMetadata(stream) + except: + import traceback + error_dialog(parent, _('Corrupt font'), + _('Failed to read metadata from the font file: %s')% + f, det_msg=traceback.format_exc(), show=True) + return + families.add(fm.font_family) + families = sorted(families) + + dest = os.path.join(config_dir, 'fonts') + for f in files: + shutil.copyfile(f, os.path.join(dest, os.path.basename(f))) + + return families + def writing_system_for_font(font): has_latin = True systems = QFontDatabase().writingSystems(font.family()) @@ -136,8 +164,8 @@ class Typefaces(QLabel): '''%(_('Available faces for %s')%family) entries = [] for font in faces: - sf = (font['wws_subfamily_name'] or font['preferred_subfamily_name'] - or font['subfamily_name']) + sf = (font['wws_subfamily_name'] or font['preferred_subfamily_name'] or + font['subfamily_name']) entries.append('''
{sf}
font-stretch: {width} font-weight: {weight} font-style: @@ -261,29 +289,9 @@ class FontFamilyDialog(QDialog): self.m.setStringList(self.families) def add_fonts(self): - from calibre.utils.fonts.metadata import FontMetadata - files = choose_files(self, 'add fonts to calibre', - _('Select font files'), filters=[(_('TrueType/OpenType Fonts'), - ['ttf', 'otf'])], all_files=False) - if not files: + families = add_fonts(self) + if not families: return - families = set() - for f in files: - try: - with open(f, 'rb') as stream: - fm = FontMetadata(stream) - except: - import traceback - error_dialog(self, _('Corrupt font'), - _('Failed to read metadata from the font file: %s')% - f, det_msg=traceback.format_exc(), show=True) - return - families.add(fm.font_family) - families = sorted(families) - - dest = os.path.join(config_dir, 'fonts') - for f in files: - shutil.copyfile(f, os.path.join(dest, os.path.basename(f))) self.font_scanner.do_scan() self.m.beginResetModel() self.build_font_list() diff --git a/src/calibre/gui2/tweak_book/manage_fonts.py b/src/calibre/gui2/tweak_book/manage_fonts.py index 4c52d473e0..5787cc5f36 100644 --- a/src/calibre/gui2/tweak_book/manage_fonts.py +++ b/src/calibre/gui2/tweak_book/manage_fonts.py @@ -6,21 +6,51 @@ from __future__ import (unicode_literals, division, absolute_import, __license__ = 'GPL v3' __copyright__ = '2014, Kovid Goyal ' -import sys +import sys, textwrap from PyQt5.Qt import ( QSplitter, QVBoxLayout, QTableView, QWidget, QLabel, QAbstractTableModel, - Qt, QApplication, QTimer, QPushButton, pyqtSignal, QFormLayout, QLineEdit, - QIcon, QSize) + Qt, QTimer, QPushButton, pyqtSignal, QFormLayout, QLineEdit, QIcon, QSize, + QHBoxLayout, QTextEdit) from calibre.ebooks.oeb.polish.container import get_container from calibre.ebooks.oeb.polish.fonts import font_family_data, change_font -from calibre.gui2 import error_dialog +from calibre.gui2 import error_dialog, info_dialog from calibre.gui2.tweak_book import current_container, set_current_container from calibre.gui2.tweak_book.widgets import Dialog, BusyCursor from calibre.utils.icu import primary_sort_key as sort_key from calibre.utils.fonts.scanner import font_scanner, NoFonts +class EmbeddingData(Dialog): + + def __init__(self, family, faces, parent=None): + Dialog.__init__(self, _('Font faces for %s') % family, 'editor-embedding-data', parent) + self.family, self.faces = family, faces + self.populate_text() + + def sizeHint(self): + return QSize(600, 500) + + def setup_ui(self): + self.l = l = QVBoxLayout(self) + self.text = t = QTextEdit(self) + t.setReadOnly(True) + l.addWidget(t), l.addWidget(self.bb) + self.bb.clear(), self.bb.setStandardButtons(self.bb.Close) + + def populate_text(self): + text = ['

' + self.windowTitle() + '

    '] + for face in self.faces: + text.append('
  • ' + _('Path to font file:') + '\xa0\xa0' + '' + face['path'] + '') + name = face.get('full_name') or face.get('family_name') or face.get('subfamily_name') + if name: + text.append('
    ' + _('Name:') + '\xa0' + type('')(name) + '') + if 'font-weight' in face: + text.append('
    ' + 'font-weight:\xa0' + type('')(face['font-weight'])) + if 'font-style' in face: + text.append('
    ' + 'font-style:\xa0' + type('')(face['font-style'])) + self.text.setHtml('\n'.join(text)) + class AllFonts(QAbstractTableModel): def __init__(self, parent=None): @@ -65,7 +95,20 @@ class AllFonts(QAbstractTableModel): if role == Qt.TextAlignmentRole: col = index.column() if col == 0: - return Qt.AlignHCenter + return Qt.AlignHCenter | Qt.AlignVCenter + if role in (Qt.UserRole, Qt.UserRole + 1): + row = index.row() + try: + name = self.items[row] + except (IndexError, KeyError): + return + if role == Qt.UserRole: + try: + return font_scanner.fonts_for_family(name) + except NoFonts: + return [] + else: + return name def sort(self, col, order=Qt.AscendingOrder): sorted_on = (('name' if col == 1 else 'embedded'), order == Qt.AscendingOrder) @@ -152,9 +195,16 @@ class ManageFonts(Dialog): self.bb.clear() self.bb.addButton(self.bb.Close) self.splitter = s = QSplitter(self) - l.addWidget(s), l.addWidget(self.bb) + self.h = h = QHBoxLayout() + h.setContentsMargins(0, 0, 0, 0) + self.install_fonts_button = b = QPushButton(_('&Install fonts'), self) + h.addWidget(b), b.setIcon(QIcon(I('plus.png'))) + b.setToolTip(textwrap.fill(_('Install fonts from .ttf/.otf files to make them available for embedding'))) + b.clicked.connect(self.install_fonts) + l.addWidget(s), l.addLayout(h), h.addStretch(10), h.addWidget(self.bb) self.fonts_view = fv = QTableView(self) + fv.doubleClicked.connect(self.show_embedding_data) self.model = m = AllFonts(fv) fv.horizontalHeader().setStretchLastSection(True) fv.setModel(m) @@ -190,14 +240,36 @@ class ManageFonts(Dialog): b.setIcon(QIcon(I('view-refresh.png'))) b.clicked.connect(self.refresh) - self.la = la = QLabel('

    ' + _( - ''' All the fonts declared in this book are shown to the left, along with whether they are embedded or not. - You can remove or replace any selected font and also embed any declared fonts that are not already embedded.''')) + self.la = la = QLabel( + '

    ' + _( + ''' All the fonts declared in this book are shown to the left, along with whether they are embedded or not. + You can remove or replace any selected font and also embed any declared fonts that are not already embedded.''') + '

    ' + _( + ''' Double click any font family to see if the font is available for embedding on your computer. ''') + ) la.setWordWrap(True) l.addWidget(la) l.setAlignment(Qt.AlignTop | Qt.AlignHCenter) + def show_embedding_data(self, index): + faces = index.data(Qt.UserRole) + family = index.data(Qt.UserRole + 1) + if not faces: + return error_dialog(self, _('Not found'), _( + 'The font %s was not found on your computer. If you have the font files,' + ' you can install it using the "Install fonts" button in the lower left corner.' + ) % family, show=True) + EmbeddingData(family, faces, self).exec_() + + def install_fonts(self): + from calibre.gui2.font_family_chooser import add_fonts + families = add_fonts(self) + if not families: + return + font_scanner.do_scan() + self.refresh() + info_dialog(self, _('Added fonts'), _('Added font families: %s')%(', '.join(families)), show=True) + def sizeHint(self): return Dialog.sizeHint(self) + QSize(100, 50) @@ -250,7 +322,8 @@ class ManageFonts(Dialog): self.model.build() if __name__ == '__main__': - app = QApplication([]) + from calibre.gui2 import Application + app = Application([]) c = get_container(sys.argv[-1], tweak_mode=True) set_current_container(c) d = ManageFonts()