From b060f55d5f75b08b3d69faf20fe4a82fcb8a2d1d Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Sun, 6 Apr 2014 09:10:57 +0530 Subject: [PATCH] Start work on adding dictionaries --- src/calibre/gui2/tweak_book/spell.py | 77 ++++++++++++++++++++++++++-- src/calibre/spell/import_from.py | 11 ++++ 2 files changed, 85 insertions(+), 3 deletions(-) diff --git a/src/calibre/gui2/tweak_book/spell.py b/src/calibre/gui2/tweak_book/spell.py index 4ce20ab935..782c75ffaa 100644 --- a/src/calibre/gui2/tweak_book/spell.py +++ b/src/calibre/gui2/tweak_book/spell.py @@ -6,13 +6,16 @@ from __future__ import (unicode_literals, division, absolute_import, __license__ = 'GPL v3' __copyright__ = '2014, Kovid Goyal ' -import cPickle +import cPickle, os from collections import defaultdict from PyQt4.Qt import ( QGridLayout, QApplication, QTreeWidget, QTreeWidgetItem, Qt, QFont, - QStackedLayout, QLabel, QVBoxLayout, QVariant, QWidget, QPushButton, QIcon) + QStackedLayout, QLabel, QVBoxLayout, QVariant, QWidget, QPushButton, QIcon, + QDialogButtonBox, QLineEdit, QDialog, QToolButton, QFormLayout, QHBoxLayout) +from calibre.constants import __appname__ +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, @@ -32,6 +35,71 @@ def country_map(): _country_map = cPickle.loads(P('localization/iso3166.pickle', data=True, allow_user_override=False)) return _country_map +class AddDictionary(QDialog): + + def __init__(self, parent=None): + QDialog.__init__(self, parent) + self.setWindowTitle(_('Add a dictionary')) + self.l = l = QFormLayout(self) + self.setLayout(l) + + self.la = la = QLabel('

' + _( + '''{0} supports the use of OpenOffice dictionaries for spell checking. You can + download more dictionaries from the OpenOffice extensions repository. + The dictionary will download as an .oxt file. Simply specify the path to the + downloaded .oxt file here to add the dictionary to {0}.'''.format( + __appname__, 'http://extensions.openoffice.org'))+'

') + la.setWordWrap(True) + la.setOpenExternalLinks(True) + la.setMinimumWidth(450) + l.addRow(la) + + self.h = h = QHBoxLayout() + self.path = p = QLineEdit(self) + p.setPlaceholderText(_('Path to OXT file')) + h.addWidget(p) + + self.b = b = QToolButton(self) + b.setIcon(QIcon(I('document_open.png'))) + b.setToolTip(_('Browse for an OXT file')) + b.clicked.connect(self.choose_file) + h.addWidget(b) + l.addRow(_('&Path to OXT file:'), h) + l.labelForField(h).setBuddy(p) + + self.nick = n = QLineEdit(self) + n.setPlaceholderText(_('Choose a nickname for this dictionary')) + l.addRow(_('&Nickname:'), n) + + self.bb = bb = QDialogButtonBox(QDialogButtonBox.Ok|QDialogButtonBox.Cancel) + bb.accepted.connect(self.accept) + bb.rejected.connect(self.reject) + l.addRow(bb) + b.setFocus(Qt.OtherFocusReason) + + 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) + if path is not None: + self.path.setText(path[0]) + if not self.nickname: + n = os.path.basename(path[0]) + self.nick.setText(n.rpartition('.')[0]) + + @property + def nickname(self): + return unicode(self.nick.text()).strip() + + def accept(self): + nick = self.nickname + if not nick: + return error_dialog(self, _('Must specify nickname'), _( + 'You must specify a nickname for this dictionary'), show=True) + 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) + QDialog.accept(self) + class ManageDictionaries(Dialog): def __init__(self, parent=None): @@ -117,7 +185,10 @@ class ManageDictionaries(Dialog): self.dictionaries.expandAll() def add_dictionary(self): - pass + d = AddDictionary(self) + if d.exec_() == d.Accepted: + path = unicode(d.path.text()) + print (path) def current_item_changed(self): item = self.dictionaries.currentItem() diff --git a/src/calibre/spell/import_from.py b/src/calibre/spell/import_from.py index 292aa3a9e2..49c9dcc901 100644 --- a/src/calibre/spell/import_from.py +++ b/src/calibre/spell/import_from.py @@ -10,9 +10,12 @@ import sys, glob, os, shutil from lxml import etree +from calibre.utils.zipfile import ZipFile + NS_MAP = { 'oor': "http://openoffice.org/2001/registry", 'xs': "http://www.w3.org/2001/XMLSchema", + 'manifest': 'http://openoffice.org/2001/manifest', } XPath = lambda x: etree.XPath(x, namespaces=NS_MAP) @@ -57,5 +60,13 @@ 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): + 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 + if __name__ == '__main__': import_from_libreoffice_source_tree(sys.argv[-1])