From ed9248201952760e952bfe3563673697a51fd08c Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Tue, 14 Jul 2009 18:12:29 -0600 Subject: [PATCH] Implement #2829 (Request for hyphenation) --- src/calibre/ebooks/oeb/iterator.py | 3 ++ src/calibre/gui2/convert/mobi_output.py | 2 +- src/calibre/gui2/viewer/config.ui | 52 ++++++++++++++++++++++--- src/calibre/gui2/viewer/documentview.py | 49 ++++++++++++++++++++++- src/calibre/gui2/viewer/js.py | 22 +++++++++++ src/calibre/gui2/viewer/main.py | 1 + upload.py | 9 ++++- 7 files changed, 127 insertions(+), 11 deletions(-) diff --git a/src/calibre/ebooks/oeb/iterator.py b/src/calibre/ebooks/oeb/iterator.py index 03c09262d4..4910bf4e10 100644 --- a/src/calibre/ebooks/oeb/iterator.py +++ b/src/calibre/ebooks/oeb/iterator.py @@ -146,6 +146,9 @@ class EbookIterator(object): self.opf = OPF(self.pathtoopf, os.path.dirname(self.pathtoopf)) + self.language = self.opf.language + if self.language: + self.language = self.language.lower() self.spine = [SpineItem(i.path) for i in self.opf.spine] cover = self.opf.cover diff --git a/src/calibre/gui2/convert/mobi_output.py b/src/calibre/gui2/convert/mobi_output.py index f7d41957b2..611ef96e11 100644 --- a/src/calibre/gui2/convert/mobi_output.py +++ b/src/calibre/gui2/convert/mobi_output.py @@ -19,7 +19,7 @@ class PluginWidget(Widget, Ui_Form): def __init__(self, parent, get_option, get_help, db=None, book_id=None): Widget.__init__(self, parent, 'mobi_output', ['prefer_author_sort', 'rescale_images', 'toc_title', - 'dont_compress',] + 'dont_compress', 'no_inline_toc'] ) self.db, self.book_id = db, book_id self.initialize_options(get_option, get_help, db, book_id) diff --git a/src/calibre/gui2/viewer/config.ui b/src/calibre/gui2/viewer/config.ui index 77532cdd6e..7b286f194c 100644 --- a/src/calibre/gui2/viewer/config.ui +++ b/src/calibre/gui2/viewer/config.ui @@ -144,7 +144,7 @@ - + Remember last used &window size @@ -174,9 +174,33 @@ + + + + H&yphenate (break line in the middle of large words) + + + + + + + The default language to use for hyphenation rules. If the book does not specify a language, this will be used. + + + + + + + Default &language for hyphenation: + + + hyphenate_default_lang + + + - + &User stylesheet @@ -226,8 +250,8 @@ accept() - 248 - 254 + 252 + 569 157 @@ -242,8 +266,8 @@ reject() - 316 - 260 + 320 + 569 286 @@ -251,5 +275,21 @@ + + hyphenate + toggled(bool) + hyphenate_default_lang + setEnabled(bool) + + + 83 + 279 + + + 349 + 312 + + + diff --git a/src/calibre/gui2/viewer/documentview.py b/src/calibre/gui2/viewer/documentview.py index 0c807a608a..8b7884d632 100644 --- a/src/calibre/gui2/viewer/documentview.py +++ b/src/calibre/gui2/viewer/documentview.py @@ -14,7 +14,7 @@ from PyQt4.QtWebKit import QWebPage, QWebView, QWebSettings from calibre.utils.config import Config, StringConfig from calibre.gui2.viewer.config_ui import Ui_Dialog -from calibre.gui2.viewer.js import bookmarks, referencing +from calibre.gui2.viewer.js import bookmarks, referencing, hyphenation from calibre.ptempfile import PersistentTemporaryFile from calibre.constants import iswindows from calibre import prints @@ -61,6 +61,9 @@ def config(defaults=None): help=_('Set the user CSS stylesheet. This can be used to customize the look of all books.')) c.add_opt('max_view_width', default=6000, help=_('Maximum width of the viewer window, in pixels.')) + c.add_opt('hyphenate', default=False, help=_('Hyphenate text')) + c.add_opt('hyphenate_default_lang', default='en', + help=_('Default language for hyphenation rules')) fonts = c.add_group('FONTS', _('Font options')) fonts('serif_family', default='Times New Roman' if iswindows else 'Liberation Serif', @@ -106,6 +109,15 @@ class ConfigDialog(QDialog, Ui_Dialog): self.css.setPlainText(opts.user_css) self.css.setToolTip(_('Set the user CSS stylesheet. This can be used to customize the look of all books.')) self.max_view_width.setValue(opts.max_view_width) + from calibre.resources import hyphenate + for x in sorted(hyphenate['languages'].split(',')): + self.hyphenate_default_lang.addItem(x) + idx = self.hyphenate_default_lang.findText(opts.hyphenate_default_lang) + if idx == -1: + idx = self.hyphenate_default_lang.findText('en') + self.hyphenate_default_lang.setCurrentIndex(idx) + self.hyphenate.setChecked(opts.hyphenate) + self.hyphenate_default_lang.setEnabled(opts.hyphenate) def accept(self, *args): @@ -119,6 +131,9 @@ class ConfigDialog(QDialog, Ui_Dialog): c.set('user_css', unicode(self.css.toPlainText())) c.set('remember_window_size', self.opt_remember_window_size.isChecked()) c.set('max_view_width', int(self.max_view_width.value())) + c.set('hyphenate', self.hyphenate.isChecked()) + c.set('hyphenate_default_lang', + self.hyphenate_default_lang.currentText()) return QDialog.accept(self, *args) @@ -141,12 +156,14 @@ class Document(QWebPage): if d.exec_() == QDialog.Accepted: self.set_font_settings() self.set_user_stylesheet() + self.misc_config() self.triggerAction(QWebPage.Reload) def __init__(self, *args): QWebPage.__init__(self, *args) self.setObjectName("py_bridge") self.debug_javascript = False + self.current_language = None #self.js_bridge = PythonJS(self.js_callback) self.setLinkDelegationPolicy(self.DelegateAllLinks) @@ -170,6 +187,7 @@ class Document(QWebPage): # Miscellaneous settings.setAttribute(QWebSettings.LinksIncludedInFocusChain, True) self.set_user_stylesheet() + self.misc_config() # Load jQuery self.connect(self.mainFrame(), SIGNAL('javaScriptWindowObjectCleared()'), @@ -182,18 +200,39 @@ class Document(QWebPage): pt.close() self.settings().setUserStyleSheetUrl(QUrl.fromLocalFile(pt.name)) + def misc_config(self): + opts = config().parse() + self.hyphenate = opts.hyphenate + self.hyphenate_default_lang = opts.hyphenate_default_lang + def load_javascript_libraries(self): self.mainFrame().addToJavaScriptWindowObject("py_bridge", self) - from calibre.resources import jquery, jquery_scrollTo + from calibre.resources import jquery, jquery_scrollTo, hyphenate self.javascript(jquery) self.javascript(jquery_scrollTo) self.javascript(bookmarks) self.javascript(referencing) + self.javascript(hyphenation) + default_lang = self.hyphenate_default_lang + lang = self.current_language + if not lang: + lang = default_lang + lang = lang.lower()[:2] + if lang not in hyphenate['languages']: + lang = default_lang + self.loaded_lang = lang + self.javascript(hyphenate['Hyphenator.js'].decode('utf-8')) + self.javascript(hyphenate[lang+'.js'].decode('utf-8')) @pyqtSignature("") def animated_scroll_done(self): self.emit(SIGNAL('animated_scroll_done()')) + @pyqtSignature("") + def init_hyphenate(self): + if self.hyphenate: + self.javascript('do_hyphenation("%s")'%self.loaded_lang) + @pyqtSignature("QString") def debug(self, msg): prints(msg) @@ -401,6 +440,12 @@ class DocumentView(QWebView): def content_size(self): return self.document.width, self.document.height + @dynamic_property + def current_language(self): + def fget(self): return self.document.current_language + def fset(self, val): self.document.current_language = val + return property(fget=fget, fset=fset) + def search(self, text): return self.findText(text) diff --git a/src/calibre/gui2/viewer/js.py b/src/calibre/gui2/viewer/js.py index 5e46bcdcfa..68768829bb 100644 --- a/src/calibre/gui2/viewer/js.py +++ b/src/calibre/gui2/viewer/js.py @@ -132,3 +132,25 @@ $(document.body).click(function(e) { $(document).ready(enter_reference_mode); ''' + +hyphenation = ''' +function init_hyphenate() { + window.py_bridge.init_hyphenate(); +} + +document.addEventListener("DOMContentLoaded", init_hyphenate, false); + +function do_hyphenation(lang) { + Hyphenator.config( + { + 'minwordlength' : 6, + //'hyphenchar' : '|', + 'displaytogglebox' : false, + 'remoteloading' : false, + 'onerrorhandler' : function (e) { + window.py_bridge.debug(e); + } + }); + Hyphenator.hyphenate(document.body, lang); +} +''' diff --git a/src/calibre/gui2/viewer/main.py b/src/calibre/gui2/viewer/main.py index 0ed5312bf8..6fdeba8df7 100644 --- a/src/calibre/gui2/viewer/main.py +++ b/src/calibre/gui2/viewer/main.py @@ -563,6 +563,7 @@ class EbookViewer(MainWindow, Ui_EbookViewer): self.close_progress_indicator() else: self.metadata.show_opf(self.iterator.opf, os.path.splitext(pathtoebook)[1][1:]) + self.view.current_language = self.iterator.language title = self.iterator.opf.title if not title: title = os.path.splitext(os.path.basename(pathtoebook))[0] diff --git a/upload.py b/upload.py index 802aa8c93a..45dbac0bd6 100644 --- a/upload.py +++ b/upload.py @@ -186,12 +186,17 @@ class resources(OptionlessCommand): def get_hyphenate(self): sdir = os.path.join('src', 'calibre', 'gui2', 'viewer', 'hyphenate') resources, max = {}, 0 + languages = set([]) for f in glob.glob(os.path.join(sdir, 'patterns', '*.js')) + \ [os.path.join(sdir, 'Hyphenator.js')]: f = os.path.abspath(f) - resources[os.path.basename(f)] = self.get(f) + b = os.path.basename(f) + resources[b] = self.get(f) + if b != 'Hyphenator.js': + languages.add(b.split('.')[0]) mtime = os.stat(f).st_mtime max = mtime if mtime > max else max + resources['languages'] = ','.join(languages) return resources, max def run(self): @@ -205,7 +210,7 @@ class resources(OptionlessCommand): static, smax = self.get_static_resources() recipes, rmax = self.get_recipes() hyphenate, hmax = self.get_hyphenate() - amax = max(rmax, smax, hmax) + amax = max(rmax, smax, hmax, os.stat(__file__).st_mtime) if newer([dest], RESOURCES.values()) or os.stat(dest).st_mtime < amax: print 'Compiling resources...' with open(dest, 'wb') as f: