From eedd0c2a72c0ceaf37513324271c8212666878c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philipp=20H=C3=B6rist?= Date: Fri, 16 Nov 2018 18:28:41 +0100 Subject: [PATCH] HtmlTextView: Fix pylint errors and minor refactoring --- gajim/htmltextview.py | 237 +++++++++++++++++++++--------------------- 1 file changed, 118 insertions(+), 119 deletions(-) diff --git a/gajim/htmltextview.py b/gajim/htmltextview.py index 20bef8b49..290d286b2 100644 --- a/gajim/htmltextview.py +++ b/gajim/htmltextview.py @@ -56,34 +56,32 @@ from gajim.gui_menu_builder import get_conv_context_menu log = logging.getLogger('gajim.htmlview') -__all__ = ['HtmlTextView'] - whitespace_rx = re.compile('\\s+') allwhitespace_rx = re.compile('^\\s*$') # embryo of CSS classes classes = { - #'system-message':';display: none', - 'problematic': ';color: red', + #'system-message':';display: none', + 'problematic': ';color: red', } # styles for elements _element_styles = { - 'u' : ';text-decoration: underline', - 'em' : ';font-style: oblique', - 'cite' : '; background-color:rgb(170,190,250);' - 'font-style: oblique', - 'li' : '; margin-left: 1em; margin-right: 10%', - 'strong' : ';font-weight: bold', - 'pre' : '; background-color:rgb(190,190,190);' - 'font-family: monospace; white-space: pre;' - 'margin-left: 1em; margin-right: 10%', - 'kbd' : ';background-color:rgb(210,210,210);' - 'font-family: monospace', - 'blockquote' : '; background-color:rgb(170,190,250);' - 'margin-left: 2em; margin-right: 10%', - 'dt' : ';font-weight: bold; font-style: oblique', - 'dd' : ';margin-left: 2em; font-style: oblique' + 'u' : ';text-decoration: underline', + 'em' : ';font-style: oblique', + 'cite' : '; background-color:rgb(170,190,250);' + 'font-style: oblique', + 'li' : '; margin-left: 1em; margin-right: 10%', + 'strong' : ';font-weight: bold', + 'pre' : '; background-color:rgb(190,190,190);' + 'font-family: monospace; white-space: pre;' + 'margin-left: 1em; margin-right: 10%', + 'kbd' : ';background-color:rgb(210,210,210);' + 'font-family: monospace', + 'blockquote' : '; background-color:rgb(170,190,250);' + 'margin-left: 2em; margin-right: 10%', + 'dt' : ';font-weight: bold; font-style: oblique', + 'dd' : ';margin-left: 2em; font-style: oblique' } # no difference for the moment _element_styles['dfn'] = _element_styles['em'] @@ -93,6 +91,12 @@ _element_styles['tt'] = _element_styles['kbd'] _element_styles['i'] = _element_styles['em'] _element_styles['b'] = _element_styles['strong'] +_supported_style_attrs = [ + 'background-color', 'color', 'font-family', 'font-size', 'font-style', + 'font-weight', 'margin-left', 'margin-right', 'text-align', + 'text-decoration', 'white-space', 'display', 'width', 'height' +] + # ========== # XEP-0071 # ========== @@ -182,8 +186,9 @@ for _name in BLOCK_HEAD: _num = int(_name[1]) _header_size = (_num - 1) // 2 _weight = (_num - 1) % 2 - _element_styles[_name] = '; font-size: %s; %s' % (('large', 'medium', 'small')[_header_size], - ('font-weight: bold', 'font-style: oblique')[_weight],) + _element_styles[_name] = '; font-size: %s; %s' % ( + ('large', 'medium', 'small')[_header_size], + ('font-weight: bold', 'font-style: oblique')[_weight]) def _parse_css_color(color): if color.startswith('rgb(') and color.endswith(')'): @@ -216,26 +221,35 @@ class HtmlHandler(xml.sax.handler.ContentHandler): self.list_counters = [] # stack (top at head) of list # counters, or None for unordered list + # build a dictionary mapping styles to methods + self.__style_methods = {} + for style in _supported_style_attrs: + method_names = '_parse_style_%s' % style.replace('-', '_') + self.__style_methods[style] = method_names + def _get_points_from_pixels(self, pixels): resolution = self.textview.get_screen().get_resolution() # points = pixels * 72 / resolution return pixels * 72 / resolution - def _parse_style_color(self, tag, value): + @staticmethod + def _parse_style_color(tag, value): color = _parse_css_color(value) tag.set_property('foreground-gdk', color) - def _parse_style_background_color(self, tag, value): + @staticmethod + def _parse_style_background_color(tag, value): color = _parse_css_color(value) tag.set_property('background-gdk', color) tag.set_property('paragraph-background-gdk', color) - def __parse_length_frac_size_allocate(self, textview, allocation, frac, - callback, args): + @staticmethod + def __parse_length_frac_size_allocate(_textview, allocation, frac, + callback, args): callback(allocation.width*frac, *args) def _parse_length(self, value, font_relative, block_relative, minl, maxl, - callback, *args): + callback, *args): """ Parse/calc length, converting to pixels, calls callback(length, *args) when the length is first computed or changes @@ -259,11 +273,11 @@ class HtmlHandler(xml.sax.handler.ContentHandler): # This is difficult/impossible to implement, so we use # textview width instead; a reasonable approximation.. alloc = self.textview.get_allocation() - self.__parse_length_frac_size_allocate(self.textview, alloc, - frac, callback, args) + self.__parse_length_frac_size_allocate( + self.textview, alloc, frac, callback, args) self.textview.connect('size-allocate', - self.__parse_length_frac_size_allocate, - frac, callback, args) + self.__parse_length_frac_size_allocate, + frac, callback, args) else: callback(frac, *args) return @@ -324,7 +338,8 @@ class HtmlHandler(xml.sax.handler.ContentHandler): elif type_ == 'px': tag.set_property('size-points', self._get_points_from_pixels(size)) - def _parse_style_display(self, tag, value): + @staticmethod + def _parse_style_display(tag, value): if value == 'none': tag.set_property('invisible', 'true') # FIXME: display: block, inline @@ -355,13 +370,14 @@ class HtmlHandler(xml.sax.handler.ContentHandler): self._parse_length( value, True, False, 5, 110, self.__parse_font_size_cb, tag) - def _parse_style_font_style(self, tag, value): + @staticmethod + def _parse_style_font_style(tag, value): try: style = { - 'normal': Pango.Style.NORMAL, - 'italic': Pango.Style.ITALIC, - 'oblique': Pango.Style.OBLIQUE, - }[value] + 'normal': Pango.Style.NORMAL, + 'italic': Pango.Style.ITALIC, + 'oblique': Pango.Style.OBLIQUE, + }[value] except KeyError: log.warning('unknown font-style %s', value) else: @@ -376,51 +392,55 @@ class HtmlHandler(xml.sax.handler.ContentHandler): def _parse_style_margin_left(self, tag, value): # block relative self._parse_length(value, False, True, 1, 1000, - self.__frac_length_tag_cb, tag, 'left-margin') + self.__frac_length_tag_cb, tag, 'left-margin') def _parse_style_margin_right(self, tag, value): # block relative self._parse_length(value, False, True, 1, 1000, - self.__frac_length_tag_cb, tag, 'right-margin') + self.__frac_length_tag_cb, tag, 'right-margin') - def _parse_style_font_weight(self, tag, value): + @staticmethod + def _parse_style_font_weight(tag, value): # TODO: missing 'bolder' and 'lighter' try: weight = { - '100': Pango.Weight.ULTRALIGHT, - '200': Pango.Weight.ULTRALIGHT, - '300': Pango.Weight.LIGHT, - '400': Pango.Weight.NORMAL, - '500': Pango.Weight.NORMAL, - '600': Pango.Weight.BOLD, - '700': Pango.Weight.BOLD, - '800': Pango.Weight.ULTRABOLD, - '900': Pango.Weight.HEAVY, - 'normal': Pango.Weight.NORMAL, - 'bold': Pango.Weight.BOLD, - }[value] + '100': Pango.Weight.ULTRALIGHT, + '200': Pango.Weight.ULTRALIGHT, + '300': Pango.Weight.LIGHT, + '400': Pango.Weight.NORMAL, + '500': Pango.Weight.NORMAL, + '600': Pango.Weight.BOLD, + '700': Pango.Weight.BOLD, + '800': Pango.Weight.ULTRABOLD, + '900': Pango.Weight.HEAVY, + 'normal': Pango.Weight.NORMAL, + 'bold': Pango.Weight.BOLD, + }[value] except KeyError: log.warning('unknown font-style %s', value) else: tag.set_property('weight', weight) - def _parse_style_font_family(self, tag, value): + @staticmethod + def _parse_style_font_family(tag, value): tag.set_property('family', value) - def _parse_style_text_align(self, tag, value): + @staticmethod + def _parse_style_text_align(tag, value): try: align = { - 'left': Gtk.Justification.LEFT, - 'right': Gtk.Justification.RIGHT, - 'center': Gtk.Justification.CENTER, - 'justify': Gtk.Justification.FILL, - }[value] + 'left': Gtk.Justification.LEFT, + 'right': Gtk.Justification.RIGHT, + 'center': Gtk.Justification.CENTER, + 'justify': Gtk.Justification.FILL, + }[value] except KeyError: log.warning('Invalid text-align: %s requested', value) else: tag.set_property('justification', align) - def _parse_style_text_decoration(self, tag, value): + @staticmethod + def _parse_style_text_decoration(tag, value): values = value.split(' ') if 'none' in values: tag.set_property('underline', Pango.Underline.NONE) @@ -438,7 +458,8 @@ class HtmlHandler(xml.sax.handler.ContentHandler): if 'overline' in values: log.warning('text-decoration:overline not implemented') - def _parse_style_white_space(self, tag, value): + @staticmethod + def _parse_style_white_space(tag, value): if value == 'pre': tag.set_property('wrap_mode', Gtk.WrapMode.NONE) elif value == 'normal': @@ -446,7 +467,8 @@ class HtmlHandler(xml.sax.handler.ContentHandler): elif value == 'nowrap': tag.set_property('wrap_mode', Gtk.WrapMode.NONE) - def __length_tag_cb(self, value, tag, propname): + @staticmethod + def __length_tag_cb(value, tag, propname): try: tag.set_property(propname, value) except Exception: @@ -455,29 +477,13 @@ class HtmlHandler(xml.sax.handler.ContentHandler): 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") + 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', - 'width', 'height'): - try: - method = locals()['_parse_style_%s' % style.replace('-', '_')] - except KeyError: - log.warning('Style attribute "%s" not yet implemented', style) - else: - __style_methods[style] = method - del style # pylint: disable=undefined-loop-variable - # -- + self._parse_length(value, False, False, 1, 1000, + self.__length_tag_cb, tag, "height") def _get_style_tags(self): return [tag for tag in self.styles if tag is not None] @@ -523,8 +529,10 @@ class HtmlHandler(xml.sax.handler.ContentHandler): else: if self.conv_textview: img_mark = self.textbuf.create_mark(None, self.iter, True) - app.thread_interface(helpers.download_image, [ - self.conv_textview.account, attrs], self._update_img, + app.thread_interface( + helpers.download_image, + [self.conv_textview.account, attrs], + self._update_img, [attrs, img_mark, self._get_style_tags()]) alt = attrs.get('alt', '') if alt: @@ -542,19 +550,20 @@ class HtmlHandler(xml.sax.handler.ContentHandler): def width_cb(length): dims[0] = length # process width and height attributes - w = attrs.get('width') - h = attrs.get('height') + width = attrs.get('width') + height = attrs.get('height') # override with width and height styles for attr, val in style_iter(attrs.get('style', '')): if attr == 'width': - w = val + width = 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): + height = val + if width: + self._parse_length(width, False, False, 1, 1000, width_cb) + if height: + self._parse_length(height, 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, @@ -569,7 +578,8 @@ class HtmlHandler(xml.sax.handler.ContentHandler): if not dims[1]: dims[1] = h loader.set_size(*dims) - if w or h: + + if width or height: loader.connect('size-prepared', set_size, dims) loader.write(mem) loader.close() @@ -621,12 +631,10 @@ class HtmlHandler(xml.sax.handler.ContentHandler): attr = attr.lower() val = val try: - method = self.__style_methods[attr] + getattr(self, self.__style_methods[attr])(tag, val) except KeyError: log.warning('Style attribute "%s" requested ' 'but not yet implemented', attr) - else: - method(self, tag, val) self.styles.append(tag) def _end_span(self): @@ -660,7 +668,7 @@ class HtmlHandler(xml.sax.handler.ContentHandler): else: self._insert_text(text.strip('\n')) - def _anchor_event(self, tag, textview, event, iter_, href, type_): + def _anchor_event(self, _tag, _textview, event, _iter, href, type_): if event.type == Gdk.EventType.BUTTON_PRESS: self.textview.emit('url-clicked', href, type_) return True @@ -668,8 +676,8 @@ class HtmlHandler(xml.sax.handler.ContentHandler): def handle_specials(self, text): if self.conv_textview: - self.iter = self.conv_textview.detect_and_print_special_text(text, - self._get_style_tags(), iter_=self.iter) + self.iter = self.conv_textview.detect_and_print_special_text( + text, self._get_style_tags(), iter_=self.iter) else: self._insert_text(text) @@ -682,7 +690,6 @@ class HtmlHandler(xml.sax.handler.ContentHandler): self.text += content self.starting = False - def startElement(self, name, attrs): self._flush_text() klass = [i for i in attrs.get('class', ' ').split(' ') if i] @@ -767,10 +774,10 @@ class HtmlHandler(xml.sax.handler.ContentHandler): log.warning('Unhandled element "%s"', name) def endElement(self, name): - endPreserving = False - newLine = False + end_preserving = False + newline = False if name == 'br': - newLine = True + newline = True elif name == 'hr': #FIXME: plenty of unused attributes (width, height,...) :) self._jump_line() @@ -779,7 +786,7 @@ class HtmlHandler(xml.sax.handler.ContentHandler): elif name in LIST_ELEMS: self.list_counters.pop() elif name == 'li': - newLine = True + newline = True elif name == 'img': pass elif name in ('body', 'html'): @@ -792,21 +799,20 @@ class HtmlHandler(xml.sax.handler.ContentHandler): pass elif name in BLOCK: if name == 'pre': - endPreserving = True + end_preserving = True elif name in BLOCK_STRUCT: - newLine = True + newline = True else: log.warning("Unhandled element '%s'", name) self._flush_text() - if endPreserving: + if end_preserving: self.preserve = False - if newLine: + if newline: self._jump_line() self._end_span() class HtmlTextView(Gtk.TextView): - def __init__(self, account=None): Gtk.TextView.__init__(self) self.set_wrap_mode(Gtk.WrapMode.CHAR) @@ -847,7 +853,7 @@ class HtmlTextView(Gtk.TextView): self.tagSthAtSth.set_property('underline', Pango.Underline.SINGLE) self.tagSthAtSth.connect('event', self.hyperlink_handler, 'sth_at_sth') - def __query_tooltip(self, widget, x_pos, y_pos, keyboard_mode, tooltip): + def __query_tooltip(self, widget, x_pos, y_pos, _keyboard_mode, tooltip): window = widget.get_window(Gtk.TextWindowType.TEXT) x_pos, y_pos = self.window_to_buffer_coords( Gtk.TextWindowType.TEXT, x_pos, y_pos) @@ -876,7 +882,7 @@ class HtmlTextView(Gtk.TextView): if menu is None: return - def destroy(menu, pspec): + def destroy(menu, _pspec): visible = menu.get_property('visible') if not visible: GLib.idle_add(menu.destroy) @@ -942,8 +948,8 @@ class HtmlTextView(Gtk.TextView): 'mlat=%(lat)s&mlon=%(lon)s&zoom=16' % \ {'lat': lat, 'lon': lon} helpers.launch_browser_mailer(kind, uri) - # other URIs else: + # other URIs helpers.launch_browser_mailer(kind, word) def display_html(self, html, textview, conv_textview, iter_=None): @@ -952,17 +958,10 @@ class HtmlTextView(Gtk.TextView): eob = iter_ else: eob = buffer_.get_end_iter() - ## this works too if libxml2 is not available - # parser = xml.sax.make_parser(['drv_libxml2']) - # parser.setFeature(xml.sax.handler.feature_validation, True) parser = xml.sax.make_parser() parser.setContentHandler(HtmlHandler(textview, conv_textview, eob)) parser.parse(StringIO(html)) - # too much space after :) - #if not eob.starts_line(): - # buffer_.insert(eob, '\n') - @staticmethod def _on_copy_clipboard(textview): clipboard = textview.get_clipboard(Gdk.SELECTION_CLIPBOARD)