2007-02-12 Zsolt Foldvari <zfoldvar@users.sourceforge.net>

* src/MarkupText.py: improvements
	* src/RelLib/_Note.py (get): try to remove tags only if note is
	formatted
	* src/DisplayTabs/_NoteTab.py: cleanup



svn: r8092
This commit is contained in:
Zsolt Foldvari 2007-02-12 19:53:30 +00:00
parent 9c64624930
commit 4f390df00d
4 changed files with 366 additions and 447 deletions

View File

@ -1,3 +1,9 @@
2007-02-12 Zsolt Foldvari <zfoldvar@users.sourceforge.net>
* src/MarkupText.py: improvements
* src/RelLib/_Note.py (get): try to remove tags only if note is
formatted
* src/DisplayTabs/_NoteTab.py: cleanup
2007-02-11 Brian Matherly <brian@gramps-project.org>
* src/BaseDoc.py: remove write_at
* src/docgen/PSDrawDoc.py: remove write_at
@ -28,25 +34,6 @@
* src/GrampsDbUtils/Makefile.am: new GEDCOM parser module
* src/ArgHandler.py: new GEDCOM parser module
* example/gedcom/sample.ged: added test cases
2007-02-11 Don Allingham <don@gramps-project.org>
* src/Merge/_MergePlace.py (MergePlaces.merge): fix typo on
add_source_reference
2007-02-07 Zsolt Foldvari <zfoldvar@users.sourceforge.net>
* src/DisplayTabs/_NoteTab.py: move "rich text" notes to 2.3 branch.
2007-02-06 Brian Matherly <brian@gramps-project.org>
* src/docgen/PdfDoc.py: provide a more useful error when reportlab crashes
2007-02-06 Douglas Blank <dblank@cs.brynmawr.edu>
* src/ReportBase/_ReportDialog.py: 0000905: Typo in catching exceptions in
buggy reports
* src/plugins/holidays.xml: 0000906: Canada holidays patch
2007-02-06 Don Allingham <don@gramps-project.org>
* src/GrampsDb/_ReadGedcom.py: fix cal/est parsing
* src/DisplayTabs/_ButtonTab.py: catch window already being open
* example/gedcom/sample.ged: Add est/cal samples
2007-02-10 Brian Matherly <brian@gramps-project.org>
* src/BaseDoc.py: remove unused functions

View File

@ -119,9 +119,9 @@ class NoteTab(GrampsTab):
self.buf = EditorBuffer()
self.text.set_buffer(self.buf)
tooltips = gtk.Tooltips()
for tip,stock,font in [('Italic',gtk.STOCK_ITALIC,'<i>italic</i>'),
('Bold',gtk.STOCK_BOLD,'<b>bold</b>'),
('Underline',gtk.STOCK_UNDERLINE,'<u>underline</u>'),
for tip,stock,font in [('Italic',gtk.STOCK_ITALIC,'<i>i</i>'),
('Bold',gtk.STOCK_BOLD,'<b>b</b>'),
('Underline',gtk.STOCK_UNDERLINE,'<u>u</u>'),
]:
button = gtk.ToggleButton()
image = gtk.Image()
@ -129,14 +129,12 @@ class NoteTab(GrampsTab):
button.set_image(image)
tooltips.set_tip(button, tip)
button.set_relief(gtk.RELIEF_NONE)
self.buf.setup_widget_from_pango(button,font)
self.buf.setup_widget_from_xml(button,font)
hbox.pack_start(button, False)
##self.buf = self.text.get_buffer()
if self.note_obj:
self.empty = False
self.buf.set_text(self.note_obj.get(markup=True))
log.debug("Text: %s" % self.buf.get_text())
##self.buf.insert_at_cursor(self.note_obj.get())
#log.debug("Text: %s" % self.buf.get_text())
else:
self.empty = True

View File

@ -25,8 +25,13 @@
# Python classes
#
#-------------------------------------------------------------------------
from xml.sax import saxutils, xmlreader
from cStringIO import StringIO
from xml.sax import saxutils, xmlreader, ContentHandler
from xml.sax import parseString, SAXParseException
import re
try:
from cStringIO import StringIO
except:
from StringIO import StringIO
#-------------------------------------------------------------------------
#
@ -49,31 +54,142 @@ import pango
# Constants
#
#-------------------------------------------------------------------------
(EVENT_START,
EVENT_END) = range(2)
class MarkupParser(ContentHandler):
"""A simple ContentHandler class to parse Gramps markup'ed text.
Use it with xml.sax.parse() or xml.sax.parseString().
Parsing result can be obtained via it's public attributes.
@attr content: clean text
@attr type: str
@attr elements: list of markup elements
@attr type: list[tuple((start, end), name, attrs),]
"""
(EVENT_START,
EVENT_END) = range(2)
class NoteXMLWriter(saxutils.XMLGenerator):
def startDocument(self):
self._open_document = False
self._open_elements = []
self.elements = []
self.content = ""
def endDocument(self):
self._open_document = False
def startElement(self, name, attrs):
if not self._open_document:
if name == 'gramps':
self._open_document = True
else:
raise SAXParseException('Root tag missing')
else:
self._open_elements.append({'name': name,
'attrs': attrs.copy(),
'start': len(self.content),
})
def endElement(self, name):
# skip root element
if name == 'gramps':
return
for e in self._open_elements:
if e['name'] == name:
self.elements.append(((e['start'], len(self.content)),
e['name'], e['attrs']))
self._open_elements.remove(e)
return
def characters (self, chunk):
self.content += chunk
class MarkupWriter:
"""Generate XML markup text for Notes.
Provides additional feature of accounting opened tags and closing them
properly in case of partialy overlapping markups.
properly in case of partially overlapping markups.
It is assumed that 'start name' and 'end name' are equal (e.g. <b>, </b>).
"""
def __init__(self, output, encoding):
saxutils.XMLGenerator.__init__(self, output, encoding)
self.attrs = xmlreader.AttributesImpl({})
#saxutils.XMLGenerator.startElement(self, u'gramps', self.attrs)
self.open_elements = []
def startElement(self, name, attrs=None):
if not attrs:
attrs = self.attrs
saxutils.XMLGenerator.startElement(self, name, attrs)
self.open_elements.append(name)
def __init__(self, encoding='utf-8'):
self._output = StringIO()
self._encoding = encoding
self._writer = saxutils.XMLGenerator(self._output, self._encoding)
def endElement(self, name):
if not len(self.open_elements):
self._attrs = xmlreader.AttributesImpl({})
self._open_elements = []
self.content = ''
# Private
def _elements_to_events(self, elements):
"""Create an event list for XML writer.
@param tagdict: dictionary of tags with start and end indices
@param type: {TextTag: [(start, end),]}
@return: eventdict
@rtype: {index: [(TextTag, event_type, pair_index),]}
index: place of the event
TextTag: tag to apply
event_type: START or END event
pair_index: index of the pair event, used for sorting
"""
eventdict = {}
for (start, end), name, attrs in elements:
# insert START events
if eventdict.has_key(start):
eventdict[start].append((name, MarkupParser.EVENT_START, end))
else:
eventdict[start] = [(name, MarkupParser.EVENT_START, end)]
# insert END events
if eventdict.has_key(end):
eventdict[end].append((name, MarkupParser.EVENT_END, start))
else:
eventdict[end] = [(name, MarkupParser.EVENT_END, start)]
# sort events at the same index
indices = eventdict.keys()
for idx in indices:
if len(eventdict[idx]) > 1:
eventdict[idx].sort(self._sort_events)
return eventdict
def _sort_events(self, event_a, event_b):
"""Sort events that are at the same index.
Sorting with the following rules:
1. END event goes always before START event;
2. from two START events the one goes first, which has it's own END
event later;
3. from two END events the one goes first, which has it's own START
event later.
"""
tag_a, type_a, pair_a = event_a
tag_b, type_b, pair_b = event_b
if (type_a + type_b) == (MarkupParser.EVENT_START +
MarkupParser.EVENT_END):
return type_b - type_a
else:
return pair_b - pair_a
def _startElement(self, name, attrs=None):
"""Insert start tag."""
if not attrs:
attrs = self._attrs
self._writer.startElement(name, attrs)
self._open_elements.append(name)
def _endElement(self, name):
"""Insert end tag."""
if not len(self._open_elements):
log.debug("Trying to close element '%s' when non is open" % name)
return
@ -83,8 +199,8 @@ class NoteXMLWriter(saxutils.XMLGenerator):
# close all open elements until we reach to the requested one
while elem != name:
try:
elem = self.open_elements.pop()
saxutils.XMLGenerator.endElement(self, elem)
elem = self._open_elements.pop()
self._writer.endElement(elem)
if elem != name:
tmp_list.append(elem)
except:
@ -96,245 +212,133 @@ class NoteXMLWriter(saxutils.XMLGenerator):
while True:
try:
elem = tmp_list.pop()
self.startElement(elem)
self._startElement(elem)
except:
break
def close(self):
#saxutils.XMLGenerator.endElement(self, u'gramps')
self.endDocument()
# Public
def generate(self, text, elements):
# reset output and start root element
self._output.seek(0)
self._writer.startElement('gramps', self._attrs)
# split the elements to events
events = self._elements_to_events(elements)
# feed the events into the xml generator
last_pos = 0
indices = events.keys()
indices.sort()
for index in indices:
self._writer.characters(text[last_pos:index])
for name, event_type, p in events[index]:
if event_type == MarkupParser.EVENT_START:
self._startElement(name)
elif event_type == MarkupParser.EVENT_END:
self._endElement(name)
last_pos = index
self._writer.characters(text[last_pos:])
# close root element and end doc
self._writer.endElement('gramps')
self._writer.endDocument()
# copy result
self.content = self._output.getvalue()
class MarkupBuffer(gtk.TextBuffer):
fontdesc_to_attr_table = {
'family': [pango.AttrFamily, ""],
'style': [pango.AttrStyle, pango.STYLE_NORMAL],
'variant': [pango.AttrVariant, pango.VARIANT_NORMAL],
'weight': [pango.AttrWeight, pango.WEIGHT_NORMAL],
'stretch': [pango.AttrStretch, pango.STRETCH_NORMAL],
}
pango_translation_properties = {
# pango ATTR TYPE : (pango attr property / tag property)
pango.ATTR_SIZE : 'size',
pango.ATTR_WEIGHT: 'weight',
pango.ATTR_UNDERLINE: 'underline',
pango.ATTR_STRETCH: 'stretch',
pango.ATTR_VARIANT: 'variant',
pango.ATTR_STYLE: 'style',
pango.ATTR_SCALE: 'scale',
pango.ATTR_STRIKETHROUGH: 'strikethrough',
pango.ATTR_RISE: 'rise',
}
attval_to_markup = {
'underline': {pango.UNDERLINE_SINGLE: 'single',
pango.UNDERLINE_DOUBLE: 'double',
pango.UNDERLINE_LOW: 'low',
pango.UNDERLINE_NONE: 'none'
},
'stretch': {pango.STRETCH_ULTRA_EXPANDED: 'ultraexpanded',
pango.STRETCH_EXPANDED: 'expanded',
pango.STRETCH_EXTRA_EXPANDED: 'extraexpanded',
pango.STRETCH_EXTRA_CONDENSED: 'extracondensed',
pango.STRETCH_ULTRA_CONDENSED: 'ultracondensed',
pango.STRETCH_CONDENSED: 'condensed',
pango.STRETCH_NORMAL: 'normal',
},
'variant': {pango.VARIANT_NORMAL: 'normal',
pango.VARIANT_SMALL_CAPS: 'smallcaps',
},
'style': {pango.STYLE_NORMAL: 'normal',
pango.STYLE_OBLIQUE: 'oblique',
pango.STYLE_ITALIC: 'italic',
},
'stikethrough': {1: 'true',
True: 'true',
0: 'false',
False: 'false'
},
}
# This is an ugly workaround until we get rid of pango
# only these markups are curently supported
pango_shortcut = {
'style2': 'i',
"""An extended TextBuffer with Gramps XML markup string interface.
It implements MarkupParser and MarkupWriter on the input/output interface.
Also translates Gramps XML markup language to gtk.TextTag's and vice versa.
"""
texttag_to_xml = {
'weight700': 'b',
'style2': 'i',
'underline1': 'u',
}
xml_to_texttag = {
'b': ('weight', 700),
'i': ('style', 2),
'u': ('underline', 1),
}
def __init__(self):
self.tagdict = {}
self.parser = MarkupParser()
self.writer = MarkupWriter()
self.tags = {}
self.tag_markup = {}
gtk.TextBuffer.__init__(self)
def set_text(self, pango_text):
def set_text(self, xmltext):
"""Set the content of the buffer with markup tags"""
try:
attrlist, text, accel = pango.parse_markup(pango_text, u'\x00')
parseString(xmltext, self.parser)
text = self.parser.content
except:
log.debug('Escaping text, we seem to have a problem here!')
escaped_text = saxutils.escape(pango_text)
attrlist, text, accel = pango.parse_markup(escaped_text, u'\x00')
# if parse fails remove all tags and use clear text instead
text = re.sub(r'(<.*?>)', '', xmltext)
text = saxutils.unescape(text)
gtk.TextBuffer.set_text(self, text)
attriter = attrlist.get_iterator()
self.add_iter_to_buffer(attriter)
while attriter.next():
self.add_iter_to_buffer(attriter)
for element in self.parser.elements:
self.add_element_to_buffer(element)
def add_iter_to_buffer(self, attriter):
"""Insert attributes into the buffer.
def add_element_to_buffer(self, elem):
"""Apply the xml element to the buffer"""
(start, end), name, attrs = elem
tag = self.get_tag_from_element(name)
if tag:
start_iter = self.get_iter_at_offset(start)
end_iter = self.get_iter_at_offset(end)
self.apply_tag(tag, start_iter, end_iter)
def get_tag_from_element(self, name):
"""Convert xml element to gtk.TextTag"""
if not self.xml_to_texttag.has_key(name):
return None
prop, val = self.xml_to_texttag[name]
key = "%s%s" % (prop, val)
if not self.tags.has_key(key):
self.tags[key] = self.create_tag()
self.tags[key].set_property(prop, val)
self.tag_markup[self.tags[key]] = self.texttag_to_xml[key]
return self.tags[key]
def get_text(self, start=None, end=None, include_hidden_chars=True):
"""Returns the buffer text with xml markup tags.
Convert the pango.Attribute at the received pango.AttrIterator
to gtk.TextTag and apply them on the buffer at the proper indices
If no markup was applied returns clean text.
"""
range = attriter.range()
start_iter = self.get_iter_at_offset(range[0])
end_iter = self.get_iter_at_offset(range[1])
font, lang, attrs = attriter.get_font()
tags = self.get_tags_from_attrs(font, lang, attrs)
for tag in tags:
self.apply_tag(tag, start_iter, end_iter)
def get_tags_from_attrs(self, font, lang, attrs):
"""Convert pango.Attribute to gtk.TextTag."""
tags = []
if font:
font, fontattrs = self.fontdesc_to_attrs(font)
fontdesc = font.to_string()
if fontattrs:
attrs.extend(fontattrs)
##if fontdesc and fontdesc != 'Normal':
##if not self.tags.has_key(font.to_string()):
##tag = self.create_tag()
##tag.set_property('font-desc', font)
##if not self.tagdict.has_key(tag):
##self.tagdict[tag] = {}
##self.tagdict[tag]['font_desc'] = font.to_string()
##self.tags[font.to_string()] = tag
##tags.append(self.tags[font.to_string()])
##if lang:
##if not self.tags.has_key(lang):
##tag = self.create_tag()
##tag.set_property('language', lang)
##self.tags[lang] = tag
##tags.append(self.tags[lang])
if attrs:
for a in attrs:
##if a.type == pango.ATTR_FOREGROUND:
##gdkcolor = self.pango_color_to_gdk(a.color)
##key = 'foreground%s' % self.color_to_hex(gdkcolor)
##if not self.tags.has_key(key):
##self.tags[key] = self.create_tag()
##self.tags[key].set_property('foreground-gdk', gdkcolor)
##self.tagdict[self.tags[key]] = {}
##self.tagdict[self.tags[key]]['foreground'] = "#%s"\
##% self.color_to_hex(gdkcolor)
##tags.append(self.tags[key])
##continue
##if a.type == pango.ATTR_BACKGROUND:
##gdkcolor = self.pango_color_to_gdk(a.color)
##key = 'background%s' % self.color_to_hex(gdkcolor)
##if not self.tags.has_key(key):
##self.tags[key] = self.create_tag()
##self.tags[key].set_property('background-gdk', gdkcolor)
##self.tagdict[self.tags[key]] = {}
##self.tagdict[self.tags[key]]['background'] = "#%s"\
##% self.color_to_hex(gdkcolor)
##tags.append(self.tags[key])
##continue
if self.pango_translation_properties.has_key(a.type):
prop = self.pango_translation_properties[a.type]
log.debug('setting property %s of %s '
'(type: %s)' % (prop, a, a.type))
val = getattr(a, 'value')
mval = val
if self.attval_to_markup.has_key(prop):
log.debug("converting %s in %s" % (prop,val))
if self.attval_to_markup[prop].has_key(val):
mval = self.attval_to_markup[prop][val]
else:
log.debug("hmmm, didn't know what to do"
" with value %s" % val)
key = "%s%s" % (prop, val)
if not self.tags.has_key(key):
self.tags[key] = self.create_tag()
self.tags[key].set_property(prop,val)
self.tagdict[self.tags[key]] = {}
self.tagdict[self.tags[key]][prop] = mval
self.tag_markup[self.tags[key]] = self.pango_shortcut[key]
tags.append(self.tags[key])
else:
log.debug("Don't know what to do with attr %s" % a)
return tags
def get_text(self, start=None, end=None, include_hidden_chars=True):
"""Returns the buffer text with Pango markup tags."""
tagdict = self.get_tags()
eventlist = self.get_event_list(tagdict)
# get the clear text from the buffer
if not start:
start = self.get_start_iter()
if not end:
end = self.get_end_iter()
txt = unicode(gtk.TextBuffer.get_text(self, start, end))
# extract tags out of the buffer
tags = self.get_tags()
output = StringIO()
note_xml = NoteXMLWriter(output, 'utf-8')
last_pos = 0
indices = eventlist.keys()
indices.sort()
for index in indices:
note_xml.characters(txt[last_pos:index])
for tag, event_type, p in eventlist[index]:
if event_type == EVENT_START:
note_xml.startElement(self.tag_markup[tag][EVENT_START])
elif event_type == EVENT_END:
note_xml.endElement(self.tag_markup[tag][EVENT_START])
last_pos = index
note_xml.characters(txt[last_pos:])
note_xml.close()
##cuts = {}
##for text_tag, range in tagdict.items():
##stag, etag = self.tag_to_markup(text_tag)
##for st, e in range:
### insert start tag
##if cuts.has_key(st):
##cuts[st].append(stag)
##else:
##cuts[st] = [stag]
### insert end tag
##if cuts.has_key(e + 1):
##cuts[e + 1] = [etag] + cuts[e + 1]
##else:
##cuts[e + 1] = [etag]
##last_pos = 0
##outbuff = ""
##cut_indices = cuts.keys()
##cut_indices.sort()
##soffset = start.get_offset()
##eoffset = end.get_offset()
##cut_indices = filter(lambda i: eoffset >= i >= soffset, cut_indices)
##for c in cut_indices:
##if not last_pos == c:
##outbuff += saxutils.escape(txt[last_pos:c])
##last_pos = c
##for tag in cuts[c]:
##outbuff += tag
##outbuff += saxutils.escape(txt[last_pos:])
##return outbuff
return output.getvalue()
if len(tags):
# convert the tags to xml elements
elements = self.get_elements(tags)
# feed the elements into the xml writer
self.writer.generate(txt, elements)
txt = self.writer.content
return txt
def get_tags(self):
"""Extract TextTags from buffer.
@ -355,113 +359,37 @@ class MarkupBuffer(gtk.TextBuffer):
else:
tagdict[tag]=[(pos, pos)]
return tagdict
def get_event_list(self, tagdict):
"""Create an event list for XML writer.
def get_elements(self, tagdict):
"""Convert TextTags to xml elements.
@param tagdict: tag dict to convert from
Create the format what MarkupWriter likes
@param tagdict: TextTag dictionary
@param type: {TextTag: [(start, end),]}
@return: eventlist
@rtype: {index: [(TextTag, EVENT_TYPE, pair_index),]}
@return: elements; xml element list
@rtype: [((start, end), name, attrs)]
"""
eventlist = {}
elements = []
for text_tag, indices in tagdict.items():
for start_idx, end_idx in indices:
# end element goes after the last markup'ed char
end_idx += 1
# insert START events
if eventlist.has_key(start_idx):
eventlist[start_idx].append((text_tag, EVENT_START, end_idx))
else:
eventlist[start_idx] = [(text_tag, EVENT_START, end_idx)]
# insert END events
if eventlist.has_key(end_idx):
eventlist[end_idx].append((text_tag, EVENT_END, start_idx))
else:
eventlist[end_idx] = [(text_tag, EVENT_END, start_idx)]
elements.append(((start_idx, end_idx+1),
self.tag_markup[text_tag],
None))
return elements
# sort events at the same index
indices = eventlist.keys()
#indices.sort()
for idx in indices:
if len(eventlist[idx]) > 1:
eventlist[idx].sort(self.sort_events)
return eventlist
##def pango_color_to_gdk(self, pc):
##return gtk.gdk.Color(pc.red, pc.green, pc.blue)
def sort_events(self, event_a, event_b):
"""Sort events that are at the same index.
##def color_to_hex(self, color):
##hexstring = ""
##for col in 'red', 'green', 'blue':
##hexfrag = hex(getattr(color, col) / (16 * 16)).split("x")[1]
##if len(hexfrag) < 2:
##hexfrag = "0" + hexfrag
##hexstring += hexfrag
##return hexstring
Sorting with the following rules:
1. END event goes always before START event;
2. from two START events the one goes first, which has it's own END
event later;
3. from two END events the one goes first, which has it's own START
event later.
"""
tag_a, type_a, pair_a = event_a
tag_b, type_b, pair_b = event_b
if (type_a + type_b) == (EVENT_START + EVENT_END):
return type_b - type_a
else:
return pair_b - pair_a
##def tag_to_markup(self, tag):
##"""Convert a gtk.TextTag to Pango markup tags."""
##stag = "<span"
##for k, v in self.tagdict[tag].items():
##stag += ' %s="%s"' % (k, v)
##stag += ">"
##return stag, "</span>"
##stag = "<%s>" % self.tag_markup[tag]
##etag = "</%s>" % self.tag_markup[tag]
##return stag,etag
def fontdesc_to_attrs(self, font):
"""Convert pango.FontDescription to gtk.Attribute."""
nicks = font.get_set_fields().value_nicks
attrs = []
for n in nicks:
if self.fontdesc_to_attr_table.has_key(n):
Attr, norm = self.fontdesc_to_attr_table[n]
# create an attribute with our current value
attrs.append(Attr(getattr(font, 'get_%s'%n)()))
# unset our font's value
getattr(font,'set_%s'%n)(norm)
return font, attrs
def pango_color_to_gdk(self, pc):
return gtk.gdk.Color(pc.red, pc.green, pc.blue)
def color_to_hex(self, color):
hexstring = ""
for col in 'red', 'green', 'blue':
hexfrag = hex(getattr(color, col) / (16 * 16)).split("x")[1]
if len(hexfrag) < 2:
hexfrag = "0" + hexfrag
hexstring += hexfrag
return hexstring
##def apply_font_and_attrs(self, font, attrs):
##tags = self.get_tags_from_attrs(font,None,attrs)
##for t in tags: self.apply_tag_to_selection(t)
##def remove_font_and_attrs(self, font, attrs):
##tags = self.get_tags_from_attrs(font,None,attrs)
##for t in tags: self.remove_tag_from_selection(t)
##def setup_default_tags(self):
##self.italics = self.get_tags_from_attrs(None,None,
##[pango.AttrStyle('italic')])[0]
##self.bold = self.get_tags_from_attrs(None,None,
##[pango.AttrWeight('bold')])[0]
##self.underline = self.get_tags_from_attrs(None,None,
##[pango.AttrUnderline('single')])[0]
def get_selection(self):
bounds = self.get_selection_bounds()
if not bounds:
@ -496,7 +424,7 @@ class MarkupBuffer(gtk.TextBuffer):
self.remove_tag(t, *selection)
class EditorBuffer(MarkupBuffer):
"""An interactive interface to allow marking up a gtk.TextBuffer.
"""An interactive interface to allow markup a gtk.TextBuffer.
normal_button is a widget whose clicked signal will make us normal
toggle_widget_alist is a list that looks like this:
@ -529,11 +457,9 @@ class EditorBuffer(MarkupBuffer):
if old_itr != insert_itr:
# Use the state of our widgets to determine what
# properties to apply...
for tags, w in self.tag_widgets.items():
for tag, w in self.tag_widgets.items():
if w.get_active():
#print 'apply tags...',tags
for t in tags:
self.apply_tag(t, old_itr, insert_itr)
self.apply_tag(tag, old_itr, insert_itr)
def do_mark_set(self, iter, mark):
# Every time the cursor moves, update our widgets that reflect
@ -543,11 +469,10 @@ class EditorBuffer(MarkupBuffer):
self._in_mark_set = True
if mark.get_name() == 'insert':
for tags,widg in self.tag_widgets.items():
for tag,widg in self.tag_widgets.items():
active = True
for t in tags:
if not iter.has_tag(t):
active = False
if not iter.has_tag(tag):
active = False
self.internal_toggle = True
widg.set_active(active)
self.internal_toggle = False
@ -559,99 +484,108 @@ class EditorBuffer(MarkupBuffer):
# Private
def _toggle(self, widget, tags):
if self.internal_toggle: return
def _toggle(self, widget, tag):
if self.internal_toggle:
return
if widget.get_active():
for t in tags: self.apply_tag_to_selection(t)
self.apply_tag_to_selection(tag)
else:
for t in tags: self.remove_tag_from_selection(t)
log.debug("Text: %s" % self.get_text())
self.remove_tag_from_selection(tag)
# Public API
def setup_widget_from_pango(self, widg, markupstring):
"""Setup widget from a pango markup string."""
a, t, s = pango.parse_markup(markupstring, u'\x00')
ai = a.get_iterator()
# we're gonna use only the first attr from the attrlist
font, lang, attrs = ai.get_font()
return self.setup_widget(widg, font, attrs)
def setup_widget(self, widg, font, attr):
tags = self.get_tags_from_attrs(font, None, attr)
self.tag_widgets[tuple(tags)] = widg
return widg.connect('toggled', self._toggle, tags)
def setup_widget_from_xml(self, widg, xmlstring):
"""Setup widget from an xml markup string."""
try:
parseString("<gramps>%s</gramps>" % xmlstring, self.parser)
except:
# raise Error
log.debug("set: " % self.parser.content)
(start, end), name, attrs = self.parser.elements[0]
return self.setup_widget(widg, name)
def setup_widget(self, widg, name):
tag = self.get_tag_from_element(name)
self.tag_widgets[tag] = widg
return widg.connect('toggled', self._toggle, tag)
if gtk.pygtk_version < (2,8,0):
gobject.type_register(EditorBuffer)
def main(args):
win = gtk.Window()
win.set_title('MarkupBuffer test window')
win.set_position(gtk.WIN_POS_CENTER)
def cb(window, event):
gtk.main_quit()
win.connect('delete-event', cb)
vbox = gtk.VBox()
win.add(vbox)
text = gtk.TextView()
text.set_accepts_tab(True)
flowed = gtk.RadioButton(None, 'Flowed')
format = gtk.RadioButton(flowed, 'Formatted')
#if self.note_obj and self.note_obj.get_format():
#self.format.set_active(True)
#self.text.set_wrap_mode(gtk.WRAP_NONE)
#else:
#self.flowed.set_active(True)
#self.text.set_wrap_mode(gtk.WRAP_WORD)
#self.spellcheck = Spell.Spell(self.text)
#flowed.connect('toggled', flow_changed)
scroll = gtk.ScrolledWindow()
scroll.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
scroll.add(text)
vbox.pack_start(scroll, True)
vbox.set_spacing(6)
vbox.set_border_width(6)
hbox = gtk.HBox()
hbox.set_spacing(12)
hbox.set_border_width(6)
hbox.pack_start(flowed, False)
hbox.pack_start(format, False)
vbox.pack_start(hbox, False)
#self.pack_start(vbox, True)
buf = EditorBuffer()
text.set_buffer(buf)
tooltips = gtk.Tooltips()
for tip,stock,font in [('Italic',gtk.STOCK_ITALIC,'<i>italic</i>'),
('Bold',gtk.STOCK_BOLD,'<b>bold</b>'),
('Underline',gtk.STOCK_UNDERLINE,'<u>underline</u>'),
]:
button = gtk.ToggleButton()
image = gtk.Image()
image.set_from_stock(stock, gtk.ICON_SIZE_MENU)
button.set_image(image)
tooltips.set_tip(button, tip)
button.set_relief(gtk.RELIEF_NONE)
buf.setup_widget_from_pango(button,font)
hbox.pack_start(button, False)
win.show_all()
gtk.main()
if __name__ == '__main__':
import sys
def main(args):
win = gtk.Window()
win.set_title('MarkupBuffer test window')
win.set_position(gtk.WIN_POS_CENTER)
def cb(window, event):
gtk.main_quit()
win.connect('delete-event', cb)
vbox = gtk.VBox()
win.add(vbox)
text = gtk.TextView()
text.set_accepts_tab(True)
flowed = gtk.RadioButton(None, 'Flowed')
format = gtk.RadioButton(flowed, 'Formatted')
#if self.note_obj and self.note_obj.get_format():
#self.format.set_active(True)
#self.text.set_wrap_mode(gtk.WRAP_NONE)
#else:
#self.flowed.set_active(True)
#self.text.set_wrap_mode(gtk.WRAP_WORD)
#self.spellcheck = Spell.Spell(self.text)
#flowed.connect('toggled', flow_changed)
scroll = gtk.ScrolledWindow()
scroll.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
scroll.add(text)
vbox.pack_start(scroll, True)
vbox.set_spacing(6)
vbox.set_border_width(6)
hbox = gtk.HBox()
hbox.set_spacing(12)
hbox.set_border_width(6)
hbox.pack_start(flowed, False)
hbox.pack_start(format, False)
vbox.pack_start(hbox, False)
#self.pack_start(vbox, True)
buf = EditorBuffer()
text.set_buffer(buf)
tooltips = gtk.Tooltips()
for tip,stock,font in [('Italic',gtk.STOCK_ITALIC,'<i>i</i>'),
('Bold',gtk.STOCK_BOLD,'<b>b</b>'),
('Underline',gtk.STOCK_UNDERLINE,'<u>u</u>'),
]:
button = gtk.ToggleButton()
image = gtk.Image()
image.set_from_stock(stock, gtk.ICON_SIZE_MENU)
button.set_image(image)
tooltips.set_tip(button, tip)
button.set_relief(gtk.RELIEF_NONE)
buf.setup_widget_from_xml(button,font)
hbox.pack_start(button, False)
buf.set_text('<gramps>'
'<b>Bold</b>. <i>Italic</i>. <u>Underline</u>.'
'</gramps>')
win.show_all()
gtk.main()
stderrh = logging.StreamHandler(sys.stderr)
stderrh.setLevel(logging.DEBUG)

View File

@ -100,7 +100,7 @@ class Note(SecondaryObject):
"""
text = self.text
if not markup:
if not markup and text[0:8] == '<gramps>':
text = self.delete_tags(text)
return text