Refactor Speller

This commit is contained in:
Philipp Hörist 2017-10-19 11:26:22 +02:00
parent 970d6f8c3f
commit 3c103315ec
7 changed files with 111 additions and 104 deletions

View File

@ -58,13 +58,6 @@ from gajim.common.exceptions import GajimGeneralException
from gajim.common.const import AvatarSize from gajim.common.const import AvatarSize
from gajim.command_system.implementation.hosts import ChatCommands from gajim.command_system.implementation.hosts import ChatCommands
try:
from gajim import gtkspell
HAS_GTK_SPELL = True
except (ImportError, ValueError):
HAS_GTK_SPELL = False
from gajim.chat_control_base import ChatControlBase from gajim.chat_control_base import ChatControlBase
################################################################################ ################################################################################
@ -1180,10 +1173,7 @@ class ChatControl(ChatControlBase):
self.handlers[i].disconnect(i) self.handlers[i].disconnect(i)
del self.handlers[i] del self.handlers[i]
self.conv_textview.del_handlers() self.conv_textview.del_handlers()
if app.config.get('use_speller') and HAS_GTK_SPELL: self.remove_speller()
spell_obj = gtkspell.get_from_text_view(self.msg_textview)
if spell_obj:
spell_obj.detach()
self.msg_textview.destroy() self.msg_textview.destroy()
# PluginSystem: calling shutdown of super class (ChatControlBase) to let # PluginSystem: calling shutdown of super class (ChatControlBase) to let
# it remove it's GUI extension points # it remove it's GUI extension points

View File

@ -35,12 +35,14 @@ from gi.repository import Pango
from gi.repository import GObject from gi.repository import GObject
from gi.repository import GLib from gi.repository import GLib
from gi.repository import Gio from gi.repository import Gio
from gajim import gtkgui_helpers from gajim import gtkgui_helpers
from gajim.gtkgui_helpers import Color from gajim.gtkgui_helpers import Color
from gajim import message_control from gajim import message_control
from gajim import dialogs from gajim import dialogs
from gajim import history_window from gajim import history_window
from gajim import notify from gajim import notify
from gajim import gtkspell
import re import re
from gajim import emoticons from gajim import emoticons
@ -64,11 +66,6 @@ from gajim.command_system.implementation.middleware import CommandTools
from gajim.command_system.implementation import standard from gajim.command_system.implementation import standard
from gajim.command_system.implementation import execute from gajim.command_system.implementation import execute
try:
from gajim import gtkspell
HAS_GTK_SPELL = True
except (ImportError, ValueError):
HAS_GTK_SPELL = False
################################################################################ ################################################################################
class ChatControlBase(MessageControl, ChatCommandProcessor, CommandTools): class ChatControlBase(MessageControl, ChatCommandProcessor, CommandTools):
@ -355,7 +352,8 @@ class ChatControlBase(MessageControl, ChatCommandProcessor, CommandTools):
self.set_emoticon_popover() self.set_emoticon_popover()
# Attach speller # Attach speller
if app.config.get('use_speller') and HAS_GTK_SPELL: self.spell = None
self.spell_handlers = []
self.set_speller() self.set_speller()
self.conv_textview.tv.show() self.conv_textview.tv.show()
@ -480,24 +478,57 @@ class ChatControlBase(MessageControl, ChatCommandProcessor, CommandTools):
image.set_from_pixbuf(icon) image.set_from_pixbuf(icon)
def set_speller(self): def set_speller(self):
# now set the one the user selected if not gtkspell.HAS_GTK_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:
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
def get_speller_language(self):
per_type = 'contacts' per_type = 'contacts'
if self.type_id == message_control.TYPE_GC: if self.type_id == 'gc':
per_type = 'rooms' per_type = 'rooms'
lang = app.config.get_per(per_type, self.contact.jid, lang = app.config.get_per(
'speller_language') per_type, self.contact.jid, 'speller_language')
if not lang: if not lang:
# use the default one # use the default one
lang = app.config.get('speller_language') lang = app.config.get('speller_language')
if not lang: if not lang:
lang = app.LANG lang = app.LANG
if lang: return lang or None
try:
self.spell = gtkspell.Spell(self.msg_textview, lang)
self.msg_textview.lang = lang
self.spell.connect('language_changed', self.on_language_changed)
except (GObject.GError, RuntimeError, TypeError, OSError):
dialogs.AspellDictError(lang)
def on_language_changed(self, spell, lang): def on_language_changed(self, spell, lang):
per_type = 'contacts' per_type = 'contacts'
@ -505,9 +536,8 @@ class ChatControlBase(MessageControl, ChatCommandProcessor, CommandTools):
per_type = 'rooms' per_type = 'rooms'
if not app.config.get_per(per_type, self.contact.jid): if not app.config.get_per(per_type, self.contact.jid):
app.config.add_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', app.config.set_per(
lang) per_type, self.contact.jid, 'speller_language', lang)
self.msg_textview.lang = lang
def on_banner_label_populate_popup(self, label, menu): def on_banner_label_populate_popup(self, label, menu):
""" """

View File

@ -50,12 +50,7 @@ from gajim import message_control
from gajim.chat_control_base import ChatControlBase from gajim.chat_control_base import ChatControlBase
from gajim import dataforms_widget from gajim import dataforms_widget
from gajim import gui_menu_builder from gajim import gui_menu_builder
try:
from gajim import gtkspell from gajim import gtkspell
HAS_GTK_SPELL = True
except (ImportError, ValueError):
HAS_GTK_SPELL = False
from gajim.common import helpers from gajim.common import helpers
from gajim.common import app from gajim.common import app
@ -192,7 +187,7 @@ class PreferencesWindow:
self.xml.get_object('xhtml_checkbutton').set_active(st) self.xml.get_object('xhtml_checkbutton').set_active(st)
# use speller # use speller
if HAS_GTK_SPELL: if gtkspell.HAS_GTK_SPELL:
st = app.config.get('use_speller') st = app.config.get('use_speller')
self.xml.get_object('speller_checkbutton').set_active(st) self.xml.get_object('speller_checkbutton').set_active(st)
else: else:
@ -660,23 +655,13 @@ class PreferencesWindow:
def apply_speller(self): def apply_speller(self):
for ctrl in self._get_all_controls(): for ctrl in self._get_all_controls():
if isinstance(ctrl, ChatControlBase): if isinstance(ctrl, ChatControlBase):
try:
spell_obj = gtkspell.get_from_text_view(ctrl.msg_textview)
except (TypeError, RuntimeError, OSError):
spell_obj = None
if not spell_obj:
ctrl.set_speller() ctrl.set_speller()
def remove_speller(self): def remove_speller(self):
for ctrl in self._get_all_controls(): for ctrl in self._get_all_controls():
if isinstance(ctrl, ChatControlBase): if isinstance(ctrl, ChatControlBase):
try: if ctrl.spell is not None:
spell_obj = gtkspell.get_from_text_view(ctrl.msg_textview) ctrl.remove_speller()
except (TypeError, RuntimeError):
spell_obj = None
if spell_obj:
spell_obj.detach()
def on_speller_checkbutton_toggled(self, widget): def on_speller_checkbutton_toggled(self, widget):
active = widget.get_active() active = widget.get_active()
@ -685,15 +670,10 @@ class PreferencesWindow:
lang = app.config.get('speller_language') lang = app.config.get('speller_language')
if not lang: if not lang:
lang = app.LANG lang = app.LANG
tv = Gtk.TextView()
try: available = gtkspell.test_language(lang)
gtkspell.Spell(tv, lang) if not available:
except (TypeError, RuntimeError, OSError): dialogs.AspellDictError(lang)
dialogs.ErrorDialog(
_('Dictionary for lang %s not available') % lang,
_('You have to install %s dictionary to use spellchecking, or '
'choose another language by setting the speller_language option.'
) % lang)
app.config.set('use_speller', False) app.config.set('use_speller', False)
widget.set_active(False) widget.set_active(False)
else: else:

View File

@ -42,6 +42,7 @@ from gajim import gtkgui_helpers
from gajim import vcard from gajim import vcard
from gajim import conversation_textview from gajim import conversation_textview
from gajim import dataforms_widget from gajim import dataforms_widget
from gajim import gtkspell
from random import randrange from random import randrange
from gajim.common import pep from gajim.common import pep
@ -50,12 +51,6 @@ from gajim.common import const
from gajim.options_dialog import OptionsDialog from gajim.options_dialog import OptionsDialog
from gajim.common.const import Option, OptionKind, OptionType from gajim.common.const import Option, OptionKind, OptionType
try:
from gajim import gtkspell
HAS_GTK_SPELL = True
except (ImportError, ValueError):
HAS_GTK_SPELL = False
# those imports are not used in this file, but in files that 'import dialogs' # those imports are not used in this file, but in files that 'import dialogs'
# so they can do dialog.GajimThemesWindow() for example # so they can do dialog.GajimThemesWindow() for example
from gajim.filetransfers_window import FileTransfersWindow from gajim.filetransfers_window import FileTransfersWindow
@ -1486,11 +1481,11 @@ class FileChooserDialog(Gtk.FileChooserDialog):
class AspellDictError: class AspellDictError:
def __init__(self, lang): def __init__(self, lang):
ErrorDialog( ErrorDialog(
_('Dictionary for lang %s not available') % lang, _('Dictionary for lang "%s" not available') % lang,
_('You have to install %s dictionary to use spellchecking, or ' _('You have to install the dictionary "%s" to use spellchecking, '
'choose another language by setting the speller_language option.' 'or choose another language by setting the speller_language '
'\n\nHighlighting misspelled words feature will not be used') % lang) 'option.\n\n'
app.config.set('use_speller', False) 'Highlighting misspelled words feature will not be used') % lang)
class ConfirmationDialog(HigDialog): class ConfirmationDialog(HigDialog):
""" """
@ -3082,14 +3077,14 @@ class SingleMessageWindow:
else: else:
self.to_entry.set_text(to) self.to_entry.set_text(to)
if app.config.get('use_speller') and HAS_GTK_SPELL and action == 'send': if app.config.get('use_speller') and gtkspell.HAS_GTK_SPELL and action == 'send':
try: try:
lang = app.config.get('speller_language') lang = app.config.get('speller_language')
if not lang: if not lang:
lang = app.LANG lang = app.LANG
gtkspell.Spell(self.conversation_textview.tv, lang) self.spell = gtkspell.Spell(self.message_textview, lang)
gtkspell.Spell(self.message_textview, lang) self.spell.attach(self.message_textview)
except (GObject.GError, TypeError, RuntimeError, OSError): except OSError:
AspellDictError(lang) AspellDictError(lang)
self.prepare_widgets_for(self.action) self.prepare_widgets_for(self.action)

View File

@ -19,9 +19,16 @@
from gi.repository import GObject from gi.repository import GObject
from gi.repository import Gtk from gi.repository import Gtk
from gi.repository import GLib
import gi import gi
gi.require_version('GtkSpell', '3.0') gi.require_version('GtkSpell', '3.0')
try:
from gi.repository import GtkSpell from gi.repository import GtkSpell
HAS_GTK_SPELL = True
except ImportError:
HAS_GTK_SPELL = False
from gajim.common import app
def ensure_attached(func): def ensure_attached(func):
@ -48,12 +55,13 @@ class Spell(GObject.GObject):
if spell: if spell:
raise RuntimeError("Textview has already a Spell obj attached") raise RuntimeError("Textview has already a Spell obj attached")
self.spell = GtkSpell.Checker.new() self.spell = GtkSpell.Checker.new()
if not self.spell:
raise OSError("Unable to create spell object.") try:
if not self.spell.attach(textview): self.spell.set_language(language)
raise OSError("Unable to attach spell object.") except GLib.GError as error:
if not self.spell.set_language(language): if error.domain == 'gtkspell-error-quark':
raise OSError("Unable to set language: '%s'" % language) raise OSError("Unable to set language: '%s'" % language)
self.spell.connect('language-changed', self.on_language_changed) self.spell.connect('language-changed', self.on_language_changed)
else: else:
@ -74,12 +82,25 @@ class Spell(GObject.GObject):
def recheck_all(self): def recheck_all(self):
self.spell.recheck_all() self.spell.recheck_all()
@ensure_attached
def detach(self): def detach(self):
if self.spell is not None:
self.spell.detach() self.spell.detach()
self.spell = None
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) GObject.type_register(Spell)
def get_from_text_view(textview):
return Spell(textview, create=False) 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

View File

@ -2858,18 +2858,6 @@ class Interface:
# get transports type from DB # get transports type from DB
app.transport_type = app.logger.get_transports_type() app.transport_type = app.logger.get_transports_type()
# test is dictionnary is present for speller
if app.config.get('use_speller'):
lang = app.config.get('speller_language')
if not lang:
lang = app.LANG
tv = Gtk.TextView()
try:
from gajim import gtkspell
spell = gtkspell.Spell(tv, lang)
except (ImportError, TypeError, RuntimeError, OSError, ValueError):
dialogs.AspellDictError(lang)
if app.config.get('soundplayer') == '': if app.config.get('soundplayer') == '':
# only on first time Gajim starts # only on first time Gajim starts
commands = ('paplay', 'aplay', 'play', 'ossplay') commands = ('paplay', 'aplay', 'play', 'ossplay')

View File

@ -57,7 +57,7 @@ class MessageTextView(Gtk.TextView):
self.undo_list = [] self.undo_list = []
# needed to know if we undid something # needed to know if we undid something
self.undo_pressed = False self.undo_pressed = False
self.lang = None # Lang used for spell checking
_buffer = self.get_buffer() _buffer = self.get_buffer()
self.begin_tags = {} self.begin_tags = {}
self.end_tags = {} self.end_tags = {}
@ -92,12 +92,15 @@ class MessageTextView(Gtk.TextView):
_buffer.insert_with_tags( _buffer.insert_with_tags(
start, self.PLACEHOLDER, self.placeholder_tag) start, self.PLACEHOLDER, self.placeholder_tag)
def _on_focus_in(self, *args): def has_text(self):
buf = self.get_buffer() buf = self.get_buffer()
start, end = buf.get_bounds() start, end = buf.get_bounds()
text = buf.get_text(start, end, True) text = buf.get_text(start, end, True)
if text == self.PLACEHOLDER: return text != self.PLACEHOLDER
buf.set_text('')
def _on_focus_in(self, *args):
if not self.has_text():
self.get_buffer().set_text('')
def _on_focus_out(self, *args): def _on_focus_out(self, *args):
buf = self.get_buffer() buf = self.get_buffer()