Refactor Speller
This commit is contained in:
parent
970d6f8c3f
commit
3c103315ec
|
@ -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
|
||||||
|
|
|
@ -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):
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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')
|
||||||
|
|
|
@ -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()
|
||||||
|
|
Loading…
Reference in New Issue