Start work on dialog to manage user installed dictionaries

This commit is contained in:
Kovid Goyal 2014-03-27 21:54:28 +05:30
parent eec1053b49
commit 1b530b128d
2 changed files with 198 additions and 3 deletions

View File

@ -0,0 +1,187 @@
#!/usr/bin/env python
# vim:fileencoding=utf-8
from __future__ import (unicode_literals, division, absolute_import,
print_function)
__license__ = 'GPL v3'
__copyright__ = '2014, Kovid Goyal <kovid at kovidgoyal.net>'
import cPickle
from collections import defaultdict
from PyQt4.Qt import (
QGridLayout, QApplication, QTreeWidget, QTreeWidgetItem, Qt, QFont,
QStackedLayout, QLabel, QVBoxLayout, QVariant, QWidget, QPushButton)
from calibre.gui2.tweak_book.widgets import Dialog
from calibre.spell.dictionary import (
builtin_dictionaries, custom_dictionaries, best_locale_for_language,
get_dictionary, DictionaryLocale, dprefs)
from calibre.utils.localization import calibre_langcode_to_name
from calibre.utils.icu import sort_key
LANG = 0
COUNTRY = 1
DICTIONARY = 2
_country_map = None
def country_map():
global _country_map
if _country_map is None:
_country_map = cPickle.loads(P('localization/iso3166.pickle', data=True, allow_user_override=False))
return _country_map
class ManageDictionaries(Dialog):
def __init__(self, parent=None):
Dialog.__init__(self, _('Manage dictionaries'), 'manage-dictionaries', parent=parent)
def sizeHint(self):
ans = Dialog.sizeHint(self)
ans.setWidth(ans.width() + 250)
ans.setHeight(ans.height() + 200)
return ans
def setup_ui(self):
self.l = l = QGridLayout(self)
self.setLayout(l)
self.stack = s = QStackedLayout()
self.helpl = la = QLabel('<p>')
la.setWordWrap(True)
self.pcb = pc = QPushButton(self)
pc.clicked.connect(self.set_preferred_country)
self.lw = w = QWidget(self)
self.ll = ll = QVBoxLayout(w)
ll.addWidget(pc)
self.dw = w = QWidget(self)
self.dl = dl = QVBoxLayout(w)
self.fb = b = QPushButton(self)
b.clicked.connect(self.set_favorite)
self.remove_dictionary = rd = QPushButton(_('&Remove this dictionary'), w)
dl.addWidget(b), dl.addWidget(rd)
w.setLayout(dl)
s.addWidget(la)
s.addWidget(self.lw)
s.addWidget(w)
self.dictionaries = d = QTreeWidget(self)
self.build_dictionaries()
d.setCurrentIndex(d.model().index(0, 0))
d.header().close()
d.currentItemChanged.connect(self.current_item_changed)
self.current_item_changed()
l.addWidget(d)
l.addLayout(s, 0, 1)
self.bb.clear()
self.bb.addButton(self.bb.Close)
l.addWidget(self.bb, l.rowCount(), 0, 1, l.columnCount())
def build_dictionaries(self):
all_dictionaries = builtin_dictionaries() | custom_dictionaries()
languages = defaultdict(lambda : defaultdict(set))
for d in all_dictionaries:
for locale in d.locales | {d.primary_locale}:
languages[locale.langcode][locale.countrycode].add(d)
bf = QFont(self.dictionaries.font())
bf.setBold(True)
itf = QFont(self.dictionaries.font())
itf.setItalic(True)
for lc in sorted(languages, key=lambda x:sort_key(calibre_langcode_to_name(x))):
i = QTreeWidgetItem(self.dictionaries, LANG)
i.setText(0, calibre_langcode_to_name(lc))
i.setData(0, Qt.UserRole, lc)
best_country = getattr(best_locale_for_language(lc), 'countrycode', None)
for countrycode in sorted(languages[lc], key=lambda x: country_map()['names'].get(x, x)):
j = QTreeWidgetItem(i, COUNTRY)
j.setText(0, country_map()['names'].get(countrycode, countrycode))
j.setData(0, Qt.UserRole, countrycode)
if countrycode == best_country:
j.setData(0, Qt.FontRole, bf)
pd = get_dictionary(DictionaryLocale(lc, countrycode))
for dictionary in sorted(languages[lc][countrycode], key=lambda d:d.name):
k = QTreeWidgetItem(j, DICTIONARY)
pl = calibre_langcode_to_name(d.primary_locale.langcode)
if d.primary_locale.countrycode:
pl += '-' + d.primary_locale.countrycode.upper()
k.setText(0, d.name or (_('<Builtin dictionary for {0}>').format(pl)))
k.setData(0, Qt.UserRole, d)
if pd == d:
k.setData(0, Qt.FontRole, itf)
self.dictionaries.expandAll()
def current_item_changed(self):
item = self.dictionaries.currentItem()
if item is not None:
self.stack.setCurrentIndex(item.type())
if item.type() == LANG:
self.init_language(item)
elif item.type() == COUNTRY:
self.init_country(item)
elif item.type() == DICTIONARY:
self.init_dictionary(item)
def init_language(self, item):
self.helpl.setText(_(
'''<p>You can change the dictionaries used for any specified language.</p>
<p>A language can have many country specific variants. Each of these variants
can have one or more dictionaries assigned to it. The default variant for each language
is shown in bold to the left.</p>
<p>You can change the default country variant as well as changing the dictionaries used for
every variant.</p>
<p>When a book specifies its language as a plain language, without any country variant,
the default variant you choose here will be used.</p>
'''))
def init_country(self, item):
pc = self.pcb
font = item.data(0, Qt.FontRole).toPyObject()
preferred = bool(font and font.bold())
pc.setText((_(
'This is already the preferred variant for the {1} language') if preferred else _(
'Use this as the preferred variant for the {1} language')).format(
unicode(item.text(0)), unicode(item.parent().text(0))))
pc.setEnabled(not preferred)
def set_preferred_country(self):
item = self.dictionaries.currentItem()
bf = QFont(self.dictionaries.font())
bf.setBold(True)
for x in (item.parent().child(i) for i in xrange(item.parent().childCount())):
x.setData(0, Qt.FontRole, bf if x is item else QVariant())
lc = unicode(item.parent().data(0, Qt.UserRole).toPyObject())
pl = dprefs['preferred_locales']
pl[lc] = '%s-%s' % (lc, unicode(item.data(0, Qt.UserRole).toPyObject()))
dprefs['preferred_locales'] = pl
def init_dictionary(self, item):
saf = self.fb
font = item.data(0, Qt.FontRole).toPyObject()
preferred = bool(font and font.italic())
saf.setText((_(
'This is already the preferred dictionary') if preferred else
_('Use this as the preferred dictionary')))
saf.setEnabled(not preferred)
self.remove_dictionary.setEnabled(not item.data(0, Qt.UserRole).toPyObject().builtin)
def set_favorite(self):
item = self.dictionaries.currentItem()
bf = QFont(self.dictionaries.font())
bf.setItalic(True)
for x in (item.parent().child(i) for i in xrange(item.parent().childCount())):
x.setData(0, Qt.FontRole, bf if x is item else QVariant())
cc = unicode(item.parent().data(0, Qt.UserRole).toPyObject())
lc = unicode(item.parent().parent().data(0, Qt.UserRole).toPyObject())
d = item.data(0, Qt.UserRole).toPyObject()
locale = '%s-%s' % (lc, cc)
pl = dprefs['preferred_dictionaries']
pl[locale] = d.name
dprefs['preferred_dictionaries'] = pl
if __name__ == '__main__':
app = QApplication([]) # noqa
d = ManageDictionaries()
d.exec_()

View File

@ -82,8 +82,16 @@ def custom_dictionaries(reread=False):
default_preferred_locales = {'eng':'en-US', 'deu':'de-DE', 'spa':'es-ES', 'fra':'fr-FR'}
def best_locale_for_language(langcode):
best_locale = dprefs['preferred_locales'].get(langcode, default_preferred_locales.get(langcode, None))
if best_locale is not None:
return parse_lang_code(best_locale)
def preferred_dictionary(locale):
return {parse_lang_code(k):v for k, v in dprefs['preferred_dictionaries']}.get(locale, None)
def get_dictionary(locale, exact_match=False):
preferred = {parse_lang_code(k):v for k, v in dprefs['preferred_dictionaries']}.get(locale, None)
preferred = preferred_dictionary(locale)
# First find all dictionaries that match locale exactly
exact_matches = {}
for collection in (custom_dictionaries(), builtin_dictionaries()):
@ -110,9 +118,9 @@ def get_dictionary(locale, exact_match=False):
# No dictionary matched the locale exactly, we will now fallback to
# matching only on language. First see if a dictionary matching the
# preferred locale for the language exists.
best_locale = dprefs['preferred_locales'].get(locale.langcode, default_preferred_locales.get(locale.langcode, None))
best_locale = best_locale_for_language(locale.langcode)
if best_locale is not None:
ans = get_dictionary(parse_lang_code(best_locale), exact_match=True)
ans = get_dictionary(best_locale, exact_match=True)
if ans is not None:
return ans