parent
e8e2b219ba
commit
4db1d2738c
|
@ -955,6 +955,13 @@ class ConversationTextview(gobject.GObject):
|
||||||
|
|
||||||
buffer_ = self.tv.get_buffer()
|
buffer_ = self.tv.get_buffer()
|
||||||
|
|
||||||
|
insert_tags_func = buffer_.insert_with_tags_by_name
|
||||||
|
# detect_and_print_special_text() is also used by
|
||||||
|
# HtmlHandler.handle_specials() and there tags is gtk.TextTag objects,
|
||||||
|
# not strings
|
||||||
|
if len(other_tags) > 0 and isinstance(other_tags[0], gtk.TextTag):
|
||||||
|
insert_tags_func = buffer_.insert_with_tags
|
||||||
|
|
||||||
index = 0
|
index = 0
|
||||||
|
|
||||||
# Too many special elements (emoticons, LaTeX formulas, etc)
|
# Too many special elements (emoticons, LaTeX formulas, etc)
|
||||||
|
@ -974,8 +981,7 @@ class ConversationTextview(gobject.GObject):
|
||||||
text_before_special_text = otext[index:start]
|
text_before_special_text = otext[index:start]
|
||||||
end_iter = buffer_.get_end_iter()
|
end_iter = buffer_.get_end_iter()
|
||||||
# we insert normal text
|
# we insert normal text
|
||||||
buffer_.insert_with_tags_by_name(end_iter,
|
insert_tags_func(end_iter, text_before_special_text, *other_tags)
|
||||||
text_before_special_text, *other_tags)
|
|
||||||
index = end # update index
|
index = end # update index
|
||||||
|
|
||||||
# now print it
|
# now print it
|
||||||
|
@ -984,7 +990,11 @@ class ConversationTextview(gobject.GObject):
|
||||||
if specials_limit <= 0:
|
if specials_limit <= 0:
|
||||||
break
|
break
|
||||||
|
|
||||||
return index # the position after *last* special text
|
# add the rest of text located in the index and after
|
||||||
|
end_iter = buffer_.get_end_iter()
|
||||||
|
insert_tags_func(end_iter, otext[index:], *other_tags)
|
||||||
|
|
||||||
|
return buffer_.get_end_iter()
|
||||||
|
|
||||||
def print_special_text(self, special_text, other_tags):
|
def print_special_text(self, special_text, other_tags):
|
||||||
'''is called by detect_and_print_special_text and prints
|
'''is called by detect_and_print_special_text and prints
|
||||||
|
@ -1280,22 +1290,17 @@ class ConversationTextview(gobject.GObject):
|
||||||
try:
|
try:
|
||||||
if name and (text.startswith('/me ') or text.startswith('/me\n')):
|
if name and (text.startswith('/me ') or text.startswith('/me\n')):
|
||||||
xhtml = xhtml.replace('/me', '<i>* %s</i>' % (name,), 1)
|
xhtml = xhtml.replace('/me', '<i>* %s</i>' % (name,), 1)
|
||||||
self.tv.display_html(xhtml.encode('utf-8'))
|
self.tv.display_html(xhtml.encode('utf-8'), self)
|
||||||
return
|
return
|
||||||
except Exception, e:
|
except Exception, e:
|
||||||
gajim.log.debug(str('Error processing xhtml') + str(e))
|
gajim.log.debug(str('Error processing xhtml') + str(e))
|
||||||
gajim.log.debug(str('with |' + xhtml + '|'))
|
gajim.log.debug(str('with |' + xhtml + '|'))
|
||||||
|
|
||||||
buffer_ = self.tv.get_buffer()
|
|
||||||
# /me is replaced by name if name is given
|
# /me is replaced by name if name is given
|
||||||
if name and (text.startswith('/me ') or text.startswith('/me\n')):
|
if name and (text.startswith('/me ') or text.startswith('/me\n')):
|
||||||
text = '* ' + name + text[3:]
|
text = '* ' + name + text[3:]
|
||||||
text_tags.append('italic')
|
text_tags.append('italic')
|
||||||
# detect urls formatting and if the user has it on emoticons
|
# detect urls formatting and if the user has it on emoticons
|
||||||
index = self.detect_and_print_special_text(text, text_tags)
|
self.detect_and_print_special_text(text, text_tags)
|
||||||
|
|
||||||
# add the rest of text located in the index and after
|
|
||||||
end_iter = buffer_.get_end_iter()
|
|
||||||
buffer_.insert_with_tags_by_name(end_iter, text[index:], *text_tags)
|
|
||||||
|
|
||||||
# vim: se ts=3:
|
# vim: se ts=3:
|
||||||
|
|
|
@ -50,6 +50,8 @@ import operator
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
from common import i18n
|
from common import i18n
|
||||||
|
import common.configpaths
|
||||||
|
common.configpaths.gajimpaths.init(None)
|
||||||
from common import gajim
|
from common import gajim
|
||||||
|
|
||||||
import tooltips
|
import tooltips
|
||||||
|
@ -184,25 +186,6 @@ for name in BLOCK_HEAD:
|
||||||
('font-weight: bold', 'font-style: oblique')[weigth],
|
('font-weight: bold', 'font-style: oblique')[weigth],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def build_patterns(view, config, interface):
|
|
||||||
# extra, rst does not mark _underline_ or /it/ up
|
|
||||||
# actually <b>, <i> or <u> are not in the JEP-0071, but are seen in the wild
|
|
||||||
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)
|
|
||||||
# emoticons
|
|
||||||
emoticons_pattern = ''
|
|
||||||
if config.get('emoticons_theme'):
|
|
||||||
emoticons_pattern = gajim.interface.emot_only
|
|
||||||
|
|
||||||
view.emot_pattern_re = re.compile(emoticons_pattern, re.IGNORECASE)
|
|
||||||
# because emoticons match later (in the string) they need to be after
|
|
||||||
# basic matches that may occur earlier
|
|
||||||
emot_and_basic_pattern = basic_pattern + emoticons_pattern
|
|
||||||
view.emot_and_basic_re = re.compile(emot_and_basic_pattern, re.IGNORECASE)
|
|
||||||
|
|
||||||
|
|
||||||
def _parse_css_color(color):
|
def _parse_css_color(color):
|
||||||
'''_parse_css_color(css_color) -> gtk.gdk.Color'''
|
'''_parse_css_color(css_color) -> gtk.gdk.Color'''
|
||||||
if color.startswith('rgb(') and color.endswith(')'):
|
if color.startswith('rgb(') and color.endswith(')'):
|
||||||
|
@ -222,11 +205,12 @@ class HtmlHandler(xml.sax.handler.ContentHandler):
|
||||||
It keeps a stack of "style spans" (start/end element pairs)
|
It keeps a stack of "style spans" (start/end element pairs)
|
||||||
and a stack of list counters, for nested lists.
|
and a stack of list counters, for nested lists.
|
||||||
"""
|
"""
|
||||||
def __init__(self, textview, startiter):
|
def __init__(self, conv_textview, startiter):
|
||||||
xml.sax.handler.ContentHandler.__init__(self)
|
xml.sax.handler.ContentHandler.__init__(self)
|
||||||
self.textbuf = textview.get_buffer()
|
self.textbuf = conv_textview.tv.get_buffer()
|
||||||
self.textview = textview
|
self.textview = conv_textview.tv
|
||||||
self.iter = startiter
|
self.iter = startiter
|
||||||
|
self.conv_textview = conv_textview
|
||||||
self.text = ''
|
self.text = ''
|
||||||
self.starting=True
|
self.starting=True
|
||||||
self.preserve = False
|
self.preserve = False
|
||||||
|
@ -672,51 +656,7 @@ class HtmlHandler(xml.sax.handler.ContentHandler):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def handle_specials(self, text):
|
def handle_specials(self, text):
|
||||||
index = 0
|
self.iter = self.conv_textview.detect_and_print_special_text(text, self._get_style_tags())
|
||||||
se = self.textview.config.get('show_ascii_formatting_chars')
|
|
||||||
af = gajim.config.get('ascii_formatting')
|
|
||||||
if self.textview.config.get('emoticons_theme'):
|
|
||||||
if af:
|
|
||||||
iterator = self.textview.emot_and_basic_re.finditer(text)
|
|
||||||
else:
|
|
||||||
iterator = self.textview.emot_pattern_re.finditer(text)
|
|
||||||
elif af:
|
|
||||||
iterator = self.textview.basic_pattern_re.finditer(text)
|
|
||||||
else:
|
|
||||||
iterator = []
|
|
||||||
for match in iterator:
|
|
||||||
start, end = match.span()
|
|
||||||
special_text = text[start:end]
|
|
||||||
if start != 0:
|
|
||||||
self._insert_text(text[index:start])
|
|
||||||
index = end # update index
|
|
||||||
#emoticons
|
|
||||||
possible_emot_ascii_caps = special_text.upper() # emoticons keys are CAPS
|
|
||||||
if self.textview.config.get('emoticons_theme') and \
|
|
||||||
possible_emot_ascii_caps in self.textview.interface.emoticons.keys():
|
|
||||||
#it's an emoticon
|
|
||||||
emot_ascii = possible_emot_ascii_caps
|
|
||||||
anchor = self.textbuf.create_child_anchor(self.iter)
|
|
||||||
img = gtk.Image()
|
|
||||||
img.set_from_file(self.textview.interface.emoticons[emot_ascii])
|
|
||||||
img.show()
|
|
||||||
# TODO: add alt/tooltip with the special_text (a11y)
|
|
||||||
self.textview.add_child_at_anchor(img, anchor)
|
|
||||||
elif af:
|
|
||||||
# now print it
|
|
||||||
if special_text.startswith('/'): # it's explicit italics
|
|
||||||
self.startElement('i', {})
|
|
||||||
elif special_text.startswith('_'): # it's explicit underline
|
|
||||||
self.startElement('u', {})
|
|
||||||
if se: self._insert_text(special_text[0])
|
|
||||||
self.handle_specials(special_text[1:-1])
|
|
||||||
if se: self._insert_text(special_text[0])
|
|
||||||
if special_text.startswith('_'): # it's explicit underline
|
|
||||||
self.endElement('u')
|
|
||||||
if special_text.startswith('/'): # it's explicit italics
|
|
||||||
self.endElement('i')
|
|
||||||
if index < len(text):
|
|
||||||
self._insert_text(text[index:])
|
|
||||||
|
|
||||||
def characters(self, content):
|
def characters(self, content):
|
||||||
if self.preserve:
|
if self.preserve:
|
||||||
|
@ -870,7 +810,6 @@ class HtmlTextView(gtk.TextView):
|
||||||
self.config = gajim.config
|
self.config = gajim.config
|
||||||
self.interface = gajim.interface
|
self.interface = gajim.interface
|
||||||
# end big hack
|
# end big hack
|
||||||
build_patterns(self,gajim.config,gajim.interface)
|
|
||||||
|
|
||||||
def __destroy_event(self, widget):
|
def __destroy_event(self, widget):
|
||||||
if self.tooltip.timeout != 0:
|
if self.tooltip.timeout != 0:
|
||||||
|
@ -921,14 +860,14 @@ class HtmlTextView(gtk.TextView):
|
||||||
self._changed_cursor = False
|
self._changed_cursor = False
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def display_html(self, html):
|
def display_html(self, html, conv_textview):
|
||||||
buffer_ = self.get_buffer()
|
buffer_ = self.get_buffer()
|
||||||
eob = buffer_.get_end_iter()
|
eob = buffer_.get_end_iter()
|
||||||
## this works too if libxml2 is not available
|
## this works too if libxml2 is not available
|
||||||
# parser = xml.sax.make_parser(['drv_libxml2'])
|
# parser = xml.sax.make_parser(['drv_libxml2'])
|
||||||
# parser.setFeature(xml.sax.handler.feature_validation, True)
|
# parser.setFeature(xml.sax.handler.feature_validation, True)
|
||||||
parser = xml.sax.make_parser()
|
parser = xml.sax.make_parser()
|
||||||
parser.setContentHandler(HtmlHandler(self, eob))
|
parser.setContentHandler(HtmlHandler(conv_textview, eob))
|
||||||
parser.parse(StringIO(html))
|
parser.parse(StringIO(html))
|
||||||
|
|
||||||
# too much space after :)
|
# too much space after :)
|
||||||
|
@ -942,6 +881,9 @@ change_cursor = None
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
import os
|
import os
|
||||||
|
|
||||||
|
from conversation_textview import ConversationTextview
|
||||||
|
import gajim as gaj
|
||||||
|
|
||||||
class log(object):
|
class log(object):
|
||||||
|
|
||||||
def debug(self, text):
|
def debug(self, text):
|
||||||
|
@ -953,33 +895,32 @@ if __name__ == '__main__':
|
||||||
|
|
||||||
gajim.log=log()
|
gajim.log=log()
|
||||||
|
|
||||||
if gajim.config.get('emoticons_theme'):
|
gaj.Interface()
|
||||||
print "emoticons"
|
|
||||||
|
|
||||||
htmlview = HtmlTextView()
|
htmlview = ConversationTextview(None)
|
||||||
|
|
||||||
path_to_file = os.path.join(gajim.DATA_DIR, 'pixmaps', 'muc_separator.png')
|
path_to_file = os.path.join(gajim.DATA_DIR, 'pixmaps', 'muc_separator.png')
|
||||||
# use this for hr
|
# use this for hr
|
||||||
htmlview.focus_out_line_pixbuf = gtk.gdk.pixbuf_new_from_file(path_to_file)
|
htmlview.tv.focus_out_line_pixbuf = gtk.gdk.pixbuf_new_from_file(path_to_file)
|
||||||
|
|
||||||
|
|
||||||
tooltip = tooltips.BaseTooltip()
|
tooltip = tooltips.BaseTooltip()
|
||||||
def on_textview_motion_notify_event(widget, event):
|
def on_textview_motion_notify_event(widget, event):
|
||||||
'''change the cursor to a hand when we are over a mail or an url'''
|
'''change the cursor to a hand when we are over a mail or an url'''
|
||||||
global change_cursor
|
global change_cursor
|
||||||
pointer_x, pointer_y = htmlview.window.get_pointer()[0:2]
|
pointer_x, pointer_y = htmlview.tv.window.get_pointer()[0:2]
|
||||||
x, y = htmlview.window_to_buffer_coords(gtk.TEXT_WINDOW_TEXT, pointer_x,
|
x, y = htmlview.tv.window_to_buffer_coords(gtk.TEXT_WINDOW_TEXT, pointer_x,
|
||||||
pointer_y)
|
pointer_y)
|
||||||
tags = htmlview.get_iter_at_location(x, y).get_tags()
|
tags = htmlview.tv.get_iter_at_location(x, y).get_tags()
|
||||||
if change_cursor:
|
if change_cursor:
|
||||||
htmlview.get_window(gtk.TEXT_WINDOW_TEXT).set_cursor(
|
htmlview.tv.get_window(gtk.TEXT_WINDOW_TEXT).set_cursor(
|
||||||
gtk.gdk.Cursor(gtk.gdk.XTERM))
|
gtk.gdk.Cursor(gtk.gdk.XTERM))
|
||||||
change_cursor = None
|
change_cursor = None
|
||||||
tag_table = htmlview.get_buffer().get_tag_table()
|
tag_table = htmlview.tv.get_buffer().get_tag_table()
|
||||||
for tag in tags:
|
for tag in tags:
|
||||||
try:
|
try:
|
||||||
if tag.is_anchor:
|
if tag.is_anchor:
|
||||||
htmlview.get_window(gtk.TEXT_WINDOW_TEXT).set_cursor(
|
htmlview.tv.get_window(gtk.TEXT_WINDOW_TEXT).set_cursor(
|
||||||
gtk.gdk.Cursor(gtk.gdk.HAND2))
|
gtk.gdk.Cursor(gtk.gdk.HAND2))
|
||||||
change_cursor = tag
|
change_cursor = tag
|
||||||
elif tag == tag_table.lookup('focus-out-line'):
|
elif tag == tag_table.lookup('focus-out-line'):
|
||||||
|
@ -994,32 +935,38 @@ if __name__ == '__main__':
|
||||||
#if over_line and not line_tooltip.win:
|
#if over_line and not line_tooltip.win:
|
||||||
# line_tooltip.timeout = gobject.timeout_add(500,
|
# line_tooltip.timeout = gobject.timeout_add(500,
|
||||||
# show_line_tooltip)
|
# show_line_tooltip)
|
||||||
# htmlview.get_window(gtk.TEXT_WINDOW_TEXT).set_cursor(
|
# htmlview.tv.get_window(gtk.TEXT_WINDOW_TEXT).set_cursor(
|
||||||
# gtk.gdk.Cursor(gtk.gdk.LEFT_PTR))
|
# gtk.gdk.Cursor(gtk.gdk.LEFT_PTR))
|
||||||
# change_cursor = tag
|
# change_cursor = tag
|
||||||
|
|
||||||
htmlview.connect('motion_notify_event', on_textview_motion_notify_event)
|
htmlview.tv.connect('motion_notify_event', on_textview_motion_notify_event)
|
||||||
|
|
||||||
def handler(texttag, widget, event, iter_, kind, href):
|
def handler(texttag, widget, event, iter_, kind, href):
|
||||||
if event.type == gtk.gdk.BUTTON_PRESS:
|
if event.type == gtk.gdk.BUTTON_PRESS:
|
||||||
print href
|
print href
|
||||||
|
|
||||||
htmlview.html_hyperlink_handler = handler
|
htmlview.tv.html_hyperlink_handler = handler
|
||||||
|
|
||||||
htmlview.display_html('<div><span style="color: red; text-decoration:underline">Hello</span><br/>\n'
|
htmlview.print_real_text(None, xhtml='<div><span style="color: red; text-decoration:underline">Hello</span><br/>\n'
|
||||||
' <img src="http://images.slashdot.org/topics/topicsoftware.gif"/><br/>\n'
|
' <img src="http://images.slashdot.org/topics/topicsoftware.gif"/><br/>\n'
|
||||||
' <span style="font-size: 500%; font-family: serif">World</span>\n'
|
' <span style="font-size: 500%; font-family: serif">World</span>\n'
|
||||||
'</div>\n')
|
'</div>\n')
|
||||||
htmlview.display_html('<hr />')
|
htmlview.print_real_text(None, xhtml='<hr />')
|
||||||
htmlview.display_html('''
|
htmlview.print_real_text(None, xhtml='''
|
||||||
<p style='font-size:large'>
|
<p style='font-size:large'>
|
||||||
<span style='font-style: italic'>O<span style='font-size:larger'>M</span>G</span>,
|
<span style='font-style: italic'>O<span style='font-size:larger'>M</span>G</span>,
|
||||||
I'm <span style='color:green'>green</span>
|
I'm <span style='color:green'>green</span>
|
||||||
with <span style='font-weight: bold'>envy</span>!
|
with <span style='font-weight: bold'>envy</span>!
|
||||||
</p>
|
</p>
|
||||||
''')
|
''')
|
||||||
htmlview.display_html('<hr />')
|
htmlview.print_real_text(None, xhtml='<hr />')
|
||||||
htmlview.display_html('''
|
htmlview.print_real_text(None, xhtml='''
|
||||||
|
<body xmlns='http://www.w3.org/1999/xhtml'>
|
||||||
|
http://test.com/ testing links autolinkifying
|
||||||
|
</body>
|
||||||
|
''')
|
||||||
|
htmlview.print_real_text(None, xhtml='<hr />')
|
||||||
|
htmlview.print_real_text(None, xhtml='''
|
||||||
<body xmlns='http://www.w3.org/1999/xhtml'>
|
<body xmlns='http://www.w3.org/1999/xhtml'>
|
||||||
<p>As Emerson said in his essay <span style='font-style: italic; background-color:cyan'>Self-Reliance</span>:</p>
|
<p>As Emerson said in his essay <span style='font-style: italic; background-color:cyan'>Self-Reliance</span>:</p>
|
||||||
<p style='margin-left: 5px; margin-right: 2%'>
|
<p style='margin-left: 5px; margin-right: 2%'>
|
||||||
|
@ -1027,8 +974,8 @@ if __name__ == '__main__':
|
||||||
</p>
|
</p>
|
||||||
</body>
|
</body>
|
||||||
''')
|
''')
|
||||||
htmlview.display_html('<hr />')
|
htmlview.print_real_text(None, xhtml='<hr />')
|
||||||
htmlview.display_html('''
|
htmlview.print_real_text(None, xhtml='''
|
||||||
<body xmlns='http://www.w3.org/1999/xhtml'>
|
<body xmlns='http://www.w3.org/1999/xhtml'>
|
||||||
<p style='text-align:center'>Hey, are you licensed to <a href='http://www.jabber.org/'>Jabber</a>?</p>
|
<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'
|
<p style='text-align:right'><img src='http://www.jabber.org/images/psa-license.jpg'
|
||||||
|
@ -1037,8 +984,8 @@ if __name__ == '__main__':
|
||||||
/></p>
|
/></p>
|
||||||
</body>
|
</body>
|
||||||
''')
|
''')
|
||||||
htmlview.display_html('<hr />')
|
htmlview.print_real_text(None, xhtml='<hr />')
|
||||||
htmlview.display_html('''
|
htmlview.print_real_text(None, xhtml='''
|
||||||
<body xmlns='http://www.w3.org/1999/xhtml'>
|
<body xmlns='http://www.w3.org/1999/xhtml'>
|
||||||
<ul style='background-color:rgb(120,140,100)'>
|
<ul style='background-color:rgb(120,140,100)'>
|
||||||
<li> One </li>
|
<li> One </li>
|
||||||
|
@ -1052,8 +999,8 @@ if __name__ == '__main__':
|
||||||
return faciter(n,1)</pre>
|
return faciter(n,1)</pre>
|
||||||
</body>
|
</body>
|
||||||
''')
|
''')
|
||||||
htmlview.display_html('<hr />')
|
htmlview.print_real_text(None, xhtml='<hr />')
|
||||||
htmlview.display_html('''
|
htmlview.print_real_text(None, xhtml='''
|
||||||
<body xmlns='http://www.w3.org/1999/xhtml'>
|
<body xmlns='http://www.w3.org/1999/xhtml'>
|
||||||
<ol style='background-color:rgb(120,140,100)'>
|
<ol style='background-color:rgb(120,140,100)'>
|
||||||
<li> One </li>
|
<li> One </li>
|
||||||
|
@ -1066,12 +1013,12 @@ if __name__ == '__main__':
|
||||||
<li> Three </li></ol>
|
<li> Three </li></ol>
|
||||||
</body>
|
</body>
|
||||||
''')
|
''')
|
||||||
htmlview.show()
|
htmlview.tv.show()
|
||||||
sw = gtk.ScrolledWindow()
|
sw = gtk.ScrolledWindow()
|
||||||
sw.set_property('hscrollbar-policy', gtk.POLICY_AUTOMATIC)
|
sw.set_property('hscrollbar-policy', gtk.POLICY_AUTOMATIC)
|
||||||
sw.set_property('vscrollbar-policy', gtk.POLICY_AUTOMATIC)
|
sw.set_property('vscrollbar-policy', gtk.POLICY_AUTOMATIC)
|
||||||
sw.set_property('border-width', 0)
|
sw.set_property('border-width', 0)
|
||||||
sw.add(htmlview)
|
sw.add(htmlview.tv)
|
||||||
sw.show()
|
sw.show()
|
||||||
frame = gtk.Frame()
|
frame = gtk.Frame()
|
||||||
frame.set_shadow_type(gtk.SHADOW_IN)
|
frame.set_shadow_type(gtk.SHADOW_IN)
|
||||||
|
|
Loading…
Reference in New Issue