Port from GtkSpell to Gspell
This commit is contained in:
parent
28073ee118
commit
5df562d302
@ -75,11 +75,9 @@ The following packages are **STRONGLY RECOMMENDED** to be installed:
|
|||||||
|
|
||||||
The following packages are optional:
|
The following packages are optional:
|
||||||
------------------------------------
|
------------------------------------
|
||||||
* **gtkspell**
|
* **gspell**
|
||||||
|
|
||||||
Enable spell checking in the notes. Gtkspell depends on
|
Enable spell checking in the notes.
|
||||||
enchant. A version of gtkspell with gobject introspection
|
|
||||||
is needed, so minimally version 3.0.0.
|
|
||||||
|
|
||||||
* **rcs**
|
* **rcs**
|
||||||
|
|
||||||
|
@ -302,7 +302,7 @@ Styled Text Buffer
|
|||||||
:members:
|
:members:
|
||||||
:undoc-members:
|
:undoc-members:
|
||||||
:show-inheritance:
|
:show-inheritance:
|
||||||
.. autoclass:: GtkSpellState
|
.. autoclass:: GspellState
|
||||||
:members:
|
:members:
|
||||||
:undoc-members:
|
:undoc-members:
|
||||||
:show-inheritance:
|
:show-inheritance:
|
||||||
|
@ -790,6 +790,8 @@ class GrampsLocale:
|
|||||||
"""
|
"""
|
||||||
return self.language
|
return self.language
|
||||||
|
|
||||||
|
def locale_code(self):
|
||||||
|
return self.lang
|
||||||
|
|
||||||
def get_addon_translator(self, filename, domain="addon",
|
def get_addon_translator(self, filename, domain="addon",
|
||||||
languages=None):
|
languages=None):
|
||||||
|
@ -363,53 +363,12 @@ def show_settings():
|
|||||||
def verstr(nums):
|
def verstr(nums):
|
||||||
return '.'.join(str(num) for num in nums)
|
return '.'.join(str(num) for num in nums)
|
||||||
|
|
||||||
#GTKSPELL_MIN_VER = (3, 0)
|
|
||||||
#gtkspell_min_ver_str = verstr(GTKSPELL_MIN_VER)
|
|
||||||
# ENCHANT_MIN_VER = (0, 0) # TODO ?
|
|
||||||
gtkspell_ver_tp = (0, 0)
|
|
||||||
# Attempting to import gtkspell gives an error dialog if gtkspell is
|
|
||||||
# not available so test first and log just a warning to the console
|
|
||||||
# instead.
|
|
||||||
try:
|
try:
|
||||||
from gi import Repository
|
gi.require_version('Gspell', '1')
|
||||||
repository = Repository.get_default()
|
from gi.repository import Gspell
|
||||||
gtkspell_ver = _("not found")
|
gspell_ver = str(Gspell._version)
|
||||||
if repository.enumerate_versions("GtkSpell"):
|
|
||||||
try:
|
|
||||||
gi.require_version('GtkSpell', '3.0')
|
|
||||||
from gi.repository import GtkSpell as Gtkspell
|
|
||||||
gtkspell_ver = str(Gtkspell._version)
|
|
||||||
aaa = Gtkspell._version.split(".")
|
|
||||||
v1 = int(aaa[0])
|
|
||||||
v2 = int(aaa[1])
|
|
||||||
gtkspell_ver_tp = (v1, v2)
|
|
||||||
# print("gtkspell_ver " + gtkspell_ver)
|
|
||||||
except Exception:
|
|
||||||
gtkspell_ver = _("not found")
|
|
||||||
elif repository.enumerate_versions("Gtkspell"):
|
|
||||||
try:
|
|
||||||
gi.require_version('Gtkspell', '3.0')
|
|
||||||
from gi.repository import Gtkspell
|
|
||||||
gtkspell_ver = str(Gtkspell._version)
|
|
||||||
gtkspell_ver_tp = Gtkspell._version
|
|
||||||
# print("gtkspell_ver " + gtkspell_ver)
|
|
||||||
except Exception:
|
|
||||||
gtkspell_ver = _("not found")
|
|
||||||
except Exception:
|
except Exception:
|
||||||
gtkspell_ver = _("not found")
|
gspell_ver = _("not found")
|
||||||
|
|
||||||
try:
|
|
||||||
import enchant
|
|
||||||
enchant_result = enchant.get_enchant_version()
|
|
||||||
except Exception:
|
|
||||||
from ctypes import cdll, c_char_p
|
|
||||||
try:
|
|
||||||
enchant = cdll.LoadLibrary("libenchant")
|
|
||||||
except FileNotFoundError:
|
|
||||||
enchant = cdll.LoadLibrary("libenchant-2")
|
|
||||||
enchant_ver_call = enchant.enchant_get_version
|
|
||||||
enchant_ver_call.restype = c_char_p
|
|
||||||
enchant_result = enchant_ver_call().decode("utf-8")
|
|
||||||
|
|
||||||
#RCS_MIN_VER = (5, 9, 4)
|
#RCS_MIN_VER = (5, 9, 4)
|
||||||
#rcs_ver_str = verstr(RCS_MIN_VER)
|
#rcs_ver_str = verstr(RCS_MIN_VER)
|
||||||
@ -539,8 +498,7 @@ def show_settings():
|
|||||||
print('')
|
print('')
|
||||||
print("Optional:")
|
print("Optional:")
|
||||||
print("---------")
|
print("---------")
|
||||||
print(' Gtkspell :', gtkspell_ver)
|
print(' Gspell :', gspell_ver)
|
||||||
print(' Enchant :', enchant_result)
|
|
||||||
print(' RCS :', rcs_ver)
|
print(' RCS :', rcs_ver)
|
||||||
print(' PILLOW :', pil_ver)
|
print(' PILLOW :', pil_ver)
|
||||||
print(' GExiv2 : %s' % gexiv2_str)
|
print(' GExiv2 : %s' % gexiv2_str)
|
||||||
|
@ -71,7 +71,7 @@ from .display import display_help
|
|||||||
from gramps.gen.plug.utils import available_updates
|
from gramps.gen.plug.utils import available_updates
|
||||||
from .plug import PluginWindows
|
from .plug import PluginWindows
|
||||||
#from gramps.gen.errors import WindowActiveError
|
#from gramps.gen.errors import WindowActiveError
|
||||||
from .spell import HAVE_GTKSPELL
|
from .spell import HAVE_GSPELL
|
||||||
from gramps.gen.constfunc import win
|
from gramps.gen.constfunc import win
|
||||||
_ = glocale.translation.gettext
|
_ = glocale.translation.gettext
|
||||||
from gramps.gen.utils.symbols import Symbols
|
from gramps.gen.utils.symbols import Symbols
|
||||||
@ -1654,14 +1654,14 @@ class GrampsPreferences(ConfigureDialog):
|
|||||||
row, 'behavior.spellcheck', start=1, stop=3,
|
row, 'behavior.spellcheck', start=1, stop=3,
|
||||||
tooltip=_("Enable the spelling checker"
|
tooltip=_("Enable the spelling checker"
|
||||||
" for notes."))
|
" for notes."))
|
||||||
if not HAVE_GTKSPELL:
|
if not HAVE_GSPELL:
|
||||||
obj.set_sensitive(False)
|
obj.set_sensitive(False)
|
||||||
spell_dict = {'gramps_wiki_build_spell_url':
|
spell_dict = {'gramps_wiki_build_spell_url':
|
||||||
URL_WIKISTRING +
|
URL_WIKISTRING +
|
||||||
"GEPS_029:_GTK3-GObject_introspection"
|
"GEPS_029:_GTK3-GObject_introspection"
|
||||||
"_Conversion#Spell_Check_Install"}
|
"_Conversion#Spell_Check_Install"}
|
||||||
obj.set_tooltip_text(
|
obj.set_tooltip_text(
|
||||||
_("GtkSpell not loaded. "
|
_("Gspell not loaded. "
|
||||||
"Spell checking will not be available.\n"
|
"Spell checking will not be available.\n"
|
||||||
"To build it for Gramps see "
|
"To build it for Gramps see "
|
||||||
"%(gramps_wiki_build_spell_url)s") % spell_dict)
|
"%(gramps_wiki_build_spell_url)s") % spell_dict)
|
||||||
|
@ -20,8 +20,7 @@
|
|||||||
#
|
#
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Provide an interface to the gtkspell interface. This requires
|
Provide an interface to the gspell interface. If the gspell package is not
|
||||||
python-gnome-extras package. If the gtkspell package is not
|
|
||||||
present, we default to no spell checking.
|
present, we default to no spell checking.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
@ -45,33 +44,24 @@ LOG = logging.getLogger(".Spell")
|
|||||||
# GTK libraries
|
# GTK libraries
|
||||||
#
|
#
|
||||||
#-------------------------------------------------------------------------
|
#-------------------------------------------------------------------------
|
||||||
from gi.repository import Gtk
|
|
||||||
from gi import Repository
|
|
||||||
|
|
||||||
from gramps.gen.const import GRAMPS_LOCALE as glocale
|
from gramps.gen.const import GRAMPS_LOCALE as glocale
|
||||||
_ = glocale.translation.gettext
|
_ = glocale.translation.gettext
|
||||||
|
|
||||||
HAVE_GTKSPELL = False
|
HAVE_GSPELL = False
|
||||||
|
|
||||||
# Attempting to import gtkspell gives an error dialog if gtkspell is not
|
try:
|
||||||
# available so test first and log just a warning to the console instead.
|
import gi
|
||||||
repository = Repository.get_default()
|
gi.require_version('Gspell', '1')
|
||||||
if repository.enumerate_versions("GtkSpell"):
|
from gi.repository import Gspell
|
||||||
try:
|
langs = Gspell.language_get_available()
|
||||||
import gi
|
for lang in langs:
|
||||||
gi.require_version('GtkSpell', '3.0')
|
LOG.debug('%s (%s) dict available', lang.get_name(), lang.get_code())
|
||||||
from gi.repository import GtkSpell as Gtkspell
|
if langs:
|
||||||
HAVE_GTKSPELL = True
|
HAVE_GSPELL = True
|
||||||
except:
|
else:
|
||||||
pass
|
LOG.warning(_("You have no installed dictionaries."))
|
||||||
elif repository.enumerate_versions("Gtkspell"):
|
except (ImportError, ValueError):
|
||||||
try:
|
pass
|
||||||
import gi
|
|
||||||
gi.require_version('Gtkspell', '3.0')
|
|
||||||
from gi.repository import Gtkspell
|
|
||||||
HAVE_GTKSPELL = True
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
|
|
||||||
#-------------------------------------------------------------------------
|
#-------------------------------------------------------------------------
|
||||||
#
|
#
|
||||||
@ -87,81 +77,47 @@ from gramps.gen.config import config
|
|||||||
#-------------------------------------------------------------------------
|
#-------------------------------------------------------------------------
|
||||||
|
|
||||||
class Spell:
|
class Spell:
|
||||||
"""Attach a gtkspell instance to the passed TextView instance.
|
"""Attach a Gspell instance to the passed TextView instance.
|
||||||
"""
|
"""
|
||||||
_spellcheck_options = {'off': _('Off')}
|
_spellcheck_options = {'off': _('Off')}
|
||||||
|
|
||||||
if HAVE_GTKSPELL:
|
if HAVE_GSPELL:
|
||||||
_spellcheck_options['on'] = _('On')
|
_spellcheck_options['on'] = _('On')
|
||||||
|
|
||||||
def __init__(self, textview):
|
def __init__(self, textview):
|
||||||
self.textview = textview
|
self._active_spellcheck = 'off'
|
||||||
|
|
||||||
if HAVE_GTKSPELL and config.get('behavior.spellcheck'):
|
if not HAVE_GSPELL:
|
||||||
|
return
|
||||||
|
|
||||||
|
locale_code = glocale.locale_code()
|
||||||
|
gspell_language = None
|
||||||
|
if locale_code is not None:
|
||||||
|
gspell_language = Gspell.language_lookup(locale_code[:5])
|
||||||
|
if gspell_language is None:
|
||||||
|
gspell_language= Gspell.language_lookup(locale_code[:2])
|
||||||
|
checker = Gspell.Checker.new(gspell_language)
|
||||||
|
buffer = Gspell.TextBuffer.get_from_gtk_text_buffer(textview.get_buffer())
|
||||||
|
buffer.set_spell_checker(checker)
|
||||||
|
self.gspell_view = Gspell.TextView.get_from_gtk_text_view(textview)
|
||||||
|
|
||||||
|
if config.get('behavior.spellcheck'):
|
||||||
self.spellcheck = 'on'
|
self.spellcheck = 'on'
|
||||||
else:
|
else:
|
||||||
self.spellcheck = 'off'
|
self.spellcheck = 'off'
|
||||||
|
|
||||||
self._active_spellcheck = 'off'
|
|
||||||
self.__real_set_active_spellcheck(self.spellcheck)
|
self.__real_set_active_spellcheck(self.spellcheck)
|
||||||
|
|
||||||
# Private
|
# Private
|
||||||
|
|
||||||
def __real_set_active_spellcheck(self, spellcheck_code):
|
def __real_set_active_spellcheck(self, spellcheck_code):
|
||||||
"""Set active spellcheck by its code."""
|
"""Set active spellcheck by its code."""
|
||||||
if self._active_spellcheck == 'off':
|
if self._active_spellcheck == spellcheck_code:
|
||||||
if spellcheck_code == 'off':
|
return
|
||||||
return
|
|
||||||
else:
|
self.gspell_view.set_inline_spell_checking(spellcheck_code == 'on')
|
||||||
try:
|
self.gspell_view.set_enable_language_menu(spellcheck_code == 'on')
|
||||||
#transfer full GTK object, so assign to an attribute!
|
self._active_spellcheck = spellcheck_code
|
||||||
if Gtkspell._namespace == "Gtkspell":
|
|
||||||
self.gtkspell_spell = Gtkspell.Spell.new()
|
|
||||||
elif Gtkspell._namespace == "GtkSpell":
|
|
||||||
self.gtkspell_spell = Gtkspell.Checker.new()
|
|
||||||
try:
|
|
||||||
#check for dictionary in system locale (LANG)
|
|
||||||
#if exist it will be default one
|
|
||||||
self.gtkspell_spell.set_language(None)
|
|
||||||
#TODO: use "get_language_list" for use when there
|
|
||||||
#is no English or systemlocale one
|
|
||||||
except:
|
|
||||||
#else check for English dictionary
|
|
||||||
#if exist it will be default one
|
|
||||||
#other installed one will also be available
|
|
||||||
self.gtkspell_spell.set_language("en")
|
|
||||||
#if that fails no spellchecker will be available
|
|
||||||
with self.textview.undo_disabled():
|
|
||||||
success = self.gtkspell_spell.attach(self.textview)
|
|
||||||
try:
|
|
||||||
#show decoded language codes in the context menu
|
|
||||||
#requires the iso-codes package from http://pkg-isocodes.alioth.debian.org
|
|
||||||
self.gtkspell_spell.set_property("decode-language-codes", True)
|
|
||||||
except TypeError:
|
|
||||||
#available in GtkSpell since version 3.0.3 (2013-06-04)
|
|
||||||
pass
|
|
||||||
self._active_spellcheck = spellcheck_code
|
|
||||||
except Exception as err:
|
|
||||||
# attaching the spellchecker will fail if
|
|
||||||
# the language does not exist
|
|
||||||
# and presumably if there is no dictionary
|
|
||||||
if not self.gtkspell_spell.get_language_list():
|
|
||||||
LOG.warning(_("You have no installed dictionaries. "
|
|
||||||
"Either install one or disable spell "
|
|
||||||
"checking"))
|
|
||||||
else:
|
|
||||||
LOG.warning(_("Spelling checker initialization "
|
|
||||||
"failed: %s"), err)
|
|
||||||
else:
|
|
||||||
if spellcheck_code == 'on':
|
|
||||||
return
|
|
||||||
else:
|
|
||||||
if Gtkspell._namespace == "Gtkspell":
|
|
||||||
self.gtkspell_spell = Gtkspell.Spell.get_from_text_view(self.textview)
|
|
||||||
elif Gtkspell._namespace == "GtkSpell":
|
|
||||||
self.gtkspell_spell = Gtkspell.Checker.get_from_text_view(self.textview)
|
|
||||||
self.gtkspell_spell.detach()
|
|
||||||
self._active_spellcheck = spellcheck_code
|
|
||||||
|
|
||||||
# Public API
|
# Public API
|
||||||
|
|
||||||
|
@ -116,15 +116,15 @@ class LinkTag(Gtk.TextTag):
|
|||||||
|
|
||||||
#-------------------------------------------------------------------------
|
#-------------------------------------------------------------------------
|
||||||
#
|
#
|
||||||
# GtkSpellState class
|
# GspellState class
|
||||||
#
|
#
|
||||||
#-------------------------------------------------------------------------
|
#-------------------------------------------------------------------------
|
||||||
class GtkSpellState:
|
class GspellState:
|
||||||
"""
|
"""
|
||||||
A simple state machine kinda thingy.
|
A simple state machine kinda thingy.
|
||||||
|
|
||||||
Trying to track Gtk.Spell activities on a buffer and re-apply formatting
|
Trying to track Gspell activities on a buffer and re-apply formatting
|
||||||
after Gtk.Spell replaces a misspelled word.
|
after Gspell replaces a misspelled word.
|
||||||
"""
|
"""
|
||||||
(STATE_NONE,
|
(STATE_NONE,
|
||||||
STATE_CLICKED,
|
STATE_CLICKED,
|
||||||
@ -180,10 +180,10 @@ class GtkSpellState:
|
|||||||
|
|
||||||
def get_word_extents_from_mark(self, textbuffer, mark):
|
def get_word_extents_from_mark(self, textbuffer, mark):
|
||||||
"""
|
"""
|
||||||
Get the word extents as Gtk.Spell does.
|
Get the word extents as Gspell does.
|
||||||
|
|
||||||
Used to get the beginning of the word, in which user right clicked.
|
Used to get the beginning of the word, in which user right clicked.
|
||||||
Formatting found at that position used after Gtk.Spell replaces
|
Formatting found at that position used after Gspell replaces
|
||||||
misspelled words.
|
misspelled words.
|
||||||
"""
|
"""
|
||||||
start = textbuffer.get_iter_at_mark(mark)
|
start = textbuffer.get_iter_at_mark(mark)
|
||||||
@ -198,7 +198,7 @@ class GtkSpellState:
|
|||||||
|
|
||||||
def forward_word_end(self, iter):
|
def forward_word_end(self, iter):
|
||||||
"""
|
"""
|
||||||
Gtk.Spell style Gtk.TextIter.forward_word_end.
|
Gspell style Gtk.TextIter.forward_word_end.
|
||||||
|
|
||||||
The parameter 'iter' is changing as side effect.
|
The parameter 'iter' is changing as side effect.
|
||||||
"""
|
"""
|
||||||
@ -217,7 +217,7 @@ class GtkSpellState:
|
|||||||
|
|
||||||
def backward_word_start(self, iter):
|
def backward_word_start(self, iter):
|
||||||
"""
|
"""
|
||||||
Gtk.Spell style Gtk.TextIter.backward_word_start.
|
Gspell style Gtk.TextIter.backward_word_start.
|
||||||
|
|
||||||
The parameter 'iter' is changing as side effect.
|
The parameter 'iter' is changing as side effect.
|
||||||
"""
|
"""
|
||||||
@ -310,8 +310,8 @@ class StyledTextBuffer(UndoableBuffer):
|
|||||||
|
|
||||||
self.linkcolor = 'blue'
|
self.linkcolor = 'blue'
|
||||||
|
|
||||||
# init gtkspell "state machine"
|
# init gspell "state machine"
|
||||||
self.gtkspell_state = GtkSpellState(self)
|
self.gspell_state = GspellState(self)
|
||||||
|
|
||||||
# Virtual methods
|
# Virtual methods
|
||||||
|
|
||||||
@ -385,6 +385,8 @@ class StyledTextBuffer(UndoableBuffer):
|
|||||||
else:
|
else:
|
||||||
value = StyledTextTagType.STYLE_DEFAULT[style]
|
value = StyledTextTagType.STYLE_DEFAULT[style]
|
||||||
for tname in tag_names:
|
for tname in tag_names:
|
||||||
|
if tname is None:
|
||||||
|
continue
|
||||||
if tname.startswith(str(style)):
|
if tname.startswith(str(style)):
|
||||||
value = tname.split(' ', 1)[1]
|
value = tname.split(' ', 1)[1]
|
||||||
value = StyledTextTagType.STYLE_TYPE[style](value)
|
value = StyledTextTagType.STYLE_TYPE[style](value)
|
||||||
@ -612,6 +614,8 @@ class StyledTextBuffer(UndoableBuffer):
|
|||||||
s_tags = []
|
s_tags = []
|
||||||
|
|
||||||
for g_tagname, g_ranges in g_tags.items():
|
for g_tagname, g_ranges in g_tags.items():
|
||||||
|
if g_tagname is None:
|
||||||
|
continue
|
||||||
if g_tagname.startswith('link'):
|
if g_tagname.startswith('link'):
|
||||||
tag = self.get_tag_table().lookup(g_tagname)
|
tag = self.get_tag_table().lookup(g_tagname)
|
||||||
s_ranges = [(start, end+1) for (start, end) in g_ranges]
|
s_ranges = [(start, end+1) for (start, end) in g_ranges]
|
||||||
|
@ -402,7 +402,8 @@ class StyledTextEditor(Gtk.TextView):
|
|||||||
self.match = self.textbuffer.match_check(iter_at_location.get_offset())
|
self.match = self.textbuffer.match_check(iter_at_location.get_offset())
|
||||||
tooltip = None
|
tooltip = None
|
||||||
for tag in (tag for tag in iter_at_location.get_tags()
|
for tag in (tag for tag in iter_at_location.get_tags()
|
||||||
if tag.get_property('name').startswith("link")):
|
if tag.get_property('name') is not None and
|
||||||
|
tag.get_property('name').startswith("link")):
|
||||||
self.match = (x, y, LINK, tag.data, tag)
|
self.match = (x, y, LINK, tag.data, tag)
|
||||||
tooltip = self.make_tooltip_from_link(tag)
|
tooltip = self.make_tooltip_from_link(tag)
|
||||||
break
|
break
|
||||||
@ -808,7 +809,7 @@ class StyledTextEditor(Gtk.TextView):
|
|||||||
"""
|
"""
|
||||||
Remove all formats from the selection or from all.
|
Remove all formats from the selection or from all.
|
||||||
|
|
||||||
Remove only our own tags without touching other ones (e.g. Gtk.Spell),
|
Remove only our own tags without touching other ones (e.g. Gspell),
|
||||||
thus remove_all_tags() can not be used.
|
thus remove_all_tags() can not be used.
|
||||||
"""
|
"""
|
||||||
clear_anything = self.textbuffer.clear_selection()
|
clear_anything = self.textbuffer.clear_selection()
|
||||||
|
Loading…
Reference in New Issue
Block a user