Refactor SpellChecker
- use Gspell instead of GtkSpell, it seems to have alot less problems and needs less code
This commit is contained in:
parent
f75dd8bcad
commit
7692b376ee
|
@ -18,7 +18,7 @@
|
|||
- python3-crypto to enable End to end encryption
|
||||
- python3-gnupg to enable GPG encryption
|
||||
- For zeroconf (bonjour) you need dbus-glib, python-avahi
|
||||
- gir1.2-gtkspell3-3.0 and aspell-LANG where lang is your locale eg. en, fr etc
|
||||
- gir1.2-gspell-1 and hunspell-LANG where lang is your locale eg. en, fr etc
|
||||
- gir1.2-secret-1 for GNOME Keyring or KDE support as password storage
|
||||
- D-Bus running to have gajim-remote working. Some distributions split dbus-x11, which is needed for dbus to work with Gajim. Version >= 0.80 is required.
|
||||
- python3-dbus bindings (>=1.2.0)
|
||||
|
|
|
@ -1173,7 +1173,6 @@ class ChatControl(ChatControlBase):
|
|||
self.handlers[i].disconnect(i)
|
||||
del self.handlers[i]
|
||||
self.conv_textview.del_handlers()
|
||||
self.remove_speller()
|
||||
self.msg_textview.destroy()
|
||||
# PluginSystem: calling shutdown of super class (ChatControlBase) to let
|
||||
# it remove it's GUI extension points
|
||||
|
|
|
@ -32,7 +32,6 @@ import time
|
|||
from gi.repository import Gtk
|
||||
from gi.repository import Gdk
|
||||
from gi.repository import Pango
|
||||
from gi.repository import GObject
|
||||
from gi.repository import GLib
|
||||
from gi.repository import Gio
|
||||
|
||||
|
@ -42,7 +41,6 @@ from gajim import message_control
|
|||
from gajim import dialogs
|
||||
from gajim import history_window
|
||||
from gajim import notify
|
||||
from gajim import gtkspell
|
||||
import re
|
||||
|
||||
from gajim import emoticons
|
||||
|
@ -66,6 +64,9 @@ from gajim.command_system.implementation.middleware import CommandTools
|
|||
from gajim.command_system.implementation import standard
|
||||
from gajim.command_system.implementation import execute
|
||||
|
||||
if app.HAVE_SPELL:
|
||||
from gi.repository import Gspell
|
||||
|
||||
|
||||
################################################################################
|
||||
class ChatControlBase(MessageControl, ChatCommandProcessor, CommandTools):
|
||||
|
@ -345,8 +346,7 @@ class ChatControlBase(MessageControl, ChatCommandProcessor, CommandTools):
|
|||
self.set_emoticon_popover()
|
||||
|
||||
# Attach speller
|
||||
self.spell = None
|
||||
self.spell_handlers = []
|
||||
self.spell_checker = None
|
||||
self.set_speller()
|
||||
self.conv_textview.tv.show()
|
||||
|
||||
|
@ -471,44 +471,22 @@ class ChatControlBase(MessageControl, ChatCommandProcessor, CommandTools):
|
|||
image.set_from_pixbuf(icon)
|
||||
|
||||
def set_speller(self):
|
||||
if not gtkspell.HAS_GTK_SPELL or not app.config.get('use_speller'):
|
||||
if not app.HAVE_SPELL or not app.config.get('use_speller'):
|
||||
return
|
||||
|
||||
def _on_focus_in(*args):
|
||||
if self.spell is None:
|
||||
return
|
||||
self.spell.attach(self.msg_textview)
|
||||
|
||||
def _on_focus_out(*args):
|
||||
if self.spell is None:
|
||||
return
|
||||
if not self.msg_textview.has_text():
|
||||
self.spell.detach()
|
||||
|
||||
lang = self.get_speller_language()
|
||||
if not lang:
|
||||
gspell_lang = self.get_speller_language()
|
||||
if gspell_lang is None:
|
||||
return
|
||||
try:
|
||||
self.spell = gtkspell.Spell(self.msg_textview, lang)
|
||||
self.spell.connect('language_changed', self.on_language_changed)
|
||||
handler_id = self.msg_textview.connect('focus-in-event',
|
||||
_on_focus_in)
|
||||
self.spell_handlers.append(handler_id)
|
||||
handler_id = self.msg_textview.connect('focus-out-event',
|
||||
_on_focus_out)
|
||||
self.spell_handlers.append(handler_id)
|
||||
except OSError:
|
||||
dialogs.AspellDictError(lang)
|
||||
app.config.set('use_speller', False)
|
||||
|
||||
def remove_speller(self):
|
||||
if self.spell is None:
|
||||
return
|
||||
self.spell.detach()
|
||||
for id_ in self.spell_handlers:
|
||||
self.msg_textview.disconnect(id_)
|
||||
self.spell_handlers.remove(id_)
|
||||
self.spell = None
|
||||
self.spell_checker = Gspell.Checker.new(gspell_lang)
|
||||
spell_buffer = Gspell.TextBuffer.get_from_gtk_text_buffer(
|
||||
self.msg_textview.get_buffer())
|
||||
spell_buffer.set_spell_checker(self.spell_checker)
|
||||
spell_view = Gspell.TextView.get_from_gtk_text_view(self.msg_textview)
|
||||
spell_view.set_inline_spell_checking(False)
|
||||
spell_view.set_enable_language_menu(True)
|
||||
|
||||
self.spell_checker.connect('notify::language', self.on_language_changed)
|
||||
|
||||
def get_speller_language(self):
|
||||
per_type = 'contacts'
|
||||
|
@ -521,16 +499,20 @@ class ChatControlBase(MessageControl, ChatCommandProcessor, CommandTools):
|
|||
lang = app.config.get('speller_language')
|
||||
if not lang:
|
||||
lang = app.LANG
|
||||
return lang or None
|
||||
gspell_lang = Gspell.language_lookup(lang)
|
||||
if gspell_lang is None:
|
||||
gspell_lang = Gspell.language_get_default()
|
||||
return gspell_lang
|
||||
|
||||
def on_language_changed(self, spell, lang):
|
||||
def on_language_changed(self, checker, param):
|
||||
gspell_lang = checker.get_language()
|
||||
per_type = 'contacts'
|
||||
if self.type_id == message_control.TYPE_GC:
|
||||
per_type = 'rooms'
|
||||
if not app.config.get_per(per_type, self.contact.jid):
|
||||
app.config.add_per(per_type, self.contact.jid)
|
||||
app.config.set_per(
|
||||
per_type, self.contact.jid, 'speller_language', lang)
|
||||
app.config.set_per(per_type, self.contact.jid,
|
||||
'speller_language', gspell_lang.get_code())
|
||||
|
||||
def on_banner_label_populate_popup(self, label, menu):
|
||||
"""
|
||||
|
|
|
@ -253,6 +253,21 @@ except Exception:
|
|||
glog.info(_('Unable to load idle module'))
|
||||
HAVE_IDLE = False
|
||||
|
||||
HAVE_SPELL = False
|
||||
try:
|
||||
spell_log = logging.getLogger('gajim.speller')
|
||||
gi.require_version('Gspell', '1')
|
||||
from gi.repository import Gspell
|
||||
langs = Gspell.language_get_available()
|
||||
for lang in langs:
|
||||
spell_log.info('%s (%s) dict available',
|
||||
lang.get_name(), lang.get_code())
|
||||
if langs:
|
||||
HAVE_SPELL = True
|
||||
else:
|
||||
spell_log.info('No dicts available')
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
gajim_identity = {'type': 'pc', 'category': 'client', 'name': 'Gajim'}
|
||||
gajim_common_features = [nbxmpp.NS_BYTESTREAM, nbxmpp.NS_SI, nbxmpp.NS_FILE,
|
||||
|
|
|
@ -50,7 +50,6 @@ from gajim import message_control
|
|||
from gajim.chat_control_base import ChatControlBase
|
||||
from gajim import dataforms_widget
|
||||
from gajim import gui_menu_builder
|
||||
from gajim import gtkspell
|
||||
|
||||
from gajim.common import helpers
|
||||
from gajim.common import app
|
||||
|
@ -66,6 +65,9 @@ try:
|
|||
except (ImportError, ValueError):
|
||||
HAS_GST = False
|
||||
|
||||
if app.HAVE_SPELL:
|
||||
from gi.repository import Gspell
|
||||
|
||||
#---------- PreferencesWindow class -------------#
|
||||
class PreferencesWindow:
|
||||
"""
|
||||
|
@ -187,7 +189,7 @@ class PreferencesWindow:
|
|||
self.xml.get_object('xhtml_checkbutton').set_active(st)
|
||||
|
||||
# use speller
|
||||
if gtkspell.HAS_GTK_SPELL:
|
||||
if app.HAVE_SPELL:
|
||||
st = app.config.get('use_speller')
|
||||
self.xml.get_object('speller_checkbutton').set_active(st)
|
||||
else:
|
||||
|
@ -657,30 +659,22 @@ class PreferencesWindow:
|
|||
if isinstance(ctrl, ChatControlBase):
|
||||
ctrl.set_speller()
|
||||
|
||||
def remove_speller(self):
|
||||
for ctrl in self._get_all_controls():
|
||||
if isinstance(ctrl, ChatControlBase):
|
||||
if ctrl.spell is not None:
|
||||
ctrl.remove_speller()
|
||||
|
||||
def on_speller_checkbutton_toggled(self, widget):
|
||||
active = widget.get_active()
|
||||
app.config.set('use_speller', active)
|
||||
if active:
|
||||
lang = app.config.get('speller_language')
|
||||
if not lang:
|
||||
lang = app.LANG
|
||||
|
||||
available = gtkspell.test_language(lang)
|
||||
if not available:
|
||||
dialogs.AspellDictError(lang)
|
||||
app.config.set('use_speller', False)
|
||||
widget.set_active(False)
|
||||
else:
|
||||
app.config.set('speller_language', lang)
|
||||
self.apply_speller()
|
||||
if not active:
|
||||
return
|
||||
lang = app.config.get('speller_language')
|
||||
gspell_lang = Gspell.language_lookup(lang)
|
||||
if gspell_lang is None:
|
||||
gspell_lang = Gspell.language_get_default()
|
||||
if gspell_lang is None:
|
||||
dialogs.AspellDictError(lang)
|
||||
app.config.set('use_speller', False)
|
||||
widget.set_active(False)
|
||||
else:
|
||||
self.remove_speller()
|
||||
app.config.set('speller_language', gspell_lang.get_code())
|
||||
self.apply_speller()
|
||||
|
||||
def on_positive_184_ack_checkbutton_toggled(self, widget):
|
||||
self.on_checkbutton_toggled(widget, 'positive_184_ack')
|
||||
|
|
|
@ -34,6 +34,7 @@ from gi.repository import Gdk
|
|||
from gi.repository import GdkPixbuf
|
||||
from gi.repository import GObject
|
||||
from gi.repository import GLib
|
||||
|
||||
import os
|
||||
import nbxmpp
|
||||
import time
|
||||
|
@ -42,7 +43,6 @@ from gajim import gtkgui_helpers
|
|||
from gajim import vcard
|
||||
from gajim import conversation_textview
|
||||
from gajim import dataforms_widget
|
||||
from gajim import gtkspell
|
||||
|
||||
from random import randrange
|
||||
from gajim.common import pep
|
||||
|
@ -64,6 +64,9 @@ from gajim.common import dataforms
|
|||
from gajim.common.exceptions import GajimGeneralException
|
||||
from gajim.common.connection_handlers_events import MessageOutgoingEvent
|
||||
|
||||
if app.HAVE_SPELL:
|
||||
from gi.repository import Gspell
|
||||
|
||||
import logging
|
||||
log = logging.getLogger('gajim.dialogs')
|
||||
|
||||
|
@ -3077,15 +3080,19 @@ class SingleMessageWindow:
|
|||
else:
|
||||
self.to_entry.set_text(to)
|
||||
|
||||
if app.config.get('use_speller') and gtkspell.HAS_GTK_SPELL and action == 'send':
|
||||
try:
|
||||
lang = app.config.get('speller_language')
|
||||
if not lang:
|
||||
lang = app.LANG
|
||||
self.spell = gtkspell.Spell(self.message_textview, lang)
|
||||
self.spell.attach(self.message_textview)
|
||||
except OSError:
|
||||
if app.config.get('use_speller') and app.HAVE_SPELL and action == 'send':
|
||||
lang = app.config.get('speller_language')
|
||||
gspell_lang = Gspell.language_lookup(lang)
|
||||
if gspell_lang is None:
|
||||
AspellDictError(lang)
|
||||
else:
|
||||
spell_buffer = Gspell.TextBuffer.get_from_gtk_text_buffer(
|
||||
self.message_textview.get_buffer())
|
||||
spell_buffer.set_spell_checker(Gspell.Checker.new(gspell_lang))
|
||||
spell_view = Gspell.TextView.get_from_gtk_text_view(
|
||||
self.message_textview)
|
||||
spell_view.set_inline_spell_checking(True)
|
||||
spell_view.set_enable_language_menu(True)
|
||||
|
||||
self.prepare_widgets_for(self.action)
|
||||
|
||||
|
|
|
@ -63,8 +63,8 @@ class FeaturesWindow:
|
|||
_('On Windows the Windows Credential Vault is used.')),
|
||||
_('Spell Checker'): (self.speller_available,
|
||||
_('Spellchecking of composed messages.'),
|
||||
_('Requires libgtkspell.'),
|
||||
_('Requires libgtkspell and libenchant.')),
|
||||
_('Requires Gspell'),
|
||||
_('Requires Gspell')),
|
||||
_('Automatic status'): (self.idle_available,
|
||||
_('Ability to measure idle time, in order to set auto status.'),
|
||||
_('Requires libxss library.'),
|
||||
|
@ -164,11 +164,7 @@ class FeaturesWindow:
|
|||
return True
|
||||
|
||||
def speller_available(self):
|
||||
try:
|
||||
__import__('gajim.gtkspell')
|
||||
except ValueError:
|
||||
return False
|
||||
return True
|
||||
return app.HAVE_SPELL
|
||||
|
||||
def idle_available(self):
|
||||
from gajim.common import sleepy
|
||||
|
|
|
@ -1,104 +0,0 @@
|
|||
## src/gtkspell.py
|
||||
##
|
||||
## (C) 2008 Thorsten P. 'dGhvcnN0ZW5wIEFUIHltYWlsIGNvbQ==\n'.decode("base64")
|
||||
## (C) 2015 Yann Leboulanger <asterix AT lagaule.org>
|
||||
##
|
||||
## This file is part of Gajim.
|
||||
##
|
||||
## Gajim is free software; you can redistribute it and/or modify
|
||||
## it under the terms of the GNU General Public License as published
|
||||
## by the Free Software Foundation; version 3 only.
|
||||
##
|
||||
## Gajim is distributed in the hope that it will be useful,
|
||||
## but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
## GNU General Public License for more details.
|
||||
##
|
||||
## You should have received a copy of the GNU General Public License
|
||||
## along with Gajim. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from gi.repository import GObject
|
||||
from gi.repository import Gtk
|
||||
from gi.repository import GLib
|
||||
import gi
|
||||
try:
|
||||
gi.require_version('GtkSpell', '3.0')
|
||||
from gi.repository import GtkSpell
|
||||
HAS_GTK_SPELL = True
|
||||
except (ImportError, ValueError):
|
||||
HAS_GTK_SPELL = False
|
||||
|
||||
|
||||
def ensure_attached(func):
|
||||
def f(self, *args, **kwargs):
|
||||
if self.spell:
|
||||
func(self, *args, **kwargs)
|
||||
else:
|
||||
raise RuntimeError("Spell object is already detached")
|
||||
return f
|
||||
|
||||
|
||||
class Spell(GObject.GObject):
|
||||
__gsignals__ = {
|
||||
'language_changed': (GObject.SignalFlags.RUN_FIRST, None, (str,))
|
||||
}
|
||||
|
||||
def __init__(self, textview, language=None, create=True, jid=None,
|
||||
per_type=None):
|
||||
GObject.GObject.__init__(self)
|
||||
if not isinstance(textview, Gtk.TextView):
|
||||
raise TypeError("Textview must be derived from Gtk.TextView")
|
||||
spell = GtkSpell.Checker.get_from_text_view(textview)
|
||||
if create:
|
||||
if spell:
|
||||
raise RuntimeError("Textview has already a Spell obj attached")
|
||||
self.spell = GtkSpell.Checker.new()
|
||||
|
||||
try:
|
||||
self.spell.set_language(language)
|
||||
except GLib.GError as error:
|
||||
if error.domain == 'gtkspell-error-quark':
|
||||
raise OSError("Unable to set language: '%s'" % language)
|
||||
|
||||
self.spell.connect('language-changed', self.on_language_changed)
|
||||
|
||||
else:
|
||||
if spell:
|
||||
self.spell = spell
|
||||
else:
|
||||
raise RuntimeError("Textview has no Spell object attached")
|
||||
|
||||
def on_language_changed(self, spell, lang):
|
||||
self.emit('language_changed', lang)
|
||||
|
||||
@ensure_attached
|
||||
def set_language(self, language):
|
||||
if not self.spell.set_language(language):
|
||||
raise OSError("Unable to set language: '%s'" % language)
|
||||
|
||||
@ensure_attached
|
||||
def recheck_all(self):
|
||||
self.spell.recheck_all()
|
||||
|
||||
def detach(self):
|
||||
if self.spell is not None:
|
||||
self.spell.detach()
|
||||
|
||||
def attach(self, textview):
|
||||
spell = GtkSpell.Checker.get_from_text_view(textview)
|
||||
if spell is None:
|
||||
print('attached')
|
||||
self.spell.attach(textview)
|
||||
|
||||
|
||||
GObject.type_register(Spell)
|
||||
|
||||
|
||||
def test_language(lang):
|
||||
spell = GtkSpell.Checker.new()
|
||||
try:
|
||||
spell.set_language(lang)
|
||||
except GLib.GError as error:
|
||||
if error.domain == 'gtkspell-error-quark':
|
||||
return False
|
||||
return True
|
|
@ -30,6 +30,10 @@ from gi.repository import Pango
|
|||
from gajim.common import app
|
||||
from gajim import gtkgui_helpers
|
||||
|
||||
if app.HAVE_SPELL:
|
||||
from gi.repository import Gspell
|
||||
|
||||
|
||||
class MessageTextView(Gtk.TextView):
|
||||
"""
|
||||
Class for the message textview (where user writes new messages) for
|
||||
|
@ -101,6 +105,7 @@ class MessageTextView(Gtk.TextView):
|
|||
def _on_focus_in(self, *args):
|
||||
if not self.has_text():
|
||||
self.get_buffer().set_text('')
|
||||
self.toggle_speller(True)
|
||||
|
||||
def _on_focus_out(self, *args):
|
||||
buf = self.get_buffer()
|
||||
|
@ -109,6 +114,12 @@ class MessageTextView(Gtk.TextView):
|
|||
if text == '':
|
||||
buf.insert_with_tags(
|
||||
start, self.PLACEHOLDER, self.placeholder_tag)
|
||||
self.toggle_speller(False)
|
||||
|
||||
def toggle_speller(self, activate):
|
||||
if app.HAVE_SPELL and app.config.get('use_speller'):
|
||||
spell_view = Gspell.TextView.get_from_gtk_text_view(self)
|
||||
spell_view.set_inline_spell_checking(activate)
|
||||
|
||||
def remove_placeholder(self):
|
||||
self._on_focus_in()
|
||||
|
|
|
@ -75,7 +75,9 @@ function install_deps {
|
|||
mingw-w64-"${ARCH}"-adwaita-icon-theme \
|
||||
mingw-w64-"${ARCH}"-libwebp \
|
||||
mingw-w64-"${ARCH}"-sqlite3 \
|
||||
mingw-w64-"${ARCH}"-goocanvas
|
||||
mingw-w64-"${ARCH}"-goocanvas \
|
||||
mingw-w64-"${ARCH}"-gspell \
|
||||
mingw-w64-"${ARCH}"-hunspell
|
||||
|
||||
build_pip install setuptools_scm
|
||||
|
||||
|
@ -136,6 +138,10 @@ function install_gajim {
|
|||
mkdir "${PACKAGE_DIR}"/gajim/data/plugins
|
||||
7z x -o"${PACKAGE_DIR}"/gajim/data/plugins "${BUILD_ROOT}"/plugin_installer.zip
|
||||
|
||||
# Install language dicts
|
||||
curl -o "${BUILD_ROOT}"/speller_dicts.zip https://gajim.org/downloads/snap/win/build/speller_dicts.zip
|
||||
7z x -o"${MINGW_ROOT}"/share "${BUILD_ROOT}"/speller_dicts.zip
|
||||
|
||||
# Install themes
|
||||
# rm -Rf "${MINGW_ROOT}"/etc
|
||||
# rm -Rf "${MINGW_ROOT}"/share/themes
|
||||
|
@ -194,7 +200,6 @@ function cleanup_install {
|
|||
rm -Rf "${MINGW_ROOT}"/share/ffmpeg
|
||||
rm -Rf "${MINGW_ROOT}"/share/vala
|
||||
rm -Rf "${MINGW_ROOT}"/share/readline
|
||||
rm -Rf "${MINGW_ROOT}"/share/xml
|
||||
rm -Rf "${MINGW_ROOT}"/share/bash-completion
|
||||
rm -Rf "${MINGW_ROOT}"/share/common-lisp
|
||||
rm -Rf "${MINGW_ROOT}"/share/emacs
|
||||
|
|
Loading…
Reference in New Issue