From 5bd7c8a9a7af4e15af2b53f409f8c0cb09e8d03e Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Sun, 23 Feb 2025 12:21:17 +0530 Subject: [PATCH] Kobo driver: Add hyphenation config support --- src/calibre/devices/kobo/driver.py | 17 +++- src/calibre/devices/kobo/kobotouch_config.py | 94 +++++++++++++++++++- 2 files changed, 109 insertions(+), 2 deletions(-) diff --git a/src/calibre/devices/kobo/driver.py b/src/calibre/devices/kobo/driver.py index 80fea9a3db..ab347d73c6 100644 --- a/src/calibre/devices/kobo/driver.py +++ b/src/calibre/devices/kobo/driver.py @@ -2335,7 +2335,15 @@ class KOBOTOUCH(KOBO): from calibre.ebooks.oeb.polish.errors import DRMError from calibre.ebooks.oeb.polish.kepubify import kepubify_path, make_options debug_print(f'Starting conversion of {mi.title} ({name}) to kepub') - opts = make_options(extra_css=extra_css or '') + opts = make_options( + extra_css=extra_css or '', + affect_hyphenation=bool(self.get_pref('affect_hyphenation')), + disable_hyphenation=bool(self.get_pref('disable_hyphenation')), + hyphenation_min_chars=bool(self.get_pref('hyphenation_min_chars')), + hyphenation_min_chars_before=bool(self.get_pref('hyphenation_min_chars_before')), + hyphenation_min_chars_after=bool(self.get_pref('hyphenation_min_chars_after')), + hyphenation_limit_lines=bool(self.get_pref('hyphenation_limit_lines')), + ) try: kepubify_path(path, outpath=path, opts=opts, allow_overwrite=True) except DRMError: @@ -3638,6 +3646,13 @@ class KOBOTOUCH(KOBO): c.add_opt('modify_css', default=False) c.add_opt('override_kobo_replace_existing', default=True) # Overriding the replace behaviour is how the driver has always worked. + c.add_opt('affect_hyphenation', default=False) + c.add_opt('disable_hyphenation', default=False) + c.add_opt('hyphenation_min_chars', default=6) + c.add_opt('hyphenation_min_chars_before', default=3) + c.add_opt('hyphenation_min_chars_after', default=3) + c.add_opt('hyphenation_limit_lines', default=2) + c.add_opt('support_newer_firmware', default=False) c.add_opt('debugging_title', default='') c.add_opt('driver_version', default='') # Mainly for debugging purposes, but might use if need to migrate between versions. diff --git a/src/calibre/devices/kobo/kobotouch_config.py b/src/calibre/devices/kobo/kobotouch_config.py index ad9d906ee0..7a142455cc 100644 --- a/src/calibre/devices/kobo/kobotouch_config.py +++ b/src/calibre/devices/kobo/kobotouch_config.py @@ -6,7 +6,7 @@ __docformat__ = 'restructuredtext en' import textwrap -from qt.core import QCheckBox, QDialog, QDialogButtonBox, QGridLayout, QHBoxLayout, QLabel, QLineEdit, QPushButton, QVBoxLayout, QWidget +from qt.core import QCheckBox, QDialog, QDialogButtonBox, QFormLayout, QGridLayout, QHBoxLayout, QLabel, QLineEdit, QPushButton, QSpinBox, QVBoxLayout, QWidget from calibre.gui2 import error_dialog from calibre.gui2.device_drivers.tabbed_device_config import DeviceConfigTab, DeviceOptionsGroupBox, TabbedDeviceConfig @@ -51,9 +51,11 @@ class KOBOTOUCHConfig(TabbedDeviceConfig): self.tab1 = Tab1Config(self, self.device) self.tab2 = Tab2Config(self, self.device) + self.tab3 = Tab3Config(self, self.device) self.addDeviceTab(self.tab1, _('Collections, covers && uploads')) self.addDeviceTab(self.tab2, _('Metadata, on device && advanced')) + self.addDeviceTab(self.tab3, _('Hyphenation')) def get_pref(self, key): return self.device.get_pref(key) @@ -191,6 +193,21 @@ class Tab2Config(DeviceConfigTab): # {{{ # }}} +class Tab3Config(DeviceConfigTab): # {{{ + + def __init__(self, parent, device): + super().__init__(parent) + self.l = l = QVBoxLayout(self) + self.hyphenation_options = h = HyphenationGroupBox(self, device) + l.addWidget(h) + l.addStretch() + + def validate(self): + return self.hyphenation_options.validate() + +# }}} + + class BookUploadsGroupBox(DeviceOptionsGroupBox): def __init__(self, parent, device): @@ -242,6 +259,81 @@ class BookUploadsGroupBox(DeviceOptionsGroupBox): return self.override_kobo_replace_existing_checkbox.isChecked() +class HyphenationGroupBox(DeviceOptionsGroupBox): + + def __init__(self, parent, device): + super().__init__(parent, device) + self.setTitle(_('Enable/disable hyphenation in KEPUB books')) + self.setCheckable(True) + self.setChecked(device.get_pref('affect_hyphenation')) + self.l = l = QFormLayout(self) + la = QLabel(_( + 'When sending EPUB as converted KEPUB to the device, you can optionally' + ' modify how the device will perform hyphenation for the book. Note that hyphenation' + ' does not work well for all languages, as it depends on dictionaries present on the device,' + ' which are not always of the highest quality.')) + la.setWordWrap(True) + l.addRow(la) + + self.disable_hyphenation_checkbox = d = QCheckBox(_('Turn off all hyphenation')) + d.setChecked(device.get_pref('disable_hyphenation')) + d.setToolTip(_('Override all hyphenation settings in book, forcefully disabling hyphenation completely')) + l.addRow(d) + + self.min_chars = mc = QSpinBox(self) + l.addRow(_('Minimum word length to hyphenate') + ':', mc) + mc.setSuffix(_(' characters')) + mc.setSpecialValueText(_('Disabled')) + mc.setRange(0, 20) + mc.setValue(device.get_pref('hyphenation_min_chars')) + + self.min_chars_before = mc = QSpinBox(self) + l.addRow(_('Minimum character before hyphens') + ':', mc) + mc.setSuffix(_(' characters')) + mc.setRange(2, 20) + mc.setValue(device.get_pref('hyphenation_min_chars_before')) + + self.min_chars_after = mc = QSpinBox(self) + l.addRow(_('Minimum character after hyphens') + ':', mc) + mc.setSuffix(_(' characters')) + mc.setRange(2, 20) + mc.setValue(device.get_pref('hyphenation_min_chars_after')) + + self.limit_lines = mc = QSpinBox(self) + l.addRow(_('Maximum consecutive hyphenated lines') + ':', mc) + mc.setSuffix(_(' lines')) + mc.setSpecialValueText(_('Disabled')) + mc.setRange(0, 20) + mc.setValue(device.get_pref('hyphenation_limit_lines')) + + def validate(self): + return True + + @property + def affect_hyphenation(self): + return self.isChecked() + + @property + def disable_hyphenation(self): + return self.disable_hyphenation_checkbox.isChecked() + + @property + def hyphenation_min_chars(self): + return self.min_chars.value() + + @property + def hyphenation_min_chars_before(self): + return self.min_chars_before.value() + + @property + def hyphenation_min_chars_after(self): + return self.min_chars_after.value() + + @property + def hyphenation_limit_lines(self): + return self.limit_lines.value() + + class CollectionsGroupBox(DeviceOptionsGroupBox): def __init__(self, parent, device):