StyledText.join method fails if the joint_text has StyledText Tags (#457)

fixes #10192
This commit is contained in:
Paul Culley 2017-09-16 19:48:42 -05:00 committed by Sam Manzi
parent fe45742c21
commit af975e926f
2 changed files with 102 additions and 6 deletions

View File

@ -27,6 +27,7 @@
# Gramps modules # Gramps modules
# #
#------------------------------------------------------------------------- #-------------------------------------------------------------------------
from copy import copy
from .styledtexttag import StyledTextTag from .styledtexttag import StyledTextTag
from ..const import GRAMPS_LOCALE as glocale from ..const import GRAMPS_LOCALE as glocale
_ = glocale.translation.gettext _ = glocale.translation.gettext
@ -77,6 +78,8 @@ class StyledText:
There could be a 'merge_tags' functionality in :py:meth:`__init__`, There could be a 'merge_tags' functionality in :py:meth:`__init__`,
however :py:class:`StyledTextBuffer` will merge them automatically if however :py:class:`StyledTextBuffer` will merge them automatically if
the text is displayed. the text is displayed.
3. Warning: Some of these operations modify the source tag ranges in place
so if you intend to use a source tag more than once, copy it for use.
""" """
(POS_TEXT, POS_TAGS) = list(range(2)) (POS_TEXT, POS_TAGS) = list(range(2))
@ -198,17 +201,27 @@ class StyledText:
new_string = self._string.join([str(string) for string in seq]) new_string = self._string.join([str(string) for string in seq])
offset = 0 offset = 0
not_first = False
new_tags = [] new_tags = []
self_len = len(self._string) self_len = len(self._string)
for text in seq: for text in seq:
if not_first: # if not first time through...
# put the joined element tag(s) into place
for tag in self.tags:
ntag = copy(tag)
ntag.ranges = [(start + offset, end + offset)
for (start, end) in tag.ranges]
new_tags += [ntag]
offset += self_len
if isinstance(text, StyledText): if isinstance(text, StyledText):
for tag in text.tags: for tag in text.tags:
tag.ranges = [(start + offset, end + offset) ntag = copy(tag)
for (start, end) in tag.ranges] ntag.ranges = [(start + offset, end + offset)
new_tags += [tag] for (start, end) in tag.ranges]
new_tags += [ntag]
offset = offset + len(str(text)) + self_len offset += len(str(text))
not_first = True
return self.__class__(new_string, new_tags) return self.__class__(new_string, new_tags)
@ -366,6 +379,7 @@ if __name__ == '__main__':
from .styledtexttagtype import StyledTextTagType from .styledtexttagtype import StyledTextTagType
T1 = StyledTextTag(StyledTextTagType(1), 'v1', [(0, 2), (2, 4), (4, 6)]) T1 = StyledTextTag(StyledTextTagType(1), 'v1', [(0, 2), (2, 4), (4, 6)])
T2 = StyledTextTag(StyledTextTagType(2), 'v2', [(1, 3), (3, 5), (0, 7)]) T2 = StyledTextTag(StyledTextTagType(2), 'v2', [(1, 3), (3, 5), (0, 7)])
T3 = StyledTextTag(StyledTextTagType(0), 'v3', [(0, 1)])
A = StyledText('123X456', [T1]) A = StyledText('123X456', [T1])
B = StyledText("abcXdef", [T2]) B = StyledText("abcXdef", [T2])
@ -376,7 +390,7 @@ if __name__ == '__main__':
C = C.join([A, S, B]) C = C.join([A, S, B])
L = C.split() L = C.split()
C = C.replace('X', StyledText('_')) C = C.replace('X', StyledText('_', [T3]))
A = A + B A = A + B
print(A) print(A)

View File

@ -0,0 +1,82 @@
#
# Gramps - a GTK+/GNOME based genealogy program
#
# Copyright (C) 2017 Paul Culley
#
# 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 2 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, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
#
""" unittest for styledtext """
import unittest
from copy import deepcopy
from ..styledtext import StyledText
from ..styledtexttag import StyledTextTag
from ..styledtexttagtype import StyledTextTagType
class Test1(unittest.TestCase):
T1 = StyledTextTag(StyledTextTagType(1), 'v1', [(0, 2), (2, 4), (4, 6)])
T2 = StyledTextTag(StyledTextTagType(2), 'v2', [(1, 3), (3, 5), (0, 7)])
T3 = StyledTextTag(StyledTextTagType(0), 'v3', [(0, 1)])
T4 = StyledTextTag(StyledTextTagType(2), 'v2',
[(8, 10), (10, 12), (7, 14)])
T5 = StyledTextTag(StyledTextTagType(2), 'v2',
[(19, 21), (21, 23), (18, 25)])
A = StyledText('123X456', [T1])
B = StyledText("abcXdef", [T2])
C = StyledText('\n')
S = 'cleartext'
# some basic tests
# because the StyledText.__eq__ method doesn't work very well (tags don't
# compare when they are equivalent, but not equal) we have to use
# serialize for comparisons.
def test_join(self):
C = self.C.join([self.A, self.S, deepcopy(self.B)])
_C = StyledText('123X456\ncleartext\nabcXdef', [self.T1, self.T5])
self.assertEqual(C.serialize(), _C.serialize())
def test_split(self):
C = self.C.join([self.A, self.S, deepcopy(self.B)])
L = C.split()
_L = [self.A, self.S, self.B]
self.assertEqual(L[0].serialize(), self.A.serialize())
self.assertEqual(str(L[1]), self.S)
self.assertEqual(L[2].serialize(), self.B.serialize())
def test_replace(self):
C = self.C.join([self.A, self.S, deepcopy(self.B)])
C = C.replace('X', StyledText('_', [self.T3]))
_C = ('123_456\ncleartext\nabc_def',
[((1, ''), 'v1', [(0, 2), (2, 3)]),
((0, ''), 'v3', [(3, 4)]),
((1, ''), 'v1', [(4, 6)]),
((2, ''), 'v2', [(19, 21), (18, 21)]),
((0, ''), 'v3', [(21, 22)]),
((2, ''), 'v2', [(22, 23), (22, 25)])])
self.assertEqual(C.serialize(), _C)
def test_add(self):
A = deepcopy(self.A) + deepcopy(self.B)
_A = StyledText('123X456abcXdef', [self.T1, self.T4])
self.assertEqual(A.serialize(), _A.serialize())
if __name__ == "__main__":
unittest.main()