[sgala and I] better support of sizes in XHTML, simplify rst generator
This commit is contained in:
parent
fc59489bdf
commit
96e6b34cd7
|
@ -21,39 +21,70 @@ try:
|
|||
from docutils import nodes,utils
|
||||
from docutils.parsers.rst.roles import set_classes
|
||||
except:
|
||||
print "Requires docutils 0.4 for set_classes to be available"
|
||||
def create_xhtml(text):
|
||||
return None
|
||||
else:
|
||||
def jep_reference_role(role, rawtext, text, lineno, inliner,
|
||||
options={}, content=[]):
|
||||
'''Role to make handy references to Jabber Enhancement Proposals (JEP).
|
||||
def pos_int_validator(text):
|
||||
"""Validates that text can be evaluated as a positive integer."""
|
||||
result = int(text)
|
||||
if result < 0:
|
||||
raise ValueError("Error: value '%(text)s' "
|
||||
"must be a positive integer")
|
||||
return result
|
||||
|
||||
Use as :JEP:`71` (or jep, or jep-reference).
|
||||
Modeled after the sample in docutils documentation.
|
||||
def generate_uri_role( role_name, aliases,
|
||||
anchor_text, base_url,
|
||||
interpret_url, validator):
|
||||
'''Creates and register a uri based "interpreted role".
|
||||
|
||||
Those are similar to the RFC, and PEP ones, and take
|
||||
role_name:
|
||||
name that will be registered
|
||||
aliases:
|
||||
list of alternate names
|
||||
anchor_text:
|
||||
text that will be used, together with the role
|
||||
base_url:
|
||||
base url for the link
|
||||
interpret_url:
|
||||
this, modulo the validated text, will be added to it
|
||||
validator:
|
||||
should return the validated text, or raise ValueError
|
||||
'''
|
||||
|
||||
jep_base_url = 'http://www.jabber.org/jeps/'
|
||||
jep_url = 'jep-%04d.html'
|
||||
def uri_reference_role(role, rawtext, text, lineno, inliner,
|
||||
options={}, content=[]):
|
||||
try:
|
||||
jepnum = int(text)
|
||||
if jepnum <= 0:
|
||||
raise ValueError
|
||||
except ValueError:
|
||||
msg = inliner.reporter.error(
|
||||
'JEP number must be a number greater than or equal to 1; '
|
||||
'"%s" is invalid.' % text, line=lineno)
|
||||
valid_text = validator(text)
|
||||
except ValueError, e:
|
||||
msg = inliner.reporter.error( e.message % dict(text=text), line=lineno)
|
||||
prb = inliner.problematic(rawtext, rawtext, msg)
|
||||
return [prb], [msg]
|
||||
ref = jep_base_url + jep_url % jepnum
|
||||
ref = base_url + interpret_url % valid_text
|
||||
set_classes(options)
|
||||
node = nodes.reference(rawtext, 'JEP ' + utils.unescape(text), refuri=ref,
|
||||
node = nodes.reference(rawtext, anchor_text + utils.unescape(text), refuri=ref,
|
||||
**options)
|
||||
return [node], []
|
||||
|
||||
roles.register_canonical_role('jep-reference', jep_reference_role)
|
||||
from docutils.parsers.rst.languages.en import roles
|
||||
roles['jep-reference'] = 'jep-reference'
|
||||
roles['jep'] = 'jep-reference'
|
||||
uri_reference_role.__doc__ = """Role to make handy references to URIs.
|
||||
|
||||
Use as :%(role_name)s:`71` (or any of %(aliases)s).
|
||||
It will use %(base_url)s+%(interpret_url)s
|
||||
validator should throw a ValueError, containing optionally
|
||||
a %%(text)s format, if the interpreted text is not valid.
|
||||
""" % locals()
|
||||
roles.register_canonical_role(role_name, uri_reference_role)
|
||||
from docutils.parsers.rst.languages import en
|
||||
en.roles[role_name] = role_name
|
||||
for alias in aliases:
|
||||
en.roles[alias] = role_name
|
||||
|
||||
generate_uri_role('xep-reference', ('jep', 'xep'),
|
||||
'XEP #', 'http://www.xmpp.org/extensions/', 'xep-%04d.html',
|
||||
pos_int_validator)
|
||||
generate_uri_role('gajim-ticket-reference', ('ticket','gtrack'),
|
||||
'Gajim Ticket #', 'http://trac.gajim.org/ticket/', '%d',
|
||||
pos_int_validator)
|
||||
|
||||
class HTMLGenerator:
|
||||
'''Really simple HTMLGenerator starting from publish_parts.
|
||||
|
@ -108,7 +139,7 @@ else:
|
|||
|
||||
|
||||
if __name__ == '__main__':
|
||||
print Generator.create_xhtml('''
|
||||
print "test 1\n", Generator.create_xhtml("""
|
||||
test::
|
||||
|
||||
>>> print 1
|
||||
|
@ -118,9 +149,10 @@ test::
|
|||
|
||||
this `` should trigger`` should trigger the problem.
|
||||
|
||||
''')
|
||||
print Generator.create_xhtml('''
|
||||
""")
|
||||
print "test 2\n", Generator.create_xhtml("""
|
||||
*test1
|
||||
|
||||
test2_
|
||||
''')
|
||||
""")
|
||||
print "test 3\n", Generator.create_xhtml(""":ticket:`316` implements :xep:`71`""")
|
||||
|
|
|
@ -40,9 +40,9 @@ import time
|
|||
import urllib2
|
||||
import operator
|
||||
|
||||
if __name__ == '__main__':
|
||||
from common import i18n
|
||||
from common import gajim
|
||||
#from common import i18n
|
||||
|
||||
|
||||
import tooltips
|
||||
|
||||
|
@ -62,7 +62,7 @@ classes = {
|
|||
'problematic':';color: red',
|
||||
}
|
||||
|
||||
#styles for elemens
|
||||
# styles for elements
|
||||
element_styles = {
|
||||
'u' : ';text-decoration: underline',
|
||||
'em' : ';font-style: oblique',
|
||||
|
@ -83,9 +83,6 @@ element_styles['tt'] = element_styles['kbd']
|
|||
element_styles['i'] = element_styles['em']
|
||||
element_styles['b'] = element_styles['strong']
|
||||
|
||||
class_styles = {
|
||||
}
|
||||
|
||||
'''
|
||||
==========
|
||||
JEP-0071
|
||||
|
@ -187,8 +184,9 @@ def build_patterns(view, config, interface):
|
|||
basic_pattern = r'(?<!\w|\<|/|:)' r'/[^\s/]' r'([^/]*[^\s/])?' r'/(?!\w|/|:)|'\
|
||||
r'(?<!\w)' r'_[^\s_]' r'([^_]*[^\s_])?' r'_(?!\w)'
|
||||
view.basic_pattern_re = re.compile(basic_pattern)
|
||||
#TODO: emoticons
|
||||
# emoticons
|
||||
emoticons_pattern = ''
|
||||
try:
|
||||
if config.get('emoticons_theme'):
|
||||
# When an emoticon is bordered by an alpha-numeric character it is NOT
|
||||
# expanded. e.g., foo:) NO, foo :) YES, (brb) NO, (:)) YES, etc.
|
||||
|
@ -216,6 +214,8 @@ def build_patterns(view, config, interface):
|
|||
'(?:(?<![\w.]' + emoticons_pattern_prematch[:-1] + '))' + \
|
||||
'(?:' + emoticons_pattern[:-1] + ')' + \
|
||||
'(?:(?![\w.]' + emoticons_pattern_postmatch[:-1] + '))'
|
||||
except:
|
||||
pass
|
||||
|
||||
# because emoticons match later (in the string) they need to be after
|
||||
# basic matches that may occur earlier
|
||||
|
@ -231,9 +231,16 @@ def _parse_css_color(color):
|
|||
else:
|
||||
return gtk.gdk.color_parse(color)
|
||||
|
||||
def style_iter(style):
|
||||
return (map(lambda x:x.strip(),item.split(':', 1)) for item in style.split(';') if len(item.strip()))
|
||||
|
||||
|
||||
class HtmlHandler(xml.sax.handler.ContentHandler):
|
||||
"""A handler to display html to a gtk textview.
|
||||
|
||||
It keeps a stack of "style spans" (start/end element pairs)
|
||||
and a stack of list counters, for nested lists.
|
||||
"""
|
||||
def __init__(self, textview, startiter):
|
||||
xml.sax.handler.ContentHandler.__init__(self)
|
||||
self.textbuf = textview.get_buffer()
|
||||
|
@ -303,16 +310,20 @@ class HtmlHandler(xml.sax.handler.ContentHandler):
|
|||
frac, callback, args):
|
||||
callback(allocation.width*frac, *args)
|
||||
|
||||
def _parse_length(self, value, font_relative, callback, *args):
|
||||
def _parse_length(self, value, font_relative, block_relative, minl, maxl, callback, *args):
|
||||
'''Parse/calc length, converting to pixels, calls callback(length, *args)
|
||||
when the length is first computed or changes'''
|
||||
if value.endswith('%'):
|
||||
frac = float(value[:-1])/100
|
||||
val = float(value[:-1])
|
||||
sign = cmp(val,0)
|
||||
# limits: 1% to 500%
|
||||
val = sign*max(1,min(abs(val),500))
|
||||
frac = val/100
|
||||
if font_relative:
|
||||
attrs = self._get_current_attributes()
|
||||
font_size = attrs.font.get_size() / pango.SCALE
|
||||
callback(frac*display_resolution*font_size, *args)
|
||||
else:
|
||||
elif block_relative:
|
||||
# CSS says 'Percentage values: refer to width of the closest
|
||||
# block-level ancestor'
|
||||
# This is difficult/impossible to implement, so we use
|
||||
|
@ -323,26 +334,41 @@ class HtmlHandler(xml.sax.handler.ContentHandler):
|
|||
self.textview.connect('size-allocate',
|
||||
self.__parse_length_frac_size_allocate,
|
||||
frac, callback, args)
|
||||
else:
|
||||
callback(frac, *args)
|
||||
return
|
||||
|
||||
elif value.endswith('pt'): # points
|
||||
callback(float(value[:-2])*display_resolution, *args)
|
||||
val = float(value[:-2])
|
||||
sign = cmp(val,0)
|
||||
# validate length
|
||||
val = sign*max(minl,min(abs(val*display_resolution),maxl))
|
||||
if value.endswith('pt'): # points
|
||||
callback(val*display_resolution, *args)
|
||||
|
||||
elif value.endswith('em'): # ems, the height of the element's font
|
||||
elif value.endswith('em'): # ems, the width of the element's font
|
||||
attrs = self._get_current_attributes()
|
||||
font_size = attrs.font.get_size() / pango.SCALE
|
||||
callback(float(value[:-2])*display_resolution*font_size, *args)
|
||||
callback(val*display_resolution*font_size, *args)
|
||||
|
||||
elif value.endswith('ex'): # x-height, ~ the height of the letter 'x'
|
||||
# FIXME: figure out how to calculate this correctly
|
||||
# for now 'em' size is used as approximation
|
||||
attrs = self._get_current_attributes()
|
||||
font_size = attrs.font.get_size() / pango.SCALE
|
||||
callback(float(value[:-2])*display_resolution*font_size, *args)
|
||||
callback(val*display_resolution*font_size, *args)
|
||||
|
||||
elif value.endswith('px'): # pixels
|
||||
callback(int(value[:-2]), *args)
|
||||
callback(val, *args)
|
||||
|
||||
else:
|
||||
try:
|
||||
# TODO: isn't "no units" interpreted as pixels?
|
||||
val = int(value)
|
||||
sign = cmp(val,0)
|
||||
# validate length
|
||||
val = sign*max(minl,min(abs(val),maxl))
|
||||
callback(val, *args)
|
||||
except:
|
||||
warnings.warn('Unable to parse length value "%s"' % value)
|
||||
|
||||
def __parse_font_size_cb(length, tag):
|
||||
|
@ -352,7 +378,7 @@ class HtmlHandler(xml.sax.handler.ContentHandler):
|
|||
def _parse_style_display(self, tag, value):
|
||||
if value == 'none':
|
||||
tag.set_property('invisible','true')
|
||||
#Fixme: display: block, inline
|
||||
# FIXME: display: block, inline
|
||||
|
||||
def _parse_style_font_size(self, tag, value):
|
||||
try:
|
||||
|
@ -377,7 +403,8 @@ class HtmlHandler(xml.sax.handler.ContentHandler):
|
|||
if value == 'larger':
|
||||
tag.set_property('scale', pango.SCALE_LARGE)
|
||||
return
|
||||
self._parse_length(value, True, self.__parse_font_size_cb, tag)
|
||||
# font relative (5 ~ 4pt, 110 ~ 72pt)
|
||||
self._parse_length(value, True, False, 5, 110, self.__parse_font_size_cb, tag)
|
||||
|
||||
def _parse_style_font_style(self, tag, value):
|
||||
try:
|
||||
|
@ -399,11 +426,13 @@ class HtmlHandler(xml.sax.handler.ContentHandler):
|
|||
#__frac_length_tag_cb = staticmethod(__frac_length_tag_cb)
|
||||
|
||||
def _parse_style_margin_left(self, tag, value):
|
||||
self._parse_length(value, False, self.__frac_length_tag_cb,
|
||||
# block relative
|
||||
self._parse_length(value, False, True, 1, 1000, self.__frac_length_tag_cb,
|
||||
tag, 'left-margin')
|
||||
|
||||
def _parse_style_margin_right(self, tag, value):
|
||||
self._parse_length(value, False, self.__frac_length_tag_cb,
|
||||
# block relative
|
||||
self._parse_length(value, False, True, 1, 1000, self.__frac_length_tag_cb,
|
||||
tag, 'right-margin')
|
||||
|
||||
def _parse_style_font_weight(self, tag, value):
|
||||
|
@ -470,12 +499,31 @@ class HtmlHandler(xml.sax.handler.ContentHandler):
|
|||
elif value == 'nowrap':
|
||||
tag.set_property('wrap_mode', gtk.WRAP_NONE)
|
||||
|
||||
def __length_tag_cb(self, value, tag, propname):
|
||||
try:
|
||||
tag.set_property(propname, value)
|
||||
except:
|
||||
gajim.log.warn( "Error with prop: " + propname + " for tag: " + str(tag))
|
||||
|
||||
|
||||
def _parse_style_width(self, tag, value):
|
||||
if value == 'auto':
|
||||
return
|
||||
self._parse_length(value, False, False, 1, 1000, self.__length_tag_cb,
|
||||
tag, "width")
|
||||
def _parse_style_height(self, tag, value):
|
||||
if value == 'auto':
|
||||
return
|
||||
self._parse_length(value, False, False, 1, 1000, self.__length_tag_cb,
|
||||
tag, "height")
|
||||
|
||||
|
||||
# build a dictionary mapping styles to methods, for greater speed
|
||||
__style_methods = dict()
|
||||
for style in ['background-color', 'color', 'font-family', 'font-size',
|
||||
'font-style', 'font-weight', 'margin-left', 'margin-right',
|
||||
'text-align', 'text-decoration', 'white-space', 'display' ]:
|
||||
'text-align', 'text-decoration', 'white-space', 'display',
|
||||
'width', 'height' ]:
|
||||
try:
|
||||
method = locals()['_parse_style_%s' % style.replace('-', '_')]
|
||||
except KeyError:
|
||||
|
@ -489,6 +537,8 @@ class HtmlHandler(xml.sax.handler.ContentHandler):
|
|||
return [tag for tag in self.styles if tag is not None]
|
||||
|
||||
def _create_url(self, href, title, type_, id_):
|
||||
'''Process a url tag.
|
||||
'''
|
||||
tag = self.textbuf.create_tag(id_)
|
||||
if href and href[0] != '#':
|
||||
tag.href = href
|
||||
|
@ -501,6 +551,125 @@ class HtmlHandler(xml.sax.handler.ContentHandler):
|
|||
tag.title = title
|
||||
return tag
|
||||
|
||||
def _process_img(self, attrs):
|
||||
'''Process a img tag.
|
||||
'''
|
||||
try:
|
||||
# Wait maximum 1s for connection
|
||||
socket.setdefaulttimeout(1)
|
||||
try:
|
||||
f = urllib2.urlopen(attrs['src'])
|
||||
except Exception, ex:
|
||||
gajim.log.debug(str('Error loading image %s ' % attrs['src'] + ex))
|
||||
pixbuf = None
|
||||
alt = attrs.get('alt', 'Broken image')
|
||||
else:
|
||||
# Wait 0.1s between each byte
|
||||
try:
|
||||
f.fp._sock.fp._sock.settimeout(0.5)
|
||||
except:
|
||||
pass
|
||||
# Max image size = 2 MB (to try to prevent DoS)
|
||||
mem = ''
|
||||
deadline = time.time() + 3
|
||||
while True:
|
||||
if time.time() > deadline:
|
||||
gajim.log.debug(str('Timeout loading image %s ' % \
|
||||
attrs['src'] + ex))
|
||||
mem = ''
|
||||
alt = attrs.get('alt', '')
|
||||
if alt:
|
||||
alt += '\n'
|
||||
alt += _('Timeout loading image')
|
||||
break
|
||||
try:
|
||||
temp = f.read(100)
|
||||
except socket.timeout, ex:
|
||||
gajim.log.debug('Timeout loading image %s ' % attrs['src'] + \
|
||||
str(ex))
|
||||
mem = ''
|
||||
alt = attrs.get('alt', '')
|
||||
if alt:
|
||||
alt += '\n'
|
||||
alt += _('Timeout loading image')
|
||||
break
|
||||
if temp:
|
||||
mem += temp
|
||||
else:
|
||||
break
|
||||
if len(mem) > 2*1024*1024:
|
||||
alt = attrs.get('alt', '')
|
||||
if alt:
|
||||
alt += '\n'
|
||||
alt += _('Image is too big')
|
||||
break
|
||||
pixbuf = None
|
||||
if mem:
|
||||
# Caveat: GdkPixbuf is known not to be safe to load
|
||||
# images from network... this program is now potentially
|
||||
# hackable ;)
|
||||
loader = gtk.gdk.PixbufLoader()
|
||||
dims = [0,0]
|
||||
def height_cb(length):
|
||||
dims[1] = length
|
||||
def width_cb(length):
|
||||
dims[0] = length
|
||||
# process width and height attributes
|
||||
w = attrs.get('width')
|
||||
h = attrs.get('height')
|
||||
# override with width and height styles
|
||||
for attr, val in style_iter(attrs.get('style', '')):
|
||||
if attr == 'width':
|
||||
w = val
|
||||
elif attr == 'height':
|
||||
h = val
|
||||
if w:
|
||||
self._parse_length(w, False, False, 1, 1000, width_cb)
|
||||
if h:
|
||||
self._parse_length(h, False, False, 1, 1000, height_cb)
|
||||
def set_size(pixbuf, w, h, dims):
|
||||
'''FIXME: floats should be relative to the whole
|
||||
textview, and resize with it. This needs new
|
||||
pifbufs for every resize, gtk.gdk.Pixbuf.scale_simple
|
||||
or similar.
|
||||
'''
|
||||
if type(dims[0]) == float:
|
||||
dims[0] = int(dims[0]*w)
|
||||
elif not dims[0]:
|
||||
dims[0] = w
|
||||
if type(dims[1]) == float:
|
||||
dims[1] = int(dims[1]*h)
|
||||
if not dims[1]:
|
||||
dims[1] = h
|
||||
loader.set_size(*dims)
|
||||
if w or h:
|
||||
loader.connect('size-prepared', set_size, dims)
|
||||
loader.write(mem)
|
||||
loader.close()
|
||||
pixbuf = loader.get_pixbuf()
|
||||
alt = attrs.get('alt', '')
|
||||
if pixbuf is not None:
|
||||
tags = self._get_style_tags()
|
||||
if tags:
|
||||
tmpmark = self.textbuf.create_mark(None, self.iter, True)
|
||||
self.textbuf.insert_pixbuf(self.iter, pixbuf)
|
||||
self.starting = False
|
||||
if tags:
|
||||
start = self.textbuf.get_iter_at_mark(tmpmark)
|
||||
for tag in tags:
|
||||
self.textbuf.apply_tag(tag, start, self.iter)
|
||||
self.textbuf.delete_mark(tmpmark)
|
||||
else:
|
||||
self._insert_text('[IMG: %s]' % alt)
|
||||
except Exception, ex:
|
||||
gajim.log.error('Error loading image ' + str(ex))
|
||||
pixbuf = None
|
||||
alt = attrs.get('alt', 'Broken image')
|
||||
try:
|
||||
loader.close()
|
||||
except:
|
||||
pass
|
||||
return pixbuf
|
||||
|
||||
def _begin_span(self, style, tag=None, id_=None):
|
||||
if style is None:
|
||||
|
@ -511,9 +680,9 @@ class HtmlHandler(xml.sax.handler.ContentHandler):
|
|||
tag = self.textbuf.create_tag(id_)
|
||||
else:
|
||||
tag = self.textbuf.create_tag() # we create anonymous tag
|
||||
for attr, val in [item.split(':', 1) for item in style.split(';') if len(item.strip())]:
|
||||
attr = attr.strip().lower()
|
||||
val = val.strip()
|
||||
for attr, val in style_iter(style):
|
||||
attr = attr.lower()
|
||||
val = val
|
||||
try:
|
||||
method = self.__style_methods[attr]
|
||||
except KeyError:
|
||||
|
@ -603,6 +772,7 @@ class HtmlHandler(xml.sax.handler.ContentHandler):
|
|||
self.text += content
|
||||
return
|
||||
if allwhitespace_rx.match(content) is not None and self._starts_line():
|
||||
self.text += ' '
|
||||
return
|
||||
self.text += content
|
||||
self.starting = False
|
||||
|
@ -611,9 +781,8 @@ class HtmlHandler(xml.sax.handler.ContentHandler):
|
|||
def startElement(self, name, attrs):
|
||||
self._flush_text()
|
||||
klass = [i for i in attrs.get('class',' ').split(' ') if i]
|
||||
style = attrs.get('style','')
|
||||
style = ''
|
||||
#Add styles defined for classes
|
||||
#TODO: priority between class and style elements?
|
||||
for k in klass:
|
||||
if k in classes:
|
||||
style += classes[k]
|
||||
|
@ -641,9 +810,13 @@ class HtmlHandler(xml.sax.handler.ContentHandler):
|
|||
tag.is_anchor = True
|
||||
elif name in LIST_ELEMS:
|
||||
style += ';margin-left: 2em'
|
||||
elif name == 'img':
|
||||
tag = self._process_img(attrs)
|
||||
if name in element_styles:
|
||||
style += element_styles[name]
|
||||
|
||||
# so that explicit styles override implicit ones,
|
||||
# we add the attribute last
|
||||
style += ";"+attrs.get('style','')
|
||||
if style == '':
|
||||
style = None
|
||||
self._begin_span(style, tag, id_)
|
||||
|
@ -681,83 +854,7 @@ class HtmlHandler(xml.sax.handler.ContentHandler):
|
|||
elif name == 'dt':
|
||||
if not self.starting:
|
||||
self._jump_line()
|
||||
elif name == 'img':
|
||||
# Wait maximum 1s for connection
|
||||
socket.setdefaulttimeout(1)
|
||||
try:
|
||||
f = urllib2.urlopen(attrs['src'])
|
||||
except Exception, ex:
|
||||
gajim.log.debug(str('Error loading image %s ' % attrs['src'] + ex))
|
||||
pixbuf = None
|
||||
alt = attrs.get('alt', 'Broken image')
|
||||
else:
|
||||
# Wait 10ms between each byte
|
||||
try:
|
||||
f.fp._sock.fp._sock.settimeout(0.1)
|
||||
except:
|
||||
pass
|
||||
# Max image size = 2 MB (to try to prevent DoS) in Max 3s
|
||||
mem = ''
|
||||
deadline = time.time() + 3
|
||||
while True:
|
||||
if time.time() > deadline:
|
||||
gajim.log.debug(str('Timeout loading image %s ' % \
|
||||
attrs['src'] + ex))
|
||||
mem = ''
|
||||
alt = attrs.get('alt', '')
|
||||
if alt:
|
||||
alt += '\n'
|
||||
alt += _('Timeout loading image')
|
||||
break
|
||||
try:
|
||||
temp = f.read(100)
|
||||
except socket.timeout, ex:
|
||||
gajim.log.debug('Timeout loading image %s ' % attrs['src'] + \
|
||||
str(ex))
|
||||
mem = ''
|
||||
alt = attrs.get('alt', '')
|
||||
if alt:
|
||||
alt += '\n'
|
||||
alt += _('Timeout loading image')
|
||||
break
|
||||
if temp:
|
||||
mem += temp
|
||||
else:
|
||||
break
|
||||
if len(mem) > 2*1024*1024:
|
||||
alt = attrs.get('alt', '')
|
||||
if alt:
|
||||
alt += '\n'
|
||||
alt += _('Image is too big')
|
||||
break
|
||||
|
||||
if mem:
|
||||
# Caveat: GdkPixbuf is known not to be safe to load
|
||||
# images from network... this program is now potentially
|
||||
# hackable ;)
|
||||
loader = gtk.gdk.PixbufLoader()
|
||||
loader.write(mem)
|
||||
loader.close()
|
||||
pixbuf = loader.get_pixbuf()
|
||||
else:
|
||||
pixbuf = None
|
||||
if pixbuf is not None:
|
||||
tags = self._get_style_tags()
|
||||
if tags:
|
||||
tmpmark = self.textbuf.create_mark(None, self.iter, True)
|
||||
|
||||
self.textbuf.insert_pixbuf(self.iter, pixbuf)
|
||||
|
||||
if tags:
|
||||
start = self.textbuf.get_iter_at_mark(tmpmark)
|
||||
for tag in tags:
|
||||
self.textbuf.apply_tag(tag, start, self.iter)
|
||||
self.textbuf.delete_mark(tmpmark)
|
||||
else:
|
||||
self._insert_text('[IMG: %s]' % alt)
|
||||
elif name == 'body' or name == 'html':
|
||||
pass
|
||||
elif name == 'a':
|
||||
elif name in ('a', 'img', 'body', 'html'):
|
||||
pass
|
||||
elif name in INLINE:
|
||||
pass
|
||||
|
@ -807,10 +904,6 @@ class HtmlHandler(xml.sax.handler.ContentHandler):
|
|||
# self.text = ' '
|
||||
|
||||
class HtmlTextView(gtk.TextView):
|
||||
__gtype_name__ = 'HtmlTextView'
|
||||
__gsignals__ = {
|
||||
'url-clicked': (gobject.SIGNAL_RUN_LAST, None, (str, str)), # href, type
|
||||
}
|
||||
|
||||
def __init__(self):
|
||||
gobject.GObject.__init__(self)
|
||||
|
@ -886,16 +979,39 @@ class HtmlTextView(gtk.TextView):
|
|||
parser.setContentHandler(HtmlHandler(self, eob))
|
||||
parser.parse(StringIO(html))
|
||||
|
||||
# too much space after :)
|
||||
#if not eob.starts_line():
|
||||
# buffer.insert(eob, '\n')
|
||||
|
||||
|
||||
|
||||
change_cursor = None
|
||||
|
||||
if __name__ == '__main__':
|
||||
import os
|
||||
from common import gajim
|
||||
|
||||
class log(object):
|
||||
|
||||
def debug(self, text):
|
||||
print "debug:", text
|
||||
def warn(self, text):
|
||||
print "warn;", text
|
||||
def error(self,text):
|
||||
print "error;", text
|
||||
|
||||
gajim.log=log()
|
||||
|
||||
if gajim.config.get('emoticons_theme'):
|
||||
print "emoticons"
|
||||
|
||||
htmlview = HtmlTextView()
|
||||
|
||||
path_to_file = os.path.join(gajim.DATA_DIR, 'pixmaps', 'muc_separator.png')
|
||||
# use this for hr
|
||||
htmlview.focus_out_line_pixbuf = gtk.gdk.pixbuf_new_from_file(path_to_file)
|
||||
|
||||
|
||||
tooltip = tooltips.BaseTooltip()
|
||||
def on_textview_motion_notify_event(widget, event):
|
||||
'''change the cursor to a hand when we are over a mail or an url'''
|
||||
|
@ -966,8 +1082,8 @@ if __name__ == '__main__':
|
|||
<p style='text-align:center'>Hey, are you licensed to <a href='http://www.jabber.org/'>Jabber</a>?</p>
|
||||
<p style='text-align:right'><img src='http://www.jabber.org/images/psa-license.jpg'
|
||||
alt='A License to Jabber'
|
||||
height='261'
|
||||
width='537'/></p>
|
||||
width='50%' height='50%'
|
||||
/></p>
|
||||
</body>
|
||||
''')
|
||||
htmlview.display_html('<hr />')
|
||||
|
@ -992,8 +1108,9 @@ if __name__ == '__main__':
|
|||
<li> One </li>
|
||||
<li> Two is nested: <ul style='background-color:rgb(200,200,100)'>
|
||||
<li> One </li>
|
||||
<li> Two </li>
|
||||
<li> Three </li>
|
||||
<li style='font-size:50%'> Two </li>
|
||||
<li style='font-size:200%'> Three </li>
|
||||
<li style='font-size:9999pt'> Four </li>
|
||||
</ul></li>
|
||||
<li> Three </li></ol>
|
||||
</body>
|
||||
|
|
Loading…
Reference in New Issue