~ubuntu-branches/ubuntu/lucid/gajim/lucid-security

« back to all changes in this revision

Viewing changes to src/htmltextview.py

  • Committer: Maia Kozheva
  • Date: 2009-11-25 08:32:36 UTC
  • mfrom: (1.1.16 upstream)
  • Revision ID: sikon@maia-desktop-20091125083236-hkxrujhn3amehuve
Merged new upstream release 0.13

Show diffs side-by-side

added added

removed removed

Lines of Context:
50
50
 
51
51
if __name__ == '__main__':
52
52
        from common import i18n
 
53
        import common.configpaths
 
54
        common.configpaths.gajimpaths.init(None)
53
55
from common import gajim
54
56
 
55
57
import tooltips
91
93
element_styles['i']   = element_styles['em']
92
94
element_styles['b']   = element_styles['strong']
93
95
 
94
 
'''
95
 
==========
96
 
  JEP-0071
97
 
==========
98
 
 
99
 
This Integration Set includes a subset of the modules defined for 
100
 
XHTML 1.0 but does not redefine any existing modules, nor 
101
 
does it define any new modules. Specifically, it includes the 
102
 
following modules only:
103
 
 
104
 
- Structure
105
 
- Text
106
 
  
107
 
  * Block
108
 
    
109
 
    phrasal
110
 
       addr, blockquote, pre
111
 
    Struc
112
 
       div,p
113
 
    Heading
114
 
       h1, h2, h3, h4, h5, h6
115
 
    
116
 
  * Inline
117
 
    
118
 
    phrasal
119
 
       abbr, acronym, cite, code, dfn, em, kbd, q, samp, strong, var
120
 
    structural
121
 
       br, span
122
 
  
123
 
- Hypertext (a)
124
 
- List (ul, ol, dl)
125
 
- Image (img)
126
 
- Style Attribute
127
 
     
128
 
Therefore XHTML-IM uses the following content models:
129
 
 
130
 
  Block.mix
131
 
            Block-like elements, e.g., paragraphs
132
 
  Flow.mix
133
 
            Any block or inline elements
134
 
  Inline.mix
135
 
            Character-level elements
136
 
  InlineNoAnchor.class
137
 
                        Anchor element 
138
 
  InlinePre.mix
139
 
            Pre element
140
 
 
141
 
XHTML-IM also uses the following Attribute Groups:
142
 
 
143
 
Core.extra.attrib
144
 
        TBD
145
 
I18n.extra.attrib
146
 
        TBD
147
 
Common.extra
148
 
        style
149
 
 
150
 
 
151
 
...
152
 
#block level:
153
 
#Heading    h
154
 
#           ( pres           = h1 | h2 | h3 | h4 | h5 | h6 )
155
 
#Block      ( phrasal        = address | blockquote | pre )
156
 
#NOT           ( presentational = hr )
157
 
#           ( structural     = div | p )
158
 
#other:     section
159
 
#Inline     ( phrasal        = abbr | acronym | cite | code | dfn | em | kbd | q | samp | strong | var )
160
 
#NOT        ( presentational =  b  | big | i | small | sub | sup | tt )
161
 
#           ( structural     =  br | span )
162
 
#Param/Legacy    param, font, basefont, center, s, strike, u, dir, menu, isindex
163
 
#
164
 
'''
 
96
# ==========
 
97
#   JEP-0071
 
98
# ==========
 
99
#
 
100
# This Integration Set includes a subset of the modules defined for
 
101
# XHTML 1.0 but does not redefine any existing modules, nor
 
102
# does it define any new modules. Specifically, it includes the
 
103
# following modules only:
 
104
#
 
105
# - Structure
 
106
# - Text
 
107
#
 
108
#   * Block
 
109
#
 
110
#     phrasal
 
111
#        addr, blockquote, pre
 
112
#     Struc
 
113
#        div,p
 
114
#     Heading
 
115
#        h1, h2, h3, h4, h5, h6
 
116
#
 
117
#   * Inline
 
118
#
 
119
#     phrasal
 
120
#        abbr, acronym, cite, code, dfn, em, kbd, q, samp, strong, var
 
121
#     structural
 
122
#        br, span
 
123
#
 
124
# - Hypertext (a)
 
125
# - List (ul, ol, dl)
 
126
# - Image (img)
 
127
# - Style Attribute
 
128
#
 
129
# Therefore XHTML-IM uses the following content models:
 
130
#
 
131
#   Block.mix
 
132
#             Block-like elements, e.g., paragraphs
 
133
#   Flow.mix
 
134
#             Any block or inline elements
 
135
#   Inline.mix
 
136
#             Character-level elements
 
137
#   InlineNoAnchor.class
 
138
#                       Anchor element
 
139
#   InlinePre.mix
 
140
#             Pre element
 
141
#
 
142
# XHTML-IM also uses the following Attribute Groups:
 
143
#
 
144
# Core.extra.attrib
 
145
#       TBD
 
146
# I18n.extra.attrib
 
147
#       TBD
 
148
# Common.extra
 
149
#       style
 
150
#
 
151
#
 
152
# ...
 
153
# block level:
 
154
# Heading    h
 
155
#            ( pres           = h1 | h2 | h3 | h4 | h5 | h6 )
 
156
# Block      ( phrasal        = address | blockquote | pre )
 
157
# NOT           ( presentational = hr )
 
158
#            ( structural     = div | p )
 
159
# other:     section
 
160
# Inline     ( phrasal        = abbr | acronym | cite | code | dfn | em |
 
161
#                               kbd | q | samp | strong | var )
 
162
# NOT        ( presentational =  b  | big | i | small | sub | sup | tt )
 
163
#            ( structural     =  br | span )
 
164
# Param/Legacy    param, font, basefont, center, s, strike, u, dir, menu,
 
165
#                 isindex
165
166
 
166
167
BLOCK_HEAD = set(( 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', ))
167
168
BLOCK_PHRASAL = set(( 'address', 'blockquote', 'pre', ))
185
186
                                                                                                        ('font-weight: bold', 'font-style: oblique')[weigth],
186
187
                                                                                          )
187
188
 
188
 
 
189
 
def build_patterns(view, config, interface):
190
 
        # extra, rst does not mark _underline_ or /it/ up
191
 
        # actually <b>, <i> or <u> are not in the JEP-0071, but are seen in the wild
192
 
        basic_pattern = r'(?<!\w|\<|/|:)' r'/[^\s/]' r'([^/]*[^\s/])?' r'/(?!\w|/|:)|'\
193
 
                                        r'(?<!\w)' r'_[^\s_]' r'([^_]*[^\s_])?' r'_(?!\w)'
194
 
        view.basic_pattern_re = re.compile(basic_pattern)
195
 
        # emoticons
196
 
        emoticons_pattern = ''
197
 
        if config.get('emoticons_theme'):
198
 
                emoticons_pattern = gajim.interface.emot_only
199
 
 
200
 
        view.emot_pattern_re = re.compile(emoticons_pattern, re.IGNORECASE)
201
 
        # because emoticons match later (in the string) they need to be after
202
 
        # basic matches that may occur earlier
203
 
        emot_and_basic_pattern = basic_pattern + emoticons_pattern
204
 
        view.emot_and_basic_re = re.compile(emot_and_basic_pattern, re.IGNORECASE)
205
 
 
206
 
 
207
189
def _parse_css_color(color):
208
190
        '''_parse_css_color(css_color) -> gtk.gdk.Color'''
209
191
        if color.startswith('rgb(') and color.endswith(')'):
213
195
                return gtk.gdk.color_parse(color)
214
196
 
215
197
def style_iter(style):
216
 
        return (map(lambda x:x.strip(),item.split(':', 1)) for item in style.split(';') if len(item.strip()))
217
 
        
 
198
        return ([x.strip() for x in item.split(':', 1)] for item in style.split(';')\
 
199
                if len(item.strip()))
 
200
 
218
201
 
219
202
class HtmlHandler(xml.sax.handler.ContentHandler):
220
203
        """A handler to display html to a gtk textview.
222
205
        It keeps a stack of "style spans" (start/end element pairs)
223
206
        and a stack of list counters, for nested lists.
224
207
        """
225
 
        def __init__(self, textview, startiter):
 
208
        def __init__(self, conv_textview, startiter):
226
209
                xml.sax.handler.ContentHandler.__init__(self)
227
 
                self.textbuf = textview.get_buffer()
228
 
                self.textview = textview
 
210
                self.textbuf = conv_textview.tv.get_buffer()
 
211
                self.textview = conv_textview.tv
229
212
                self.iter = startiter
 
213
                self.conv_textview = conv_textview
230
214
                self.text = ''
231
215
                self.starting=True
232
216
                self.preserve = False
244
228
                tag.set_property('paragraph-background-gdk', color)
245
229
 
246
230
 
247
 
        #FIXME: when we migrate to 2.10 rm this
248
 
        if gtk.gtk_version >= (2, 8, 5) or gobject.pygtk_version >= (2, 8, 1):
249
 
 
250
 
                def _get_current_attributes(self):
251
 
                        attrs = self.textview.get_default_attributes()
252
 
                        self.iter.backward_char()
253
 
                        self.iter.get_attributes(attrs)
254
 
                        self.iter.forward_char()
255
 
                        return attrs
256
 
                
257
 
        else:
258
 
                
259
 
                # Workaround http://bugzilla.gnome.org/show_bug.cgi?id=317455
260
 
                def _get_current_style_attr(self, propname, comb_oper=None):
261
 
                        tags = [tag for tag in self.styles if tag is not None]
262
 
                        tags.reverse()
263
 
                        is_set_name = propname + '-set'
264
 
                        value = None
265
 
                        for tag in tags:
266
 
                                if tag.get_property(is_set_name):
267
 
                                        if value is None:
268
 
                                                value = tag.get_property(propname)
269
 
                                                if comb_oper is None:
270
 
                                                        return value
271
 
                                        else:
272
 
                                                value = comb_oper(value, tag.get_property(propname))
273
 
                        return value
274
 
 
275
 
                class _FakeAttrs(object):
276
 
                        __slots__ = ('font', 'font_scale')
277
 
 
278
 
                def _get_current_attributes(self):
279
 
                        attrs = self._FakeAttrs()
280
 
                        attrs.font_scale = self._get_current_style_attr('scale',
281
 
                                                                                                                        operator.mul)
282
 
                        if attrs.font_scale is None:
283
 
                                attrs.font_scale = 1.0
284
 
                        attrs.font = self._get_current_style_attr('font-desc')
285
 
                        if attrs.font is None:
286
 
                                attrs.font = self.textview.style.font_desc
287
 
                        return attrs
288
 
 
 
231
        def _get_current_attributes(self):
 
232
                attrs = self.textview.get_default_attributes()
 
233
                self.iter.backward_char()
 
234
                self.iter.get_attributes(attrs)
 
235
                self.iter.forward_char()
 
236
                return attrs
289
237
 
290
238
        def __parse_length_frac_size_allocate(self, textview, allocation,
291
239
                                                                                  frac, callback, args):
299
247
                        sign = cmp(val,0)
300
248
                        # limits: 1% to 500%
301
249
                        val = sign*max(1,min(abs(val),500))
302
 
                        frac = val/100 
 
250
                        frac = val/100
303
251
                        if font_relative:
304
252
                                attrs = self._get_current_attributes()
305
253
                                font_size = attrs.font.get_size() / pango.SCALE
352
300
                                callback(val, *args)
353
301
                        except Exception:
354
302
                                warnings.warn('Unable to parse length value "%s"' % value)
355
 
                
 
303
 
356
304
        def __parse_font_size_cb(length, tag):
357
305
                tag.set_property('size-points', length/display_resolution)
358
306
        __parse_font_size_cb = staticmethod(__parse_font_size_cb)
406
354
                        length += styles[-1].get_property(propname)
407
355
                tag.set_property(propname, length)
408
356
        #__frac_length_tag_cb = staticmethod(__frac_length_tag_cb)
409
 
                
 
357
 
410
358
        def _parse_style_margin_left(self, tag, value):
411
359
                # block relative
412
360
                self._parse_length(value, False, True, 1, 1000, self.__frac_length_tag_cb,
453
401
                        warnings.warn('Invalid text-align:%s requested' % value)
454
402
                else:
455
403
                        tag.set_property('justification', align)
456
 
        
 
404
 
457
405
        def _parse_style_text_decoration(self, tag, value):
458
406
                values = value.split(' ')
459
407
                if 'none' in values:
471
419
                        warnings.warn('text-decoration:blink not implemented')
472
420
                if 'overline' in values:
473
421
                        warnings.warn('text-decoration:overline not implemented')
474
 
        
 
422
 
475
423
        def _parse_style_white_space(self, tag, value):
476
424
                if value == 'pre':
477
425
                        tag.set_property('wrap_mode', gtk.WRAP_NONE)
485
433
                        tag.set_property(propname, value)
486
434
                except Exception:
487
435
                        gajim.log.warn( "Error with prop: " + propname + " for tag: " + str(tag))
488
 
                
 
436
 
489
437
 
490
438
        def _parse_style_width(self, tag, value):
491
439
                if value == 'auto':
497
445
                        return
498
446
                self._parse_length(value, False, False, 1, 1000, self.__length_tag_cb,
499
447
                                                   tag, "height")
500
 
         
501
 
        
 
448
 
 
449
 
502
450
        # build a dictionary mapping styles to methods, for greater speed
503
451
        __style_methods = dict()
504
452
        for style in ('background-color', 'color', 'font-family', 'font-size',
525
473
                        tag.href = href
526
474
                        tag.type_ = type_ # to be used by the URL handler
527
475
                        tag.connect('event', self.textview.html_hyperlink_handler, 'url', href)
528
 
                        tag.set_property('foreground', '#0000ff')
 
476
                        tag.set_property('foreground', gajim.config.get('urlmsgcolor'))
529
477
                        tag.set_property('underline', pango.UNDERLINE_SINGLE)
530
478
                        tag.is_anchor = True
531
479
                if title:
535
483
        def _process_img(self, attrs):
536
484
                '''Process a img tag.
537
485
                '''
 
486
                mem = ''
538
487
                try:
539
 
                        # Wait maximum 1s for connection 
 
488
                        # Wait maximum 1s for connection
540
489
                        socket.setdefaulttimeout(1)
541
 
                        try: 
542
 
                                f = urllib2.urlopen(attrs['src']) 
543
 
                        except Exception, ex: 
 
490
                        try:
 
491
                                f = urllib2.urlopen(attrs['src'])
 
492
                        except Exception, ex:
544
493
                                gajim.log.debug('Error loading image %s ' % attrs['src']  + str(ex))
545
 
                                pixbuf = None 
546
 
                                alt = attrs.get('alt', 'Broken image') 
547
 
                        else: 
548
 
                                # Wait 0.1s between each byte 
549
 
                                try: 
550
 
                                        f.fp._sock.fp._sock.settimeout(0.5) 
551
 
                                except Exception: 
552
 
                                        pass 
553
 
                        # Max image size = 2 MB (to try to prevent DoS)
554
 
                        mem = ''
555
 
                        deadline = time.time() + 3
556
 
                        while True:
557
 
                                if time.time() > deadline:
558
 
                                        gajim.log.debug(str('Timeout loading image %s ' % \
559
 
                                                attrs['src'] + ex))
560
 
                                        mem = ''
561
 
                                        alt = attrs.get('alt', '')
562
 
                                        if alt:
563
 
                                                alt += '\n'
564
 
                                        alt += _('Timeout loading image')
565
 
                                        break
 
494
                                pixbuf = None
 
495
                                alt = attrs.get('alt', 'Broken image')
 
496
                        else:
 
497
                                # Wait 0.1s between each byte
566
498
                                try:
567
 
                                        temp = f.read(100)
568
 
                                except socket.timeout, ex:
569
 
                                        gajim.log.debug('Timeout loading image %s ' % attrs['src'] + \
570
 
                                                str(ex))
571
 
                                        mem = ''
572
 
                                        alt = attrs.get('alt', '')
573
 
                                        if alt:
574
 
                                                alt += '\n'
575
 
                                        alt += _('Timeout loading image')
576
 
                                        break
577
 
                                if temp:
578
 
                                        mem += temp
579
 
                                else:
580
 
                                        break
581
 
                                if len(mem) > 2*1024*1024:
582
 
                                        alt = attrs.get('alt', '')
583
 
                                        if alt:
584
 
                                                alt += '\n'
585
 
                                        alt += _('Image is too big')
586
 
                                        break
 
499
                                        f.fp._sock.fp._sock.settimeout(0.5)
 
500
                                except Exception:
 
501
                                        pass
 
502
                                # Max image size = 2 MB (to try to prevent DoS)
 
503
                                deadline = time.time() + 3
 
504
                                while True:
 
505
                                        if time.time() > deadline:
 
506
                                                gajim.log.debug(str('Timeout loading image %s ' % \
 
507
                                                        attrs['src'] + ex))
 
508
                                                mem = ''
 
509
                                                alt = attrs.get('alt', '')
 
510
                                                if alt:
 
511
                                                        alt += '\n'
 
512
                                                alt += _('Timeout loading image')
 
513
                                                break
 
514
                                        try:
 
515
                                                temp = f.read(100)
 
516
                                        except socket.timeout, ex:
 
517
                                                gajim.log.debug('Timeout loading image %s ' % attrs['src'] + \
 
518
                                                        str(ex))
 
519
                                                alt = attrs.get('alt', '')
 
520
                                                if alt:
 
521
                                                        alt += '\n'
 
522
                                                alt += _('Timeout loading image')
 
523
                                                break
 
524
                                        if temp:
 
525
                                                mem += temp
 
526
                                        else:
 
527
                                                break
 
528
                                        if len(mem) > 2*1024*1024:
 
529
                                                alt = attrs.get('alt', '')
 
530
                                                if alt:
 
531
                                                        alt += '\n'
 
532
                                                alt += _('Image is too big')
 
533
                                                break
587
534
                        pixbuf = None
588
535
                        if mem:
589
536
                                # Caveat: GdkPixbuf is known not to be safe to load
691
638
 
692
639
        def _starts_line(self):
693
640
                return self.starting or self.iter.starts_line()
694
 
                
 
641
 
695
642
        def _flush_text(self):
696
643
                if not self.text: return
697
644
                text, self.text = self.text, ''
708
655
                return False
709
656
 
710
657
        def handle_specials(self, text):
711
 
                index = 0
712
 
                se = self.textview.config.get('show_ascii_formatting_chars')
713
 
                af = gajim.config.get('ascii_formatting')
714
 
                if self.textview.config.get('emoticons_theme'):
715
 
                        if af:
716
 
                                iterator = self.textview.emot_and_basic_re.finditer(text)
717
 
                        else:
718
 
                                iterator = self.textview.emot_pattern_re.finditer(text)
719
 
                elif af:
720
 
                        iterator = self.textview.basic_pattern_re.finditer(text)
721
 
                else:
722
 
                        iterator = []
723
 
                for match in iterator:
724
 
                        start, end = match.span()
725
 
                        special_text = text[start:end]
726
 
                        if start != 0:
727
 
                                self._insert_text(text[index:start])
728
 
                        index = end # update index
729
 
                        #emoticons
730
 
                        possible_emot_ascii_caps = special_text.upper() # emoticons keys are CAPS
731
 
                        if self.textview.config.get('emoticons_theme') and \
732
 
                                        possible_emot_ascii_caps in self.textview.interface.emoticons.keys():
733
 
                                #it's an emoticon
734
 
                                emot_ascii = possible_emot_ascii_caps
735
 
                                anchor = self.textbuf.create_child_anchor(self.iter)
736
 
                                img = gtk.Image()
737
 
                                img.set_from_file(self.textview.interface.emoticons[emot_ascii])
738
 
                                img.show()
739
 
                                # TODO: add alt/tooltip with the special_text (a11y) 
740
 
                                self.textview.add_child_at_anchor(img, anchor)
741
 
                        elif af:
742
 
                                # now print it
743
 
                                if special_text.startswith('/'): # it's explicit italics
744
 
                                        self.startElement('i', {})
745
 
                                elif special_text.startswith('_'): # it's explicit underline
746
 
                                        self.startElement('u', {})
747
 
                                if se: self._insert_text(special_text[0])
748
 
                                self.handle_specials(special_text[1:-1])
749
 
                                if se: self._insert_text(special_text[0])
750
 
                                if special_text.startswith('_'): # it's explicit underline
751
 
                                        self.endElement('u')
752
 
                                if special_text.startswith('/'): # it's explicit italics
753
 
                                        self.endElement('i')
754
 
                if index < len(text):
755
 
                        self._insert_text(text[index:])
756
 
                
 
658
                self.iter = self.conv_textview.detect_and_print_special_text(text,                                                      self._get_style_tags())
 
659
 
757
660
        def characters(self, content):
758
661
                if self.preserve:
759
662
                        self.text += content
778
681
                #FIXME: if we want to use id, it needs to be unique across
779
682
                # the whole textview, so we need to add something like the
780
683
                # message-id to it.
781
 
                #id_ = attrs.get('id',None) 
 
684
                #id_ = attrs.get('id',None)
782
685
                id_ = None
783
686
                if name == 'a':
784
687
                        #TODO: accesskey, charset, hreflang, rel, rev, tabindex, type
801
704
                        tag = self._process_img(attrs)
802
705
                if name in element_styles:
803
706
                        style += element_styles[name]
804
 
                # so that explicit styles override implicit ones, 
 
707
                # so that explicit styles override implicit ones,
805
708
                # we add the attribute last
806
709
                style += ";"+attrs.get('style','')
807
710
                if style == '':
808
 
                        style = None        
 
711
                        style = None
809
712
                self._begin_span(style, tag, id_)
810
713
 
811
714
                if name == 'br':
891
794
                #    self.text = ' '
892
795
 
893
796
class HtmlTextView(gtk.TextView):
894
 
        
 
797
 
895
798
        def __init__(self):
896
799
                gobject.GObject.__init__(self)
897
800
                self.set_wrap_mode(gtk.WRAP_CHAR)
906
809
                self.config = gajim.config
907
810
                self.interface = gajim.interface
908
811
                # end big hack
909
 
                build_patterns(self,gajim.config,gajim.interface)
910
812
 
911
813
        def __destroy_event(self, widget):
912
814
                if self.tooltip.timeout != 0:
941
843
                x, y, _ = widget.window.get_pointer()
942
844
                x, y = widget.window_to_buffer_coords(gtk.TEXT_WINDOW_TEXT, x, y)
943
845
                tags = widget.get_iter_at_location(x, y).get_tags()
944
 
                is_over_anchor = False
945
 
                for tag in tags:
946
 
                        if getattr(tag, 'is_anchor', False):
947
 
                                is_over_anchor = True
948
 
                                break
 
846
                anchor_tags = [tag for tag in tags if getattr(tag, 'is_anchor', False)]
949
847
                if self.tooltip.timeout != 0:
950
848
                        # Check if we should hide the line tooltip
951
 
                        if not is_over_anchor:
 
849
                        if not anchor_tags:
952
850
                                self.tooltip.hide_tooltip()
953
 
                if not self._changed_cursor and is_over_anchor:
 
851
                if not self._changed_cursor and anchor_tags:
954
852
                        window = widget.get_window(gtk.TEXT_WINDOW_TEXT)
955
853
                        window.set_cursor(gtk.gdk.Cursor(gtk.gdk.HAND2))
956
854
                        self._changed_cursor = True
957
 
                        self.tooltip.timeout = gobject.timeout_add(500, self.show_tooltip, tag)
958
 
                elif self._changed_cursor and not is_over_anchor:
 
855
                        self.tooltip.timeout = gobject.timeout_add(500, self.show_tooltip, anchor_tags[0])
 
856
                elif self._changed_cursor and not anchor_tags:
959
857
                        window = widget.get_window(gtk.TEXT_WINDOW_TEXT)
960
858
                        window.set_cursor(gtk.gdk.Cursor(gtk.gdk.XTERM))
961
859
                        self._changed_cursor = False
962
860
                return False
963
861
 
964
 
        def display_html(self, html):
965
 
                buffer = self.get_buffer()
966
 
                eob = buffer.get_end_iter()
 
862
        def display_html(self, html, conv_textview):
 
863
                buffer_ = self.get_buffer()
 
864
                eob = buffer_.get_end_iter()
967
865
                ## this works too if libxml2 is not available
968
866
                # parser = xml.sax.make_parser(['drv_libxml2'])
969
867
                # parser.setFeature(xml.sax.handler.feature_validation, True)
970
868
                parser = xml.sax.make_parser()
971
 
                parser.setContentHandler(HtmlHandler(self, eob))
 
869
                parser.setContentHandler(HtmlHandler(conv_textview, eob))
972
870
                parser.parse(StringIO(html))
973
 
                
 
871
 
974
872
                # too much space after :)
975
873
                #if not eob.starts_line():
976
 
                #    buffer.insert(eob, '\n')
 
874
                #    buffer_.insert(eob, '\n')
977
875
 
978
876
 
979
877
 
981
879
 
982
880
if __name__ == '__main__':
983
881
        import os
984
 
        from common import gajim
 
882
 
 
883
        from conversation_textview import ConversationTextview
 
884
        import gajim as gaj
985
885
 
986
886
        class log(object):
987
887
 
994
894
 
995
895
        gajim.log=log()
996
896
 
997
 
        if gajim.config.get('emoticons_theme'):
998
 
                print "emoticons"
 
897
        gaj.Interface()
999
898
 
1000
 
        htmlview = HtmlTextView()
 
899
        htmlview = ConversationTextview(None)
1001
900
 
1002
901
        path_to_file = os.path.join(gajim.DATA_DIR, 'pixmaps', 'muc_separator.png')
1003
902
        # use this for hr
1004
 
        htmlview.focus_out_line_pixbuf =  gtk.gdk.pixbuf_new_from_file(path_to_file)
 
903
        htmlview.tv.focus_out_line_pixbuf =  gtk.gdk.pixbuf_new_from_file(path_to_file)
1005
904
 
1006
905
 
1007
906
        tooltip = tooltips.BaseTooltip()
1008
907
        def on_textview_motion_notify_event(widget, event):
1009
908
                '''change the cursor to a hand when we are over a mail or an url'''
1010
909
                global change_cursor
1011
 
                pointer_x, pointer_y, spam = htmlview.window.get_pointer()
1012
 
                x, y = htmlview.window_to_buffer_coords(gtk.TEXT_WINDOW_TEXT, pointer_x,
 
910
                pointer_x, pointer_y = htmlview.tv.window.get_pointer()[0:2]
 
911
                x, y = htmlview.tv.window_to_buffer_coords(gtk.TEXT_WINDOW_TEXT, pointer_x,
1013
912
                                                                   pointer_y)
1014
 
                tags = htmlview.get_iter_at_location(x, y).get_tags()
 
913
                tags = htmlview.tv.get_iter_at_location(x, y).get_tags()
1015
914
                if change_cursor:
1016
 
                        htmlview.get_window(gtk.TEXT_WINDOW_TEXT).set_cursor(
 
915
                        htmlview.tv.get_window(gtk.TEXT_WINDOW_TEXT).set_cursor(
1017
916
                                         gtk.gdk.Cursor(gtk.gdk.XTERM))
1018
917
                        change_cursor = None
1019
 
                tag_table = htmlview.get_buffer().get_tag_table()
1020
 
                over_line = False
 
918
                tag_table = htmlview.tv.get_buffer().get_tag_table()
1021
919
                for tag in tags:
1022
920
                        try:
1023
921
                                if tag.is_anchor:
1024
 
                                        htmlview.get_window(gtk.TEXT_WINDOW_TEXT).set_cursor(
 
922
                                        htmlview.tv.get_window(gtk.TEXT_WINDOW_TEXT).set_cursor(
1025
923
                                                                                gtk.gdk.Cursor(gtk.gdk.HAND2))
1026
924
                                        change_cursor = tag
1027
925
                                elif tag == tag_table.lookup('focus-out-line'):
1028
926
                                        over_line = True
1029
 
                        except: pass
 
927
                        except Exception:
 
928
                                pass
1030
929
 
1031
930
                #if line_tooltip.timeout != 0:
1032
931
                        # Check if we should hide the line tooltip
1035
934
                #if over_line and not line_tooltip.win:
1036
935
                #       line_tooltip.timeout = gobject.timeout_add(500,
1037
936
                #               show_line_tooltip)
1038
 
                #       htmlview.get_window(gtk.TEXT_WINDOW_TEXT).set_cursor(
 
937
                #       htmlview.tv.get_window(gtk.TEXT_WINDOW_TEXT).set_cursor(
1039
938
                #               gtk.gdk.Cursor(gtk.gdk.LEFT_PTR))
1040
939
                #       change_cursor = tag
1041
940
 
1042
 
        htmlview.connect('motion_notify_event', on_textview_motion_notify_event)
 
941
        htmlview.tv.connect('motion_notify_event', on_textview_motion_notify_event)
1043
942
 
1044
943
        def handler(texttag, widget, event, iter_, kind, href):
1045
944
                if event.type == gtk.gdk.BUTTON_PRESS:
1046
945
                        print href
1047
946
 
1048
 
        htmlview.html_hyperlink_handler = handler
 
947
        htmlview.tv.html_hyperlink_handler = handler
1049
948
 
1050
 
        htmlview.display_html('<div><span style="color: red; text-decoration:underline">Hello</span><br/>\n'
 
949
        htmlview.print_real_text(None, xhtml='<div><span style="color: red; text-decoration:underline">Hello</span><br/>\n'
1051
950
                                                  '  <img src="http://images.slashdot.org/topics/topicsoftware.gif"/><br/>\n'
1052
951
                                                  '  <span style="font-size: 500%; font-family: serif">World</span>\n'
1053
952
                                                  '</div>\n')
1054
 
        htmlview.display_html('<hr />')
1055
 
        htmlview.display_html('''
 
953
        htmlview.print_real_text(None, xhtml='<hr />')
 
954
        htmlview.print_real_text(None, xhtml='''<body xmlns='http://www.w3.org/1999/xhtml'><p xmlns='http://www.w3.org/1999/xhtml'>a:b<a href='http://google.com/' xmlns='http://www.w3.org/1999/xhtml'>Google</a></p><br/></body>''')
 
955
        htmlview.print_real_text(None, xhtml='''
 
956
         <body xmlns='http://www.w3.org/1999/xhtml'>
1056
957
          <p style='font-size:large'>
1057
 
                <span style='font-style: italic'>O<span style='font-size:larger'>M</span>G</span>, 
 
958
                <span style='font-style: italic'>O<span style='font-size:larger'>M</span>G</span>,
1058
959
                I&apos;m <span style='color:green'>green</span>
1059
960
                with <span style='font-weight: bold'>envy</span>!
1060
961
          </p>
1061
 
                ''')
1062
 
        htmlview.display_html('<hr />')
1063
 
        htmlview.display_html('''
 
962
         </body>
 
963
                ''')
 
964
        htmlview.print_real_text(None, xhtml='<hr />')
 
965
        htmlview.print_real_text(None, xhtml='''
 
966
        <body xmlns='http://www.w3.org/1999/xhtml'>
 
967
                http://test.com/  testing links autolinkifying  
 
968
        </body>
 
969
                ''')
 
970
        htmlview.print_real_text(None, xhtml='<hr />')
 
971
        htmlview.print_real_text(None, xhtml='''
1064
972
        <body xmlns='http://www.w3.org/1999/xhtml'>
1065
973
          <p>As Emerson said in his essay <span style='font-style: italic; background-color:cyan'>Self-Reliance</span>:</p>
1066
974
          <p style='margin-left: 5px; margin-right: 2%'>
1068
976
          </p>
1069
977
        </body>
1070
978
                ''')
1071
 
        htmlview.display_html('<hr />')
1072
 
        htmlview.display_html('''
 
979
        htmlview.print_real_text(None, xhtml='<hr />')
 
980
        htmlview.print_real_text(None, xhtml='''
1073
981
        <body xmlns='http://www.w3.org/1999/xhtml'>
1074
982
          <p style='text-align:center'>Hey, are you licensed to <a href='http://www.jabber.org/'>Jabber</a>?</p>
1075
983
          <p style='text-align:right'><img src='http://www.jabber.org/images/psa-license.jpg'
1076
 
                          alt='A License to Jabber' 
1077
 
                          width='50%' height='50%' 
 
984
                          alt='A License to Jabber'
 
985
                          width='50%' height='50%'
1078
986
                          /></p>
1079
987
        </body>
1080
988
                ''')
1081
 
        htmlview.display_html('<hr />')
1082
 
        htmlview.display_html('''
 
989
        htmlview.print_real_text(None, xhtml='<hr />')
 
990
        htmlview.print_real_text(None, xhtml='''
1083
991
        <body xmlns='http://www.w3.org/1999/xhtml'>
1084
992
          <ul style='background-color:rgb(120,140,100)'>
1085
993
           <li> One </li>
1086
994
           <li> Two </li>
1087
995
           <li> Three </li>
1088
996
          </ul><hr /><pre style="background-color:rgb(120,120,120)">def fac(n):
1089
 
  def faciter(n,acc): 
 
997
  def faciter(n,acc):
1090
998
        if n==0: return acc
1091
999
        return faciter(n-1, acc*n)
1092
1000
  if n&lt;0: raise ValueError('Must be non-negative')
1093
1001
  return faciter(n,1)</pre>
1094
1002
        </body>
1095
1003
                ''')
1096
 
        htmlview.display_html('<hr />')
1097
 
        htmlview.display_html('''
 
1004
        htmlview.print_real_text(None, xhtml='<hr />')
 
1005
        htmlview.print_real_text(None, xhtml='''
1098
1006
        <body xmlns='http://www.w3.org/1999/xhtml'>
1099
1007
         <ol style='background-color:rgb(120,140,100)'>
1100
1008
           <li> One </li>
1107
1015
           <li> Three </li></ol>
1108
1016
        </body>
1109
1017
                ''')
1110
 
        htmlview.show()
 
1018
        htmlview.tv.show()
1111
1019
        sw = gtk.ScrolledWindow()
1112
1020
        sw.set_property('hscrollbar-policy', gtk.POLICY_AUTOMATIC)
1113
1021
        sw.set_property('vscrollbar-policy', gtk.POLICY_AUTOMATIC)
1114
1022
        sw.set_property('border-width', 0)
1115
 
        sw.add(htmlview)
 
1023
        sw.add(htmlview.tv)
1116
1024
        sw.show()
1117
1025
        frame = gtk.Frame()
1118
1026
        frame.set_shadow_type(gtk.SHADOW_IN)