Port from GtkSpell to Gspell

This commit is contained in:
André Apitzsch 2023-07-03 22:18:55 +02:00 committed by Nick Hall
parent 28073ee118
commit 5df562d302
8 changed files with 69 additions and 150 deletions

View File

@ -75,11 +75,9 @@ The following packages are **STRONGLY RECOMMENDED** to be installed:
The following packages are optional:
------------------------------------
* **gtkspell**
* **gspell**
Enable spell checking in the notes. Gtkspell depends on
enchant. A version of gtkspell with gobject introspection
is needed, so minimally version 3.0.0.
Enable spell checking in the notes.
* **rcs**

View File

@ -302,7 +302,7 @@ Styled Text Buffer
:members:
:undoc-members:
:show-inheritance:
.. autoclass:: GtkSpellState
.. autoclass:: GspellState
:members:
:undoc-members:
:show-inheritance:

View File

@ -790,6 +790,8 @@ class GrampsLocale:
"""
return self.language
def locale_code(self):
return self.lang
def get_addon_translator(self, filename, domain="addon",
languages=None):

View File

@ -363,53 +363,12 @@ def show_settings():
def verstr(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:
from gi import Repository
repository = Repository.get_default()
gtkspell_ver = _("not found")
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")
gi.require_version('Gspell', '1')
from gi.repository import Gspell
gspell_ver = str(Gspell._version)
except Exception:
gtkspell_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")
gspell_ver = _("not found")
#RCS_MIN_VER = (5, 9, 4)
#rcs_ver_str = verstr(RCS_MIN_VER)
@ -539,8 +498,7 @@ def show_settings():
print('')
print("Optional:")
print("---------")
print(' Gtkspell :', gtkspell_ver)
print(' Enchant :', enchant_result)
print(' Gspell :', gspell_ver)
print(' RCS :', rcs_ver)
print(' PILLOW :', pil_ver)
print(' GExiv2 : %s' % gexiv2_str)

View File

@ -71,7 +71,7 @@ from .display import display_help
from gramps.gen.plug.utils import available_updates
from .plug import PluginWindows
#from gramps.gen.errors import WindowActiveError
from .spell import HAVE_GTKSPELL
from .spell import HAVE_GSPELL
from gramps.gen.constfunc import win
_ = glocale.translation.gettext
from gramps.gen.utils.symbols import Symbols
@ -1654,14 +1654,14 @@ class GrampsPreferences(ConfigureDialog):
row, 'behavior.spellcheck', start=1, stop=3,
tooltip=_("Enable the spelling checker"
" for notes."))
if not HAVE_GTKSPELL:
if not HAVE_GSPELL:
obj.set_sensitive(False)
spell_dict = {'gramps_wiki_build_spell_url':
URL_WIKISTRING +
"GEPS_029:_GTK3-GObject_introspection"
"_Conversion#Spell_Check_Install"}
obj.set_tooltip_text(
_("GtkSpell not loaded. "
_("Gspell not loaded. "
"Spell checking will not be available.\n"
"To build it for Gramps see "
"%(gramps_wiki_build_spell_url)s") % spell_dict)

View File

@ -20,8 +20,7 @@
#
"""
Provide an interface to the gtkspell interface. This requires
python-gnome-extras package. If the gtkspell package is not
Provide an interface to the gspell interface. If the gspell package is not
present, we default to no spell checking.
"""
@ -45,33 +44,24 @@ LOG = logging.getLogger(".Spell")
# GTK libraries
#
#-------------------------------------------------------------------------
from gi.repository import Gtk
from gi import Repository
from gramps.gen.const import GRAMPS_LOCALE as glocale
_ = glocale.translation.gettext
HAVE_GTKSPELL = False
HAVE_GSPELL = False
# 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.
repository = Repository.get_default()
if repository.enumerate_versions("GtkSpell"):
try:
import gi
gi.require_version('GtkSpell', '3.0')
from gi.repository import GtkSpell as Gtkspell
HAVE_GTKSPELL = True
except:
pass
elif repository.enumerate_versions("Gtkspell"):
try:
import gi
gi.require_version('Gtkspell', '3.0')
from gi.repository import Gtkspell
HAVE_GTKSPELL = True
except:
pass
try:
import gi
gi.require_version('Gspell', '1')
from gi.repository import Gspell
langs = Gspell.language_get_available()
for lang in langs:
LOG.debug('%s (%s) dict available', lang.get_name(), lang.get_code())
if langs:
HAVE_GSPELL = True
else:
LOG.warning(_("You have no installed dictionaries."))
except (ImportError, ValueError):
pass
#-------------------------------------------------------------------------
#
@ -87,81 +77,47 @@ from gramps.gen.config import config
#-------------------------------------------------------------------------
class Spell:
"""Attach a gtkspell instance to the passed TextView instance.
"""Attach a Gspell instance to the passed TextView instance.
"""
_spellcheck_options = {'off': _('Off')}
if HAVE_GTKSPELL:
if HAVE_GSPELL:
_spellcheck_options['on'] = _('On')
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'
else:
self.spellcheck = 'off'
self._active_spellcheck = 'off'
self.__real_set_active_spellcheck(self.spellcheck)
# Private
def __real_set_active_spellcheck(self, spellcheck_code):
"""Set active spellcheck by its code."""
if self._active_spellcheck == 'off':
if spellcheck_code == 'off':
return
else:
try:
#transfer full GTK object, so assign to an attribute!
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
if self._active_spellcheck == spellcheck_code:
return
self.gspell_view.set_inline_spell_checking(spellcheck_code == 'on')
self.gspell_view.set_enable_language_menu(spellcheck_code == 'on')
self._active_spellcheck = spellcheck_code
# Public API

View File

@ -116,15 +116,15 @@ class LinkTag(Gtk.TextTag):
#-------------------------------------------------------------------------
#
# GtkSpellState class
# GspellState class
#
#-------------------------------------------------------------------------
class GtkSpellState:
class GspellState:
"""
A simple state machine kinda thingy.
Trying to track Gtk.Spell activities on a buffer and re-apply formatting
after Gtk.Spell replaces a misspelled word.
Trying to track Gspell activities on a buffer and re-apply formatting
after Gspell replaces a misspelled word.
"""
(STATE_NONE,
STATE_CLICKED,
@ -180,10 +180,10 @@ class GtkSpellState:
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.
Formatting found at that position used after Gtk.Spell replaces
Formatting found at that position used after Gspell replaces
misspelled words.
"""
start = textbuffer.get_iter_at_mark(mark)
@ -198,7 +198,7 @@ class GtkSpellState:
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.
"""
@ -217,7 +217,7 @@ class GtkSpellState:
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.
"""
@ -310,8 +310,8 @@ class StyledTextBuffer(UndoableBuffer):
self.linkcolor = 'blue'
# init gtkspell "state machine"
self.gtkspell_state = GtkSpellState(self)
# init gspell "state machine"
self.gspell_state = GspellState(self)
# Virtual methods
@ -385,6 +385,8 @@ class StyledTextBuffer(UndoableBuffer):
else:
value = StyledTextTagType.STYLE_DEFAULT[style]
for tname in tag_names:
if tname is None:
continue
if tname.startswith(str(style)):
value = tname.split(' ', 1)[1]
value = StyledTextTagType.STYLE_TYPE[style](value)
@ -612,6 +614,8 @@ class StyledTextBuffer(UndoableBuffer):
s_tags = []
for g_tagname, g_ranges in g_tags.items():
if g_tagname is None:
continue
if g_tagname.startswith('link'):
tag = self.get_tag_table().lookup(g_tagname)
s_ranges = [(start, end+1) for (start, end) in g_ranges]

View File

@ -402,7 +402,8 @@ class StyledTextEditor(Gtk.TextView):
self.match = self.textbuffer.match_check(iter_at_location.get_offset())
tooltip = None
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)
tooltip = self.make_tooltip_from_link(tag)
break
@ -808,7 +809,7 @@ class StyledTextEditor(Gtk.TextView):
"""
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.
"""
clear_anything = self.textbuffer.clear_selection()