mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-07 10:14:46 -04:00
E-book viewer: Allow customizing the website that is used as a dictionary for looking up words in the viewer. Click the Preferences button in the viewer and choose the dictionaries tab to customize the website.
This commit is contained in:
parent
01847b8983
commit
3bdb87f90b
@ -10,15 +10,18 @@ __docformat__ = 'restructuredtext en'
|
||||
import zipfile
|
||||
from functools import partial
|
||||
|
||||
from PyQt5.Qt import (QFont, QDialog, Qt, QColor, QColorDialog,
|
||||
QMenu, QInputDialog)
|
||||
from PyQt5.Qt import (
|
||||
QFont, QDialog, Qt, QColor, QColorDialog, QMenu, QInputDialog,
|
||||
QListWidgetItem, QFormLayout, QLabel, QLineEdit, QDialogButtonBox)
|
||||
|
||||
from calibre.constants import iswindows, isxp
|
||||
from calibre.utils.config import Config, StringConfig, JSONConfig
|
||||
from calibre.gui2 import min_available_height
|
||||
from calibre.utils.icu import sort_key
|
||||
from calibre.utils.localization import get_language, calibre_langcode_to_name
|
||||
from calibre.gui2 import min_available_height, error_dialog
|
||||
from calibre.gui2.languages import LanguagesEdit
|
||||
from calibre.gui2.shortcuts import ShortcutConfig
|
||||
from calibre.gui2.viewer.config_ui import Ui_Dialog
|
||||
from calibre.utils.localization import get_language
|
||||
|
||||
def config(defaults=None):
|
||||
desc = _('Options to customize the ebook viewer')
|
||||
@ -143,10 +146,14 @@ class ConfigDialog(QDialog, Ui_Dialog):
|
||||
opts = config().parse()
|
||||
self.load_options(opts)
|
||||
self.init_load_themes()
|
||||
self.init_dictionaries()
|
||||
|
||||
self.clear_search_history_button.clicked.connect(self.clear_search_history)
|
||||
self.resize(self.width(), min(self.height(), max(575, min_available_height()-25)))
|
||||
|
||||
for x in 'add remove change'.split():
|
||||
getattr(self, x + '_dictionary_website_button').clicked.connect(getattr(self, x + '_dictionary_website'))
|
||||
|
||||
def clear_search_history(self):
|
||||
from calibre.gui2 import config
|
||||
config['viewer_search_history'] = []
|
||||
@ -190,9 +197,83 @@ class ConfigDialog(QDialog, Ui_Dialog):
|
||||
self.theming_message.setText(_('Deleted the theme named: %s')%
|
||||
theme[len('theme_'):])
|
||||
|
||||
def init_dictionaries(self):
|
||||
from calibre.gui2.viewer.main import dprefs
|
||||
self.word_lookups = dprefs['word_lookups']
|
||||
|
||||
@dynamic_property
|
||||
def word_lookups(self):
|
||||
def fget(self):
|
||||
return dict(self.dictionary_list.item(i).data(Qt.UserRole) for i in range(self.dictionary_list.count()))
|
||||
def fset(self, wl):
|
||||
self.dictionary_list.clear()
|
||||
for langcode, url in sorted(wl.iteritems(), key=lambda (lc, url):sort_key(calibre_langcode_to_name(lc))):
|
||||
i = QListWidgetItem('%s: %s' % (calibre_langcode_to_name(langcode), url), self.dictionary_list)
|
||||
i.setData(Qt.UserRole, (langcode, url))
|
||||
return property(fget=fget, fset=fset)
|
||||
|
||||
def add_dictionary_website(self):
|
||||
class AD(QDialog):
|
||||
|
||||
def __init__(self, parent):
|
||||
QDialog.__init__(self, parent)
|
||||
self.setWindowTitle(_('Add a dictionary website'))
|
||||
self.l = l = QFormLayout(self)
|
||||
self.la = la = QLabel(
|
||||
_('Choose a language and enter the website address (URL) for it below.'
|
||||
' The URL must have %s in it, which will be replaced by the actual word being'
|
||||
' looked up') % '{word}')
|
||||
la.setWordWrap(True)
|
||||
l.addRow(la)
|
||||
self.le = LanguagesEdit(self)
|
||||
l.addRow(_('&Language:'), self.le)
|
||||
self.url = u = QLineEdit(self)
|
||||
u.setMinimumWidth(350)
|
||||
u.setPlaceholderText(_('For example: %s') % 'http://dictionary.com/{word}')
|
||||
l.addRow(_('&URL:'), u)
|
||||
self.bb = bb = QDialogButtonBox(QDialogButtonBox.Ok|QDialogButtonBox.Cancel)
|
||||
l.addRow(bb)
|
||||
bb.accepted.connect(self.accept), bb.rejected.connect(self.reject)
|
||||
self.resize(self.sizeHint())
|
||||
|
||||
def accept(self):
|
||||
if '{word}' not in self.url.text():
|
||||
return error_dialog(self, _('Invalid URL'), _(
|
||||
'The URL {0} does not have {1} in it.').format(self.url.text(), '{word}'), show=True)
|
||||
QDialog.accept(self)
|
||||
|
||||
d = AD(self)
|
||||
if d.exec_() == d.Accepted:
|
||||
url = d.url.text()
|
||||
if url:
|
||||
wl = self.word_lookups
|
||||
for lc in d.le.lang_codes:
|
||||
wl[lc] = url
|
||||
self.word_lookups = wl
|
||||
|
||||
def remove_dictionary_website(self):
|
||||
idx = self.dictionary_list.currentIndex()
|
||||
if idx.isValid():
|
||||
lc, url = idx.data(Qt.UserRole)
|
||||
wl = self.word_lookups
|
||||
wl.pop(lc, None)
|
||||
self.word_lookups = wl
|
||||
|
||||
def change_dictionary_website(self):
|
||||
idx = self.dictionary_list.currentIndex()
|
||||
if idx.isValid():
|
||||
lc, url = idx.data(Qt.UserRole)
|
||||
url, ok = QInputDialog.getText(self, _('Enter new website'), 'URL:', text=url)
|
||||
if ok:
|
||||
wl = self.word_lookups
|
||||
wl[lc] = url
|
||||
self.word_lookups = wl
|
||||
|
||||
def restore_defaults(self):
|
||||
opts = config('').parse()
|
||||
self.load_options(opts)
|
||||
from calibre.gui2.viewer.main import dprefs
|
||||
self.word_lookups = dprefs.defaults['word_lookups']
|
||||
|
||||
def load_options(self, opts):
|
||||
self.opt_remember_window_size.setChecked(opts.remember_window_size)
|
||||
@ -320,5 +401,5 @@ class ConfigDialog(QDialog, Ui_Dialog):
|
||||
c.set('show_controls', self.opt_show_controls.isChecked())
|
||||
for x in ('top', 'bottom', 'side'):
|
||||
c.set(x+'_margin', int(getattr(self, 'opt_%s_margin'%x).value()))
|
||||
|
||||
|
||||
from calibre.gui2.viewer.main import dprefs
|
||||
dprefs['word_lookups'] = self.word_lookups
|
||||
|
@ -67,8 +67,8 @@ QToolBox::tab:hover {
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>811</width>
|
||||
<height>380</height>
|
||||
<width>371</width>
|
||||
<height>236</height>
|
||||
</rect>
|
||||
</property>
|
||||
<attribute name="label">
|
||||
@ -240,8 +240,8 @@ QToolBox::tab:hover {
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>811</width>
|
||||
<height>380</height>
|
||||
<width>374</width>
|
||||
<height>211</height>
|
||||
</rect>
|
||||
</property>
|
||||
<attribute name="label">
|
||||
@ -370,8 +370,8 @@ QToolBox::tab:hover {
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>811</width>
|
||||
<height>380</height>
|
||||
<width>799</width>
|
||||
<height>378</height>
|
||||
</rect>
|
||||
</property>
|
||||
<attribute name="label">
|
||||
@ -472,8 +472,8 @@ QToolBox::tab:hover {
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>811</width>
|
||||
<height>380</height>
|
||||
<width>340</width>
|
||||
<height>70</height>
|
||||
</rect>
|
||||
</property>
|
||||
<attribute name="label">
|
||||
@ -551,8 +551,8 @@ QToolBox::tab:hover {
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>811</width>
|
||||
<height>380</height>
|
||||
<width>384</width>
|
||||
<height>115</height>
|
||||
</rect>
|
||||
</property>
|
||||
<attribute name="label">
|
||||
@ -622,8 +622,8 @@ QToolBox::tab:hover {
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>811</width>
|
||||
<height>380</height>
|
||||
<width>368</width>
|
||||
<height>167</height>
|
||||
</rect>
|
||||
</property>
|
||||
<attribute name="label">
|
||||
@ -853,6 +853,81 @@ QToolBox::tab:hover {
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="tab_5">
|
||||
<attribute name="title">
|
||||
<string>&Dictionaries</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_4">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_25">
|
||||
<property name="text">
|
||||
<string>When you lookup a word, the viewer opens the word's definition in a dictionary website. The dictionary website is chosen based on the language of the book. You can customize the website used for a particular language here.</string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QListWidget" name="dictionary_list"/>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||
<item>
|
||||
<widget class="QPushButton" name="add_dictionary_website_button">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>&Add website</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../../../../resources/images.qrc">
|
||||
<normaloff>:/images/plus.png</normaloff>:/images/plus.png</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="remove_dictionary_website_button">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>&Remove website</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../../../../resources/images.qrc">
|
||||
<normaloff>:/images/minus.png</normaloff>:/images/minus.png</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="change_dictionary_website_button">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>&Change website</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../../../../resources/images.qrc">
|
||||
<normaloff>:/images/edit_input.png</normaloff>:/images/edit_input.png</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
|
@ -24,8 +24,11 @@ from calibre.customize.ui import available_input_formats
|
||||
from calibre import as_unicode, force_unicode, isbytestring
|
||||
from calibre.ptempfile import reset_base_dir
|
||||
from calibre.utils.zipfile import BadZipfile
|
||||
from calibre.utils.localization import canonicalize_lang, lang_as_iso639_1
|
||||
|
||||
vprefs = JSONConfig('viewer')
|
||||
dprefs = JSONConfig('viewer_dictionaries')
|
||||
dprefs.defaults['word_lookups'] = {}
|
||||
|
||||
class Worker(Thread):
|
||||
|
||||
@ -48,6 +51,18 @@ class RecentAction(QAction):
|
||||
self.path = path
|
||||
QAction.__init__(self, os.path.basename(path), parent)
|
||||
|
||||
def default_lookup_website(lang):
|
||||
lang = lang_as_iso639_1(lang) or lang
|
||||
if lang == 'en':
|
||||
prefix = 'https://www.wordnik.com/words/'
|
||||
else:
|
||||
prefix = 'http://%s.wiktionary.org/wiki/' % lang
|
||||
return prefix + '{word}'
|
||||
|
||||
def lookup_website(lang):
|
||||
wm = dprefs['word_lookups']
|
||||
return wm.get(lang, default_lookup_website(lang))
|
||||
|
||||
class EbookViewer(MainWindow):
|
||||
|
||||
STATE_VERSION = 2
|
||||
@ -272,17 +287,14 @@ class EbookViewer(MainWindow):
|
||||
at_start=True)
|
||||
|
||||
def lookup(self, word):
|
||||
from calibre.utils.localization import canonicalize_lang, lang_as_iso639_1
|
||||
from urllib import quote
|
||||
lang = lang_as_iso639_1(self.view.current_language)
|
||||
if not lang:
|
||||
lang = canonicalize_lang(lang) or 'en'
|
||||
word = quote(word.encode('utf-8'))
|
||||
if lang == 'en':
|
||||
prefix = 'https://www.wordnik.com/words/'
|
||||
else:
|
||||
prefix = 'http://%s.wiktionary.org/wiki/' % lang
|
||||
open_url(prefix + word)
|
||||
try:
|
||||
url = lookup_website(canonicalize_lang(self.view.current_language) or 'en').format(word=word)
|
||||
except Exception:
|
||||
traceback.print_exc()
|
||||
url = default_lookup_website(canonicalize_lang(self.view.current_language) or 'en').format(word=word)
|
||||
open_url(url)
|
||||
|
||||
def get_remember_current_page_opt(self):
|
||||
from calibre.gui2.viewer.documentview import config
|
||||
|
Loading…
x
Reference in New Issue
Block a user