mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Implement #2829 (Request for hyphenation)
This commit is contained in:
parent
ffb1d3d770
commit
ed92482019
@ -146,6 +146,9 @@ class EbookIterator(object):
|
|||||||
|
|
||||||
|
|
||||||
self.opf = OPF(self.pathtoopf, os.path.dirname(self.pathtoopf))
|
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]
|
self.spine = [SpineItem(i.path) for i in self.opf.spine]
|
||||||
|
|
||||||
cover = self.opf.cover
|
cover = self.opf.cover
|
||||||
|
@ -19,7 +19,7 @@ class PluginWidget(Widget, Ui_Form):
|
|||||||
def __init__(self, parent, get_option, get_help, db=None, book_id=None):
|
def __init__(self, parent, get_option, get_help, db=None, book_id=None):
|
||||||
Widget.__init__(self, parent, 'mobi_output',
|
Widget.__init__(self, parent, 'mobi_output',
|
||||||
['prefer_author_sort', 'rescale_images', 'toc_title',
|
['prefer_author_sort', 'rescale_images', 'toc_title',
|
||||||
'dont_compress',]
|
'dont_compress', 'no_inline_toc']
|
||||||
)
|
)
|
||||||
self.db, self.book_id = db, book_id
|
self.db, self.book_id = db, book_id
|
||||||
self.initialize_options(get_option, get_help, db, book_id)
|
self.initialize_options(get_option, get_help, db, book_id)
|
||||||
|
@ -144,7 +144,7 @@
|
|||||||
</item>
|
</item>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="4" column="0" colspan="2">
|
<item row="6" column="0" colspan="2">
|
||||||
<widget class="QCheckBox" name="opt_remember_window_size">
|
<widget class="QCheckBox" name="opt_remember_window_size">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Remember last used &window size</string>
|
<string>Remember last used &window size</string>
|
||||||
@ -174,9 +174,33 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
<item row="4" column="0" colspan="2">
|
||||||
|
<widget class="QCheckBox" name="hyphenate">
|
||||||
|
<property name="text">
|
||||||
|
<string>H&yphenate (break line in the middle of large words)</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="5" column="1">
|
||||||
|
<widget class="QComboBox" name="hyphenate_default_lang">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>The default language to use for hyphenation rules. If the book does not specify a language, this will be used.</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="5" column="0">
|
||||||
|
<widget class="QLabel" name="label_8">
|
||||||
|
<property name="text">
|
||||||
|
<string>Default &language for hyphenation:</string>
|
||||||
|
</property>
|
||||||
|
<property name="buddy">
|
||||||
|
<cstring>hyphenate_default_lang</cstring>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</item>
|
</item>
|
||||||
<item row="2" column="0">
|
<item row="3" column="0">
|
||||||
<widget class="QGroupBox" name="groupBox_2">
|
<widget class="QGroupBox" name="groupBox_2">
|
||||||
<property name="title">
|
<property name="title">
|
||||||
<string>&User stylesheet</string>
|
<string>&User stylesheet</string>
|
||||||
@ -226,8 +250,8 @@
|
|||||||
<slot>accept()</slot>
|
<slot>accept()</slot>
|
||||||
<hints>
|
<hints>
|
||||||
<hint type="sourcelabel">
|
<hint type="sourcelabel">
|
||||||
<x>248</x>
|
<x>252</x>
|
||||||
<y>254</y>
|
<y>569</y>
|
||||||
</hint>
|
</hint>
|
||||||
<hint type="destinationlabel">
|
<hint type="destinationlabel">
|
||||||
<x>157</x>
|
<x>157</x>
|
||||||
@ -242,8 +266,8 @@
|
|||||||
<slot>reject()</slot>
|
<slot>reject()</slot>
|
||||||
<hints>
|
<hints>
|
||||||
<hint type="sourcelabel">
|
<hint type="sourcelabel">
|
||||||
<x>316</x>
|
<x>320</x>
|
||||||
<y>260</y>
|
<y>569</y>
|
||||||
</hint>
|
</hint>
|
||||||
<hint type="destinationlabel">
|
<hint type="destinationlabel">
|
||||||
<x>286</x>
|
<x>286</x>
|
||||||
@ -251,5 +275,21 @@
|
|||||||
</hint>
|
</hint>
|
||||||
</hints>
|
</hints>
|
||||||
</connection>
|
</connection>
|
||||||
|
<connection>
|
||||||
|
<sender>hyphenate</sender>
|
||||||
|
<signal>toggled(bool)</signal>
|
||||||
|
<receiver>hyphenate_default_lang</receiver>
|
||||||
|
<slot>setEnabled(bool)</slot>
|
||||||
|
<hints>
|
||||||
|
<hint type="sourcelabel">
|
||||||
|
<x>83</x>
|
||||||
|
<y>279</y>
|
||||||
|
</hint>
|
||||||
|
<hint type="destinationlabel">
|
||||||
|
<x>349</x>
|
||||||
|
<y>312</y>
|
||||||
|
</hint>
|
||||||
|
</hints>
|
||||||
|
</connection>
|
||||||
</connections>
|
</connections>
|
||||||
</ui>
|
</ui>
|
||||||
|
@ -14,7 +14,7 @@ from PyQt4.QtWebKit import QWebPage, QWebView, QWebSettings
|
|||||||
|
|
||||||
from calibre.utils.config import Config, StringConfig
|
from calibre.utils.config import Config, StringConfig
|
||||||
from calibre.gui2.viewer.config_ui import Ui_Dialog
|
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.ptempfile import PersistentTemporaryFile
|
||||||
from calibre.constants import iswindows
|
from calibre.constants import iswindows
|
||||||
from calibre import prints
|
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.'))
|
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,
|
c.add_opt('max_view_width', default=6000,
|
||||||
help=_('Maximum width of the viewer window, in pixels.'))
|
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 = c.add_group('FONTS', _('Font options'))
|
||||||
fonts('serif_family', default='Times New Roman' if iswindows else 'Liberation Serif',
|
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.setPlainText(opts.user_css)
|
||||||
self.css.setToolTip(_('Set the user CSS stylesheet. This can be used to customize the look of all books.'))
|
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)
|
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):
|
def accept(self, *args):
|
||||||
@ -119,6 +131,9 @@ class ConfigDialog(QDialog, Ui_Dialog):
|
|||||||
c.set('user_css', unicode(self.css.toPlainText()))
|
c.set('user_css', unicode(self.css.toPlainText()))
|
||||||
c.set('remember_window_size', self.opt_remember_window_size.isChecked())
|
c.set('remember_window_size', self.opt_remember_window_size.isChecked())
|
||||||
c.set('max_view_width', int(self.max_view_width.value()))
|
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)
|
return QDialog.accept(self, *args)
|
||||||
|
|
||||||
|
|
||||||
@ -141,12 +156,14 @@ class Document(QWebPage):
|
|||||||
if d.exec_() == QDialog.Accepted:
|
if d.exec_() == QDialog.Accepted:
|
||||||
self.set_font_settings()
|
self.set_font_settings()
|
||||||
self.set_user_stylesheet()
|
self.set_user_stylesheet()
|
||||||
|
self.misc_config()
|
||||||
self.triggerAction(QWebPage.Reload)
|
self.triggerAction(QWebPage.Reload)
|
||||||
|
|
||||||
def __init__(self, *args):
|
def __init__(self, *args):
|
||||||
QWebPage.__init__(self, *args)
|
QWebPage.__init__(self, *args)
|
||||||
self.setObjectName("py_bridge")
|
self.setObjectName("py_bridge")
|
||||||
self.debug_javascript = False
|
self.debug_javascript = False
|
||||||
|
self.current_language = None
|
||||||
#self.js_bridge = PythonJS(self.js_callback)
|
#self.js_bridge = PythonJS(self.js_callback)
|
||||||
|
|
||||||
self.setLinkDelegationPolicy(self.DelegateAllLinks)
|
self.setLinkDelegationPolicy(self.DelegateAllLinks)
|
||||||
@ -170,6 +187,7 @@ class Document(QWebPage):
|
|||||||
# Miscellaneous
|
# Miscellaneous
|
||||||
settings.setAttribute(QWebSettings.LinksIncludedInFocusChain, True)
|
settings.setAttribute(QWebSettings.LinksIncludedInFocusChain, True)
|
||||||
self.set_user_stylesheet()
|
self.set_user_stylesheet()
|
||||||
|
self.misc_config()
|
||||||
|
|
||||||
# Load jQuery
|
# Load jQuery
|
||||||
self.connect(self.mainFrame(), SIGNAL('javaScriptWindowObjectCleared()'),
|
self.connect(self.mainFrame(), SIGNAL('javaScriptWindowObjectCleared()'),
|
||||||
@ -182,18 +200,39 @@ class Document(QWebPage):
|
|||||||
pt.close()
|
pt.close()
|
||||||
self.settings().setUserStyleSheetUrl(QUrl.fromLocalFile(pt.name))
|
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):
|
def load_javascript_libraries(self):
|
||||||
self.mainFrame().addToJavaScriptWindowObject("py_bridge", 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)
|
||||||
self.javascript(jquery_scrollTo)
|
self.javascript(jquery_scrollTo)
|
||||||
self.javascript(bookmarks)
|
self.javascript(bookmarks)
|
||||||
self.javascript(referencing)
|
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("")
|
@pyqtSignature("")
|
||||||
def animated_scroll_done(self):
|
def animated_scroll_done(self):
|
||||||
self.emit(SIGNAL('animated_scroll_done()'))
|
self.emit(SIGNAL('animated_scroll_done()'))
|
||||||
|
|
||||||
|
@pyqtSignature("")
|
||||||
|
def init_hyphenate(self):
|
||||||
|
if self.hyphenate:
|
||||||
|
self.javascript('do_hyphenation("%s")'%self.loaded_lang)
|
||||||
|
|
||||||
@pyqtSignature("QString")
|
@pyqtSignature("QString")
|
||||||
def debug(self, msg):
|
def debug(self, msg):
|
||||||
prints(msg)
|
prints(msg)
|
||||||
@ -401,6 +440,12 @@ class DocumentView(QWebView):
|
|||||||
def content_size(self):
|
def content_size(self):
|
||||||
return self.document.width, self.document.height
|
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):
|
def search(self, text):
|
||||||
return self.findText(text)
|
return self.findText(text)
|
||||||
|
|
||||||
|
@ -132,3 +132,25 @@ $(document.body).click(function(e) {
|
|||||||
$(document).ready(enter_reference_mode);
|
$(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);
|
||||||
|
}
|
||||||
|
'''
|
||||||
|
@ -563,6 +563,7 @@ class EbookViewer(MainWindow, Ui_EbookViewer):
|
|||||||
self.close_progress_indicator()
|
self.close_progress_indicator()
|
||||||
else:
|
else:
|
||||||
self.metadata.show_opf(self.iterator.opf, os.path.splitext(pathtoebook)[1][1:])
|
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
|
title = self.iterator.opf.title
|
||||||
if not title:
|
if not title:
|
||||||
title = os.path.splitext(os.path.basename(pathtoebook))[0]
|
title = os.path.splitext(os.path.basename(pathtoebook))[0]
|
||||||
|
@ -186,12 +186,17 @@ class resources(OptionlessCommand):
|
|||||||
def get_hyphenate(self):
|
def get_hyphenate(self):
|
||||||
sdir = os.path.join('src', 'calibre', 'gui2', 'viewer', 'hyphenate')
|
sdir = os.path.join('src', 'calibre', 'gui2', 'viewer', 'hyphenate')
|
||||||
resources, max = {}, 0
|
resources, max = {}, 0
|
||||||
|
languages = set([])
|
||||||
for f in glob.glob(os.path.join(sdir, 'patterns', '*.js')) + \
|
for f in glob.glob(os.path.join(sdir, 'patterns', '*.js')) + \
|
||||||
[os.path.join(sdir, 'Hyphenator.js')]:
|
[os.path.join(sdir, 'Hyphenator.js')]:
|
||||||
f = os.path.abspath(f)
|
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
|
mtime = os.stat(f).st_mtime
|
||||||
max = mtime if mtime > max else max
|
max = mtime if mtime > max else max
|
||||||
|
resources['languages'] = ','.join(languages)
|
||||||
return resources, max
|
return resources, max
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
@ -205,7 +210,7 @@ class resources(OptionlessCommand):
|
|||||||
static, smax = self.get_static_resources()
|
static, smax = self.get_static_resources()
|
||||||
recipes, rmax = self.get_recipes()
|
recipes, rmax = self.get_recipes()
|
||||||
hyphenate, hmax = self.get_hyphenate()
|
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:
|
if newer([dest], RESOURCES.values()) or os.stat(dest).st_mtime < amax:
|
||||||
print 'Compiling resources...'
|
print 'Compiling resources...'
|
||||||
with open(dest, 'wb') as f:
|
with open(dest, 'wb') as f:
|
||||||
|
Loading…
x
Reference in New Issue
Block a user