Hello community,
here is the log from the commit of package rednotebook for openSUSE:Factory checked in at 2017-03-10 21:46:18
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/rednotebook (Old)
and /work/SRC/openSUSE:Factory/.rednotebook.new (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "rednotebook"
Fri Mar 10 21:46:18 2017 rev:41 rq:477814 version:1.15
Changes:
--------
--- /work/SRC/openSUSE:Factory/rednotebook/rednotebook.changes 2017-03-03 17:55:41.490573231 +0100
+++ /work/SRC/openSUSE:Factory/.rednotebook.new/rednotebook.changes 2017-03-10 21:46:18.750391598 +0100
@@ -1,0 +2,9 @@
+Fri Mar 3 20:39:34 UTC 2017 - zaitor@opensuse.org
+
+- Update to version 1.15:
+ + Bundle pygtkspellcheck 4.0.5 since earlier versions contain a
+ bug (lp#1615629).
+ + Fix toggling autostart (lp#1628497).
+ + Set system tray icon name (lp#1660129).
+
+-------------------------------------------------------------------
Old:
----
rednotebook-1.14.tar.gz
New:
----
rednotebook-1.15.tar.gz
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ rednotebook.spec ++++++
--- /var/tmp/diff_new_pack.pUcxDt/_old 2017-03-10 21:46:19.594271908 +0100
+++ /var/tmp/diff_new_pack.pUcxDt/_new 2017-03-10 21:46:19.598271342 +0100
@@ -17,7 +17,7 @@
Name: rednotebook
-Version: 1.14
+Version: 1.15
Release: 0
Summary: Graphical diary and journal
License: GPL-3.0+
++++++ rednotebook-1.14.tar.gz -> rednotebook-1.15.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/rednotebook-1.14/CHANGELOG new/rednotebook-1.15/CHANGELOG
--- old/rednotebook-1.14/CHANGELOG 2016-09-26 15:27:34.000000000 +0200
+++ new/rednotebook-1.15/CHANGELOG 2017-02-11 16:13:36.000000000 +0100
@@ -1,3 +1,8 @@
+== 1.15 (2017-02-11) ==
+* Bundle pygtkspellcheck 4.0.5 since earlier versions contain a bug (lp:1615629).
+* Fix toggling autostart (lp:1628497).
+* Set system tray icon name (lp:1660129).
+
== 1.14 (2016-09-26) ==
* Use new pygtkspellcheck API (lp:1592727).
* Fix conversion from old single "Tags" category to new tags format.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/rednotebook-1.14/PKG-INFO new/rednotebook-1.15/PKG-INFO
--- old/rednotebook-1.14/PKG-INFO 2016-09-26 15:27:34.000000000 +0200
+++ new/rednotebook-1.15/PKG-INFO 2017-02-11 16:13:36.000000000 +0100
@@ -1,6 +1,6 @@
Metadata-Version: 1.0
Name: rednotebook
-Version: 1.14
+Version: 1.15
Summary: Graphical daily journal with calendar, templates and keyword searching
Home-page: http://rednotebook.sourceforge.net
Author: Jendrik Seipp
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/rednotebook-1.14/rednotebook/external/spellcheck.py new/rednotebook-1.15/rednotebook/external/spellcheck.py
--- old/rednotebook-1.14/rednotebook/external/spellcheck.py 1970-01-01 01:00:00.000000000 +0100
+++ new/rednotebook-1.15/rednotebook/external/spellcheck.py 2017-01-20 11:18:11.000000000 +0100
@@ -0,0 +1,658 @@
+# -*- coding:utf-8 -*-
+#
+# Copyright (C) 2012, Maximilian Köhl
+# Copyright (C) 2012, Carlos Jenkins
+#
+# This program 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, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program 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 this program. If not, see http://www.gnu.org/licenses/.
+
+"""
+RedNotebook bundles its own copy of pygtkspellcheck, because pygtkspellcheck
+versions < 4.0 don't decode UTF-8 from GTK widgets. The earliest Ubuntu version
+with a fixed pygtkspellcheck (4.0.5) is 17.04 (see also
+https://bugs.launchpad.net/rednotebook/+bug/1615629).
+
+A simple but quite powerful spellchecking library written in pure Python for Gtk
+based on Enchant. It supports PyGObject as well as PyGtk for Python 2 and 3 with
+automatic switching and binding detection. For automatic translation of the user
+interface it can use Gedit’s translation files.
+"""
+
+import enchant
+import gettext
+import logging
+import re
+import sys
+
+# public objects
+__all__ = ['SpellChecker', 'NoDictionariesFound', 'NoGtkBindingFound']
+
+# logger
+logger = logging.getLogger(__name__)
+
+class NoDictionariesFound(Exception):
+ """
+ There aren't any dictionaries installed on the current system so
+ spellchecking could not work in any way.
+ """
+
+class NoGtkBindingFound(Exception):
+ """
+ Could not find any loaded Gtk binding.
+ """
+
+if sys.version_info.major == 3:
+ _py3k = True
+else:
+ _py3k = False
+
+if _py3k:
+ # there is only the gi binding for Python 3
+ from gi.repository import Gtk as gtk
+ _pygobject = True
+else:
+ # find any loaded gtk binding
+ if 'gi.repository.Gtk' in sys.modules:
+ gtk = sys.modules['gi.repository.Gtk']
+ _pygobject = True
+ elif 'gtk' in sys.modules:
+ gtk = sys.modules['gtk']
+ _pygobject = False
+ else:
+ raise NoGtkBindingFound('could not find any loaded Gtk binding')
+
+# select base list class
+try:
+ from collections import UserList
+ _list = UserList
+except ImportError:
+ _list = list
+
+
+
+# select base string
+if _py3k:
+ basestring = str
+
+# map between Gedit's translation and PyGtkSpellcheck's
+_GEDIT_MAP = {'Languages' : 'Languages',
+ 'Ignore All' : 'Ignore _All',
+ 'Suggestions' : 'Suggestions',
+ '(no suggestions)' : '(no suggested words)',
+ 'Add "{}" to Dictionary' : 'Add w_ord',
+ 'Unknown' : 'Unknown'}
+
+# translation
+if gettext.find('gedit'):
+ _gedit = gettext.translation('gedit', fallback=True).gettext
+ _ = lambda message: _gedit(_GEDIT_MAP[message]).replace('_', '')
+else:
+ locale_name = 'py{}gtkspellcheck'.format(sys.version_info.major)
+ _ = gettext.translation(locale_name, fallback=True).gettext
+
+def code_to_name(code, separator='_'):
+ # Escape underscores for GTK menuitems.
+ return code.replace(separator, separator * 2)
+
+class SpellChecker(object):
+ """
+ Main spellchecking class, everything important happens here.
+
+ :param view: GtkTextView the SpellChecker should be attached to.
+ :param language: The language which should be used for spellchecking.
+ Use a combination of two letter lower-case ISO 639 language code with a
+ two letter upper-case ISO 3166 country code, for example en_US or de_DE.
+ :param prefix: A prefix for some internal GtkTextMarks.
+ :param collapse: Enclose suggestions in its own menu.
+ :param params: Dictionary with Enchant broker parameters that should be set
+ e.g. `enchant.myspell.dictionary.path`.
+
+ .. attribute:: languages
+
+ A list of supported languages.
+
+ .. function:: exists(language)
+
+ Checks if a language exists.
+
+ :param language: language to check
+ """
+ FILTER_WORD = 'word'
+ FILTER_LINE = 'line'
+ FILTER_TEXT = 'text'
+
+ DEFAULT_FILTERS = {FILTER_WORD : [r'[0-9.,]+'],
+ FILTER_LINE : [(r'(https?|ftp|file):((//)|(\\\\))+[\w\d:'
+ r'#@%/;$()~_?+-=\\.&]+'),
+ r'[\w\d]+@[\w\d.]+'],
+ FILTER_TEXT : []}
+
+ class _LanguageList(_list):
+ def __init__(self, *args, **kwargs):
+ if sys.version_info.major == 3:
+ super().__init__(*args, **kwargs)
+ else:
+ _list.__init__(self, *args, **kwargs)
+ self.mapping = dict(self)
+
+ @classmethod
+ def from_broker(cls, broker):
+ return cls(sorted([(language, code_to_name(language))
+ for language in broker.list_languages()],
+ key=lambda language: language[1]))
+
+ def exists(self, language):
+ return language in self.mapping
+
+ class _Mark():
+ def __init__(self, buffer, name, start):
+ self._buffer = buffer
+ self._name = name
+ self._mark = self._buffer.create_mark(self._name, start, True)
+
+ @property
+ def iter(self):
+ return self._buffer.get_iter_at_mark(self._mark)
+
+ @property
+ def inside_word(self):
+ return self.iter.inside_word()
+
+ @property
+ def word(self):
+ start = self.iter
+ if not start.starts_word():
+ start.backward_word_start()
+ end = self.iter
+ if end.inside_word():
+ end.forward_word_end()
+ return start, end
+
+ def move(self, location):
+ self._buffer.move_mark(self._mark, location)
+
+ def __init__(self, view, language='en', prefix='gtkspellchecker',
+ collapse=True, params={}):
+ self._view = view
+ self.collapse = collapse
+ self._view.connect('populate-popup',
+ lambda entry, menu:self._extend_menu(menu))
+ self._view.connect('popup-menu', self._click_move_popup)
+ self._view.connect('button-press-event', self._click_move_button)
+ self._prefix = prefix
+ self._broker = enchant.Broker()
+ for param, value in params.items(): self._broker.set_param(param, value)
+ self.languages = SpellChecker._LanguageList.from_broker(self._broker)
+ if self.languages.exists(language):
+ self._language = language
+ elif self.languages.exists('en'):
+ logger.warning(('no installed dictionary for language "{}", '
+ 'fallback to english'.format(language)))
+ self._language = 'en'
+ else:
+ if self.languages:
+ self._language = self.languages[0][0]
+ logger.warning(('no installed dictionary for language "{}" '
+ 'and english, fallback to first language in'
+ 'language list ("{}")').format(language,
+ self._language))
+ else:
+ logger.critical('no dictionaries found')
+ raise NoDictionariesFound()
+ self._dictionary = self._broker.request_dict(self._language)
+ self._deferred_check = False
+ self._filters = dict(SpellChecker.DEFAULT_FILTERS)
+ self._regexes = {SpellChecker.FILTER_WORD : re.compile('|'.join(
+ self._filters[SpellChecker.FILTER_WORD])),
+ SpellChecker.FILTER_LINE : re.compile('|'.join(
+ self._filters[SpellChecker.FILTER_LINE])),
+ SpellChecker.FILTER_TEXT : re.compile('|'.join(
+ self._filters[SpellChecker.FILTER_TEXT]),
+ re.MULTILINE)}
+ self._enabled = True
+ self.buffer_initialize()
+
+ @property
+ def language(self):
+ """
+ The language used for spellchecking.
+ """
+ return self._language
+
+ @language.setter
+ def language(self, language):
+ if language != self._language and self.languages.exists(language):
+ self._language = language
+ self._dictionary = self._broker.request_dict(language)
+ self.recheck()
+
+ @property
+ def enabled(self):
+ """
+ Enable or disable spellchecking.
+ """
+ return self._enabled
+
+ @enabled.setter
+ def enabled(self, enabled):
+ if enabled and not self._enabled:
+ self.enable()
+ elif not enabled and self._enabled:
+ self.disable()
+
+ def buffer_initialize(self):
+ """
+ Initialize the GtkTextBuffer associated with the GtkTextView. If you
+ have associated a new GtkTextBuffer with the GtkTextView call this
+ method.
+ """
+ if _pygobject:
+ self._misspelled = gtk.TextTag.new('{}-misspelled'\
+ .format(self._prefix))
+ else:
+ self._misspelled = gtk.TextTag('{}-misspelled'.format(self._prefix))
+ self._misspelled.set_property('underline', 4)
+ self._buffer = self._view.get_buffer()
+ self._buffer.connect('insert-text', self._before_text_insert)
+ self._buffer.connect_after('insert-text', self._after_text_insert)
+ self._buffer.connect_after('delete-range', self._range_delete)
+ self._buffer.connect_after('mark-set', self._mark_set)
+ start = self._buffer.get_bounds()[0]
+ self._marks = {'insert-start' : SpellChecker._Mark(self._buffer,
+ '{}-insert-start'.format(self._prefix), start),
+ 'insert-end' : SpellChecker._Mark(self._buffer,
+ '{}-insert-end'.format(self._prefix), start),
+ 'click' : SpellChecker._Mark(self._buffer,
+ '{}-click'.format(self._prefix), start)}
+ self._table = self._buffer.get_tag_table()
+ self._table.add(self._misspelled)
+ self.ignored_tags = []
+ def tag_added(tag, *args):
+ if hasattr(tag, 'spell_check') and not getattr(tag, 'spell_check'):
+ self.ignored_tags.append(tag)
+ def tag_removed(tag, *args):
+ if tag in self.ignored_tags:
+ self.ignored_tags.remove(tag)
+ self._table.connect('tag-added', tag_added)
+ self._table.connect('tag-removed', tag_removed)
+ self._table.foreach(tag_added, None)
+ self.no_spell_check = self._table.lookup('no-spell-check')
+ if not self.no_spell_check:
+ if _pygobject:
+ self.no_spell_check = gtk.TextTag.new('no-spell-check')
+ else:
+ self.no_spell_check = gtk.TextTag('no-spell-check')
+ self._table.add(self.no_spell_check)
+ self.recheck()
+
+ def recheck(self):
+ """
+ Rechecks the spelling of the whole text.
+ """
+ start, end = self._buffer.get_bounds()
+ self.check_range(start, end, True)
+
+ def disable(self):
+ """
+ Disable spellchecking.
+ """
+ self._enabled = False
+ start, end = self._buffer.get_bounds()
+ self._buffer.remove_tag(self._misspelled, start, end)
+
+ def enable(self):
+ """
+ Enable spellchecking.
+ """
+ self._enabled = True
+ self.recheck()
+
+ def append_filter(self, regex, filter_type):
+ """
+ Append a new filter to the filter list. Filters are useful to ignore
+ some misspelled words based on regular expressions.
+
+ :param regex: The regex used for filtering.
+ :param filter_type: The type of the filter.
+
+ Filter Types:
+
+ :const:`SpellChecker.FILTER_WORD`: The regex must match the whole word
+ you want to filter. The word separation is done by Pango's word
+ separation algorithm so, for example, urls won't work here because
+ they are split in many words.
+
+ :const:`SpellChecker.FILTER_LINE`: If the expression you want to match
+ is a single line expression use this type. It should not be an open
+ end expression because then the rest of the line with the text you
+ want to filter will become correct.
+
+ :const:`SpellChecker.FILTER_TEXT`: Use this if you want to filter
+ multiline expressions. The regex will be compiled with the
+ `re.MULTILINE` flag. Same with open end expressions apply here.
+ """
+ self._filters[filter_type].append(regex)
+ if filter_type == SpellChecker.FILTER_TEXT:
+ self._regexes[filter_type] = re.compile('|'.join(
+ self._filters[filter_type]), re.MULTILINE)
+ else:
+ self._regexes[filter_type] = re.compile('|'.join(
+ self._filters[filter_type]))
+
+ def remove_filter(self, regex, filter_type):
+ """
+ Remove a filter from the filter list.
+
+ :param regex: The regex which used for filtering.
+ :param filter_type: The type of the filter.
+ """
+ self._filters[filter_type].remove(regex)
+ if filter_type == SpellChecker.FILTER_TEXT:
+ self._regexes[filter_type] = re.compile('|'.join(
+ self._filters[filter_type]), re.MULTILINE)
+ else:
+ self._regexes[filter_type] = re.compile('|'.join(
+ self._filters[filter_type]))
+
+ def append_ignore_tag(self, tag):
+ """
+ Appends a tag to the list of ignored tags. A string will be automatic
+ resolved into a tag object.
+
+ :param tag: Tag object or tag name.
+ """
+ if isinstance(tag, basestring):
+ tag = self._table.lookup(tag)
+ self.ignored_tags.append(tag)
+
+ def remove_ignore_tag(self, tag):
+ """
+ Removes a tag from the list of ignored tags. A string will be automatic
+ resolved into a tag object.
+
+ :param tag: Tag object or tag name.
+ """
+ if isinstance(tag, basestring):
+ tag = self._table.lookup(tag)
+ self.ignored_tags.remove(tag)
+
+ def add_to_dictionary(self, word):
+ """
+ Adds a word to user's dictionary.
+
+ :param word: The word to add.
+ """
+ self._dictionary.add_to_pwl(word)
+ self.recheck()
+
+ def ignore_all(self, word):
+ """
+ Ignores a word for the current session.
+
+ :param word: The word to ignore.
+ """
+ self._dictionary.add_to_session(word)
+ self.recheck()
+
+ def check_range(self, start, end, force_all=False):
+ """
+ Checks a specified range between two GtkTextIters.
+
+ :param start: Start iter - checking starts here.
+ :param end: End iter - checking ends here.
+ """
+ if not self._enabled:
+ return
+ if end.inside_word(): end.forward_word_end()
+ if not start.starts_word() and (start.inside_word() or
+ start.ends_word()):
+ start.backward_word_start()
+ self._buffer.remove_tag(self._misspelled, start, end)
+ cursor = self._buffer.get_iter_at_mark(self._buffer.get_insert())
+ precursor = cursor.copy()
+ precursor.backward_char()
+ highlight = (cursor.has_tag(self._misspelled) or
+ precursor.has_tag(self._misspelled))
+ if not start.get_offset():
+ start.forward_word_end()
+ start.backward_word_start()
+ word_start = start.copy()
+ while word_start.compare(end) < 0:
+ word_end = word_start.copy()
+ word_end.forward_word_end()
+ in_word = ((word_start.compare(cursor) < 0) and
+ (cursor.compare(word_end) <= 0))
+ if in_word and not force_all:
+ if highlight:
+ self._check_word(word_start, word_end)
+ else:
+ self._deferred_check = True
+ else:
+ self._check_word(word_start, word_end)
+ self._deferred_check = False
+ word_end.forward_word_end()
+ word_end.backward_word_start()
+ if word_start.equal(word_end):
+ break
+ word_start = word_end.copy()
+
+ def _languages_menu(self):
+ def _set_language(item, code):
+ self.language = code
+ if _pygobject:
+ menu = gtk.Menu.new()
+ group = []
+ else:
+ menu = gtk.Menu()
+ group = gtk.RadioMenuItem()
+ connect = []
+ for code, name in self.languages:
+ if _pygobject:
+ item = gtk.RadioMenuItem.new_with_label(group, name)
+ group.append(item)
+ else:
+ item = gtk.RadioMenuItem(group, name)
+ if code == self.language:
+ item.set_active(True)
+ connect.append((item, code))
+ menu.append(item)
+ for item, code in connect:
+ item.connect('activate', _set_language, code)
+ return menu
+
+ def _suggestion_menu(self, word):
+ menu = []
+ suggestions = self._dictionary.suggest(word)
+ if not suggestions:
+ if _pygobject:
+ item = gtk.MenuItem.new()
+ label = gtk.Label.new('')
+ else:
+ item = gtk.MenuItem()
+ label = gtk.Label()
+ try:
+ label.set_halign(gtk.Align.LEFT)
+ except AttributeError:
+ label.set_alignment(0.0, 0.5)
+ label.set_markup('<i>{text}</i>'.format(text=_('(no suggestions)')))
+ item.add(label)
+ menu.append(item)
+ else:
+ for suggestion in suggestions:
+ if _pygobject:
+ item = gtk.MenuItem.new()
+ label = gtk.Label.new('')
+ else:
+ item = gtk.MenuItem()
+ label = gtk.Label()
+ label.set_markup('<b>{text}</b>'.format(text=suggestion))
+ try:
+ label.set_halign(gtk.Align.LEFT)
+ except AttributeError:
+ label.set_alignment(0.0, 0.5)
+ item.add(label)
+ item.connect('activate', self._replace_word, word, suggestion)
+ menu.append(item)
+ if _pygobject:
+ menu.append(gtk.SeparatorMenuItem.new())
+ item = gtk.MenuItem.new_with_label(
+ _('Add "{}" to Dictionary').format(word))
+ else:
+ menu.append(gtk.SeparatorMenuItem())
+ item = gtk.MenuItem(_('Add "{}" to Dictionary').format(word))
+ item.connect('activate', lambda *args: self.add_to_dictionary(word))
+ menu.append(item)
+ if _pygobject:
+ item = gtk.MenuItem.new_with_label(_('Ignore All'))
+ else:
+ item = gtk.MenuItem(_('Ignore All'))
+ item.connect('activate', lambda *args: self.ignore_all(word))
+ menu.append(item)
+ return menu
+
+ def _extend_menu(self, menu):
+ if not self._enabled:
+ return
+ if _pygobject:
+ separator = gtk.SeparatorMenuItem.new()
+ else:
+ separator = gtk.SeparatorMenuItem()
+ separator.show()
+ menu.prepend(separator)
+ if _pygobject:
+ languages = gtk.MenuItem.new_with_label(_('Languages'))
+ else:
+ languages = gtk.MenuItem(_('Languages'))
+ languages.set_submenu(self._languages_menu())
+ languages.show_all()
+ menu.prepend(languages)
+ if self._marks['click'].inside_word:
+ start, end = self._marks['click'].word
+ if start.has_tag(self._misspelled):
+ if _py3k:
+ word = self._buffer.get_text(start, end, False)
+ else:
+ word = self._buffer.get_text(start, end,
+ False).decode('utf-8')
+ items = self._suggestion_menu(word)
+ if self.collapse:
+ if _pygobject:
+ suggestions = gtk.MenuItem.new_with_label(
+ _('Suggestions'))
+ submenu = gtk.Menu.new()
+ else:
+ suggestions = gtk.MenuItem(_('Suggestions'))
+ submenu = gtk.Menu()
+ for item in items:
+ submenu.append(item)
+ suggestions.set_submenu(submenu)
+ suggestions.show_all()
+ menu.prepend(suggestions)
+ else:
+ items.reverse()
+ for item in items:
+ menu.prepend(item)
+ menu.show_all()
+
+ def _click_move_popup(self, *args):
+ self._marks['click'].move(self._buffer.get_iter_at_mark(
+ self._buffer.get_insert()))
+ return False
+
+ def _click_move_button(self, widget, event):
+ if event.button == 3:
+ if self._deferred_check: self._check_deferred_range(True)
+ x, y = self._view.window_to_buffer_coords(2, int(event.x),
+ int(event.y))
+ iter = self._view.get_iter_at_location(x, y)
+ if isinstance(iter, tuple):
+ iter = iter[1]
+ self._marks['click'].move(iter)
+ return False
+
+ def _before_text_insert(self, textbuffer, location, text, length):
+ self._marks['insert-start'].move(location)
+
+ def _after_text_insert(self, textbuffer, location, text, length):
+ start = self._marks['insert-start'].iter
+ self.check_range(start, location)
+ self._marks['insert-end'].move(location)
+
+ def _range_delete(self, textbuffer, start, end):
+ self.check_range(start, end)
+
+ def _mark_set(self, textbuffer, location, mark):
+ if mark == self._buffer.get_insert() and self._deferred_check:
+ self._check_deferred_range(False)
+
+ def _replace_word(self, item, old_word, new_word):
+ start, end = self._marks['click'].word
+ offset = start.get_offset()
+ self._buffer.begin_user_action()
+ self._buffer.delete(start, end)
+ self._buffer.insert(self._buffer.get_iter_at_offset(offset), new_word)
+ self._buffer.end_user_action()
+ self._dictionary.store_replacement(old_word, new_word)
+
+ def _check_deferred_range(self, force_all):
+ start = self._marks['insert-start'].iter
+ end = self._marks['insert-end'].iter
+ self.check_range(start, end, force_all)
+
+ def _check_word(self, start, end):
+ if start.has_tag(self.no_spell_check):
+ return
+ for tag in self.ignored_tags:
+ if start.has_tag(tag):
+ return
+ if _py3k:
+ word = self._buffer.get_text(start, end, False).strip()
+ else:
+ word = self._buffer.get_text(start, end, False).decode('utf-8').strip()
+ if not word:
+ return
+ if len(self._filters[SpellChecker.FILTER_WORD]):
+ if self._regexes[SpellChecker.FILTER_WORD].match(word):
+ return
+ if len(self._filters[SpellChecker.FILTER_LINE]):
+ line_start = self._buffer.get_iter_at_line(start.get_line())
+ line_end = end.copy()
+ line_end.forward_to_line_end()
+ if _py3k:
+ line = self._buffer.get_text(line_start, line_end, False)
+ else:
+ line = self._buffer.get_text(line_start, line_end,
+ False).decode('utf-8')
+ for match in self._regexes[SpellChecker.FILTER_LINE].finditer(line):
+ if match.start() <= start.get_line_offset() <= match.end():
+ start = self._buffer.get_iter_at_line_offset(
+ start.get_line(), match.start())
+ end = self._buffer.get_iter_at_line_offset(start.get_line(),
+ match.end())
+ self._buffer.remove_tag(self._misspelled, start, end)
+ return
+ if len(self._filters[SpellChecker.FILTER_TEXT]):
+ text_start, text_end = self._buffer.get_bounds()
+ if _py3k:
+ text = self._buffer.get_text(text_start, text_end, False)
+ else:
+ text = self._buffer.get_text(text_start, text_end,
+ False).decode('utf-8')
+ for match in self._regexes[SpellChecker.FILTER_TEXT].finditer(text):
+ if match.start() <= start.get_offset() <= match.end():
+ start = self._buffer.get_iter_at_offset(match.start())
+ end = self._buffer.get_iter_at_offset(match.end())
+ self._buffer.remove_tag(self._misspelled, start, end)
+ return
+ if not self._dictionary.check(word):
+ self._buffer.apply_tag(self._misspelled, start, end)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/rednotebook-1.14/rednotebook/gui/editor.py new/rednotebook-1.15/rednotebook/gui/editor.py
--- old/rednotebook-1.14/rednotebook/gui/editor.py 2016-09-26 13:58:58.000000000 +0200
+++ new/rednotebook-1.15/rednotebook/gui/editor.py 2017-01-20 11:06:28.000000000 +0100
@@ -24,17 +24,17 @@
import gtk
import pango
-try:
- import gtkspellcheck
-except ImportError:
- logging.warning(
- 'For spell checking, please install pygtkspellcheck (python-gtkspellcheck).')
- gtkspellcheck = None
-
from rednotebook.gui import t2t_highlight
from rednotebook import undo
from rednotebook.util import filesystem
+try:
+ from rednotebook.external import spellcheck
+except ImportError:
+ logging.warning(
+ 'For spell checking, please install enchant (python-enchant).')
+ spellcheck = None
+
DEFAULT_FONT = gtk.settings_get_default().get_property('gtk-font-name')
@@ -268,10 +268,10 @@
def can_spell_check(self):
"""Return True if spell checking is available."""
- return gtkspellcheck is not None
+ return spellcheck is not None
def is_spell_check_enabled(self):
- return self._spell_checker and self._spell_checker.enabled
+ return bool(self._spell_checker and self._spell_checker.enabled)
def _enable_spell_check(self):
assert self.can_spell_check()
@@ -279,10 +279,11 @@
self._spell_checker.enable()
else:
try:
- self._spell_checker = gtkspellcheck.SpellChecker(
+ self._spell_checker = spellcheck.SpellChecker(
self.day_text_view, filesystem.LANGUAGE)
- # TODO: Find out which exceptions can be thrown here. Seems to
- # depend on the library version.
+ except spellcheck.NoDictionariesFound:
+ logging.warning('No spell checking dictionaries found.')
+ self._spell_checker = None
except Exception as err:
logging.error(
'Spell checking could not be enabled. %s: %s' %
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/rednotebook-1.14/rednotebook/gui/main_window.py new/rednotebook-1.15/rednotebook/gui/main_window.py
--- old/rednotebook-1.14/rednotebook/gui/main_window.py 2016-07-14 16:27:00.000000000 +0200
+++ new/rednotebook-1.15/rednotebook/gui/main_window.py 2017-01-29 13:59:47.000000000 +0100
@@ -242,6 +242,11 @@
def setup_tray_icon(self):
self.tray_icon = gtk.StatusIcon()
+ try:
+ # Available in PyGTK >= 2.22
+ self.tray_icon.set_name('RedNotebook')
+ except AttributeError:
+ pass
visible = (self.journal.config.read('closeToTray') == 1)
self.tray_icon.set_visible(visible)
logging.debug('Tray icon visible: %s' % visible)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/rednotebook-1.14/rednotebook/gui/options.py new/rednotebook-1.15/rednotebook/gui/options.py
--- old/rednotebook-1.14/rednotebook/gui/options.py 2016-03-28 21:43:27.000000000 +0200
+++ new/rednotebook-1.15/rednotebook/gui/options.py 2017-01-18 21:30:56.000000000 +0100
@@ -82,7 +82,7 @@
class AutostartOption(TickOption):
def __init__(self):
self.autostart_file = os.path.expanduser(
- '~.config/autostart/rednotebook.desktop')
+ '~/.config/autostart/rednotebook.desktop')
autostart_file_exists = os.path.exists(self.autostart_file)
TickOption.__init__(
self, _('Load RedNotebook at startup'), None, value=autostart_file_exists)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/rednotebook-1.14/rednotebook/info.py new/rednotebook-1.15/rednotebook/info.py
--- old/rednotebook-1.14/rednotebook/info.py 2016-09-26 15:27:32.000000000 +0200
+++ new/rednotebook-1.15/rednotebook/info.py 2017-02-11 16:13:25.000000000 +0100
@@ -26,7 +26,7 @@
return string
-version = '1.14'
+version = '1.15'
author = 'Jendrik Seipp'
author_mail = 'jendrikseipp@web.de'
url = 'http://rednotebook.sourceforge.net'