mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Add/remove for dictionaries from OpenOffice extensions works
This commit is contained in:
parent
b060f55d5f
commit
40204e0d3a
@ -19,7 +19,8 @@ from calibre.gui2 import choose_files, error_dialog
|
||||
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)
|
||||
get_dictionary, DictionaryLocale, dprefs, remove_dictionary)
|
||||
from calibre.spell.import_from import import_from_oxt
|
||||
from calibre.utils.localization import calibre_langcode_to_name
|
||||
from calibre.utils.icu import sort_key
|
||||
|
||||
@ -35,7 +36,7 @@ def country_map():
|
||||
_country_map = cPickle.loads(P('localization/iso3166.pickle', data=True, allow_user_override=False))
|
||||
return _country_map
|
||||
|
||||
class AddDictionary(QDialog):
|
||||
class AddDictionary(QDialog): # {{{
|
||||
|
||||
def __init__(self, parent=None):
|
||||
QDialog.__init__(self, parent)
|
||||
@ -79,7 +80,7 @@ class AddDictionary(QDialog):
|
||||
|
||||
def choose_file(self):
|
||||
path = choose_files(self, 'choose-dict-for-import', _('Choose OXT Dictionary'), filters=[
|
||||
(_('Dictionaries', ['oxt']))], all_files=False, select_only_single_file=True)
|
||||
(_('Dictionaries'), ['oxt'])], all_files=False, select_only_single_file=True)
|
||||
if path is not None:
|
||||
self.path.setText(path[0])
|
||||
if not self.nickname:
|
||||
@ -98,7 +99,17 @@ class AddDictionary(QDialog):
|
||||
if nick in {d.name for d in custom_dictionaries()}:
|
||||
return error_dialog(self, _('Nickname already used'), _(
|
||||
'A dictionary with the nick name "%s" already exists.'), show=True)
|
||||
oxt = unicode(self.path.text())
|
||||
try:
|
||||
num = import_from_oxt(oxt, nick)
|
||||
except:
|
||||
return error_dialog(self, _('Failed to import dictionaries'), _(
|
||||
'Failed to import dictionaries from %s. Click "Show Details" for more information') % oxt, show=True)
|
||||
if num == 0:
|
||||
return error_dialog(self, _('No dictionaries'), _(
|
||||
'No dictionaries were found in %s') % oxt, show=True)
|
||||
QDialog.accept(self)
|
||||
# }}}
|
||||
|
||||
class ManageDictionaries(Dialog):
|
||||
|
||||
@ -126,7 +137,8 @@ class ManageDictionaries(Dialog):
|
||||
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)
|
||||
self.remove_dictionary_button = rd = QPushButton(_('&Remove this dictionary'), w)
|
||||
rd.clicked.connect(self.remove_dictionary)
|
||||
dl.addWidget(b), dl.addWidget(rd)
|
||||
w.setLayout(dl)
|
||||
s.addWidget(la)
|
||||
@ -149,8 +161,8 @@ class ManageDictionaries(Dialog):
|
||||
b.clicked.connect(self.add_dictionary)
|
||||
l.addWidget(self.bb, l.rowCount(), 0, 1, l.columnCount())
|
||||
|
||||
def build_dictionaries(self):
|
||||
all_dictionaries = builtin_dictionaries() | custom_dictionaries()
|
||||
def build_dictionaries(self, reread=False):
|
||||
all_dictionaries = builtin_dictionaries() | custom_dictionaries(reread=reread)
|
||||
languages = defaultdict(lambda : defaultdict(set))
|
||||
for d in all_dictionaries:
|
||||
for locale in d.locales | {d.primary_locale}:
|
||||
@ -159,6 +171,7 @@ class ManageDictionaries(Dialog):
|
||||
bf.setBold(True)
|
||||
itf = QFont(self.dictionaries.font())
|
||||
itf.setItalic(True)
|
||||
self.dictionaries.clear()
|
||||
|
||||
for lc in sorted(languages, key=lambda x:sort_key(calibre_langcode_to_name(x))):
|
||||
i = QTreeWidgetItem(self.dictionaries, LANG)
|
||||
@ -174,12 +187,12 @@ class ManageDictionaries(Dialog):
|
||||
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:
|
||||
pl = calibre_langcode_to_name(dictionary.primary_locale.langcode)
|
||||
if dictionary.primary_locale.countrycode:
|
||||
pl += '-' + dictionary.primary_locale.countrycode.upper()
|
||||
k.setText(0, dictionary.name or (_('<Builtin dictionary for {0}>').format(pl)))
|
||||
k.setData(0, Qt.UserRole, dictionary)
|
||||
if pd == dictionary:
|
||||
k.setData(0, Qt.FontRole, itf)
|
||||
|
||||
self.dictionaries.expandAll()
|
||||
@ -187,8 +200,15 @@ class ManageDictionaries(Dialog):
|
||||
def add_dictionary(self):
|
||||
d = AddDictionary(self)
|
||||
if d.exec_() == d.Accepted:
|
||||
path = unicode(d.path.text())
|
||||
print (path)
|
||||
self.build_dictionaries(reread=True)
|
||||
|
||||
def remove_dictionary(self):
|
||||
item = self.dictionaries.currentItem()
|
||||
if item is not None and item.type() == DICTIONARY:
|
||||
dic = item.data(0, Qt.UserRole).toPyObject()
|
||||
if not dic.builtin:
|
||||
remove_dictionary(dic)
|
||||
self.build_dictionaries(reread=True)
|
||||
|
||||
def current_item_changed(self):
|
||||
item = self.dictionaries.currentItem()
|
||||
@ -242,7 +262,7 @@ class ManageDictionaries(Dialog):
|
||||
'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)
|
||||
self.remove_dictionary_button.setEnabled(not item.data(0, Qt.UserRole).toPyObject().builtin)
|
||||
|
||||
def set_favorite(self):
|
||||
item = self.dictionaries.currentItem()
|
||||
@ -255,7 +275,7 @@ class ManageDictionaries(Dialog):
|
||||
d = item.data(0, Qt.UserRole).toPyObject()
|
||||
locale = '%s-%s' % (lc, cc)
|
||||
pl = dprefs['preferred_dictionaries']
|
||||
pl[locale] = d.name
|
||||
pl[locale] = d.id
|
||||
dprefs['preferred_dictionaries'] = pl
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
@ -6,7 +6,7 @@ from __future__ import (unicode_literals, division, absolute_import,
|
||||
__license__ = 'GPL v3'
|
||||
__copyright__ = '2014, Kovid Goyal <kovid at kovidgoyal.net>'
|
||||
|
||||
import cPickle, os, glob
|
||||
import cPickle, os, glob, shutil
|
||||
from collections import namedtuple
|
||||
from operator import attrgetter
|
||||
|
||||
@ -15,8 +15,8 @@ from calibre.utils.config import JSONConfig
|
||||
from calibre.utils.localization import get_lang, canonicalize_lang
|
||||
|
||||
DictionaryLocale = namedtuple('DictionaryLocale', 'langcode countrycode')
|
||||
Dictionary = namedtuple('Dictionary', 'primary_locale locales dicpath affpath builtin name')
|
||||
LoadedDictionary = namedtuple('Dictionary', 'primary_locale locales obj builtin name')
|
||||
Dictionary = namedtuple('Dictionary', 'primary_locale locales dicpath affpath builtin name id')
|
||||
LoadedDictionary = namedtuple('Dictionary', 'primary_locale locales obj builtin name id')
|
||||
hunspell = plugins['hunspell'][0]
|
||||
if hunspell is None:
|
||||
raise RuntimeError('Failed to load hunspell: %s' % plugins[1])
|
||||
@ -60,15 +60,13 @@ def builtin_dictionaries():
|
||||
base = os.path.dirname(lc)
|
||||
dics.append(Dictionary(
|
||||
parse_lang_code(locale), frozenset(map(parse_lang_code, locales)), os.path.join(base, '%s.dic' % locale),
|
||||
os.path.join(base, '%s.aff' % locale), True, None))
|
||||
os.path.join(base, '%s.aff' % locale), True, None, None))
|
||||
_builtins = frozenset(dics)
|
||||
return _builtins
|
||||
|
||||
def custom_dictionaries(reread=False):
|
||||
global _custom
|
||||
if reread:
|
||||
_custom = None
|
||||
if _custom is None:
|
||||
if _custom is None or reread:
|
||||
dics = []
|
||||
for lc in glob.glob(os.path.join(config_dir, 'dictionaries', '*/locales')):
|
||||
locales = filter(None, open(lc, 'rb').read().decode('utf-8').splitlines())
|
||||
@ -76,7 +74,7 @@ def custom_dictionaries(reread=False):
|
||||
base = os.path.dirname(lc)
|
||||
dics.append(Dictionary(
|
||||
parse_lang_code(locale), frozenset(map(parse_lang_code, locales)), os.path.join(base, '%s.dic' % locale),
|
||||
os.path.join(base, '%s.aff' % locale), False, name))
|
||||
os.path.join(base, '%s.aff' % locale), False, name, os.path.basename(base)))
|
||||
_custom = frozenset(dics)
|
||||
return _custom
|
||||
|
||||
@ -88,7 +86,14 @@ def best_locale_for_language(langcode):
|
||||
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)
|
||||
return {parse_lang_code(k):v for k, v in dprefs['preferred_dictionaries'].iteritems()}.get(locale, None)
|
||||
|
||||
def remove_dictionary(dictionary):
|
||||
if dictionary.builtin:
|
||||
raise ValueError('Cannot remove builtin dictionaries')
|
||||
base = os.path.dirname(dictionary.dicpath)
|
||||
shutil.rmtree(base)
|
||||
dprefs['preferred_dictionaries'] = {k:v for k, v in dprefs['preferred_dictionaries'].iteritems() if v != dictionary.id}
|
||||
|
||||
def get_dictionary(locale, exact_match=False):
|
||||
preferred = preferred_dictionary(locale)
|
||||
@ -97,11 +102,11 @@ def get_dictionary(locale, exact_match=False):
|
||||
for collection in (custom_dictionaries(), builtin_dictionaries()):
|
||||
for d in collection:
|
||||
if d.primary_locale == locale:
|
||||
exact_matches[d.name] = d
|
||||
exact_matches[d.id] = d
|
||||
for d in collection:
|
||||
for q in d.locales:
|
||||
if q == locale and d.name not in exact_matches:
|
||||
exact_matches[d.name] = d
|
||||
if q == locale and d.id not in exact_matches:
|
||||
exact_matches[d.id] = d
|
||||
|
||||
# If the user has specified a preferred dictionary for this locale, use it,
|
||||
# otherwise, if a builtin dictionary exists, use that
|
||||
@ -134,7 +139,7 @@ def get_dictionary(locale, exact_match=False):
|
||||
def load_dictionary(dictionary):
|
||||
with open(dictionary.dicpath, 'rb') as dic, open(dictionary.affpath, 'rb') as aff:
|
||||
obj = hunspell.Dictionary(dic.read(), aff.read())
|
||||
return LoadedDictionary(dictionary.primary_locale, dictionary.locales, obj, dictionary.builtin, dictionary.name)
|
||||
return LoadedDictionary(dictionary.primary_locale, dictionary.locales, obj, dictionary.builtin, dictionary.name, dictionary.id)
|
||||
|
||||
class Dictionaries(object):
|
||||
|
||||
|
@ -6,10 +6,11 @@ from __future__ import (unicode_literals, division, absolute_import,
|
||||
__license__ = 'GPL v3'
|
||||
__copyright__ = '2014, Kovid Goyal <kovid at kovidgoyal.net>'
|
||||
|
||||
import sys, glob, os, shutil
|
||||
import sys, glob, os, shutil, tempfile
|
||||
|
||||
from lxml import etree
|
||||
|
||||
from calibre.constants import config_dir
|
||||
from calibre.utils.zipfile import ZipFile
|
||||
|
||||
NS_MAP = {
|
||||
@ -60,13 +61,25 @@ def import_from_libreoffice_source_tree(source_path):
|
||||
if want_locales:
|
||||
raise Exception('Failed to find dictionaries for some wanted locales: %s' % want_locales)
|
||||
|
||||
def import_from_oxt(source_path):
|
||||
def import_from_oxt(source_path, name, dest_dir=None, prefix='dic-'):
|
||||
dest_dir = dest_dir or os.path.join(config_dir, 'dictionaries')
|
||||
num = 0
|
||||
with ZipFile(source_path) as zf:
|
||||
root = etree.fromstring(zf.open('META-INF/manifest.xml').read())
|
||||
xcu = XPath('//manifest:file-entry[@manifest:media-type="application/vnd.sun.star.configuration-data"]')(root)[0].get(
|
||||
'{%s}full-path' % NS_MAP['manifest'])
|
||||
dictionaries = {(dic.lstrip('/'), aff.lstrip('/')):locales for (dic, aff), locales in parse_xcu(zf.open(xcu).read(), origin='').iteritems()}
|
||||
return dictionaries
|
||||
for (dic, aff), locales in parse_xcu(zf.open(xcu).read(), origin='').iteritems():
|
||||
dic, aff = dic.lstrip('/'), aff.lstrip('/')
|
||||
d = tempfile.mkdtemp(prefix=prefix, dir=dest_dir)
|
||||
metadata = [name] + locales
|
||||
with open(os.path.join(d, 'locales'), 'wb') as f:
|
||||
f.write(('\n'.join(metadata)).encode('utf-8'))
|
||||
with open(os.path.join(d, '%s.dic' % locales[0]), 'wb') as f:
|
||||
shutil.copyfileobj(zf.open(dic), f)
|
||||
with open(os.path.join(d, '%s.aff' % locales[0]), 'wb') as f:
|
||||
shutil.copyfileobj(zf.open(aff), f)
|
||||
num += 1
|
||||
return num
|
||||
|
||||
if __name__ == '__main__':
|
||||
import_from_libreoffice_source_tree(sys.argv[-1])
|
||||
|
Loading…
x
Reference in New Issue
Block a user