From 3188e6ab28e13963b7fdebecf7a79ffb064a1425 Mon Sep 17 00:00:00 2001 From: GRiker Date: Sun, 2 Jun 2013 11:44:50 -0600 Subject: [PATCH 001/105] Filter device list for repeating entries (occurs under Windows occasionally). --- src/calibre/devices/idevice/libimobiledevice.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/calibre/devices/idevice/libimobiledevice.py b/src/calibre/devices/idevice/libimobiledevice.py index 08c9e24fd4..f247191ca0 100644 --- a/src/calibre/devices/idevice/libimobiledevice.py +++ b/src/calibre/devices/idevice/libimobiledevice.py @@ -1293,7 +1293,9 @@ class libiMobileDevice(): else: index = 0 while devices[index]: - device_list.append(devices[index].contents.value) + # Filter out redundant entries + if devices[index].contents.value not in device_list: + device_list.append(devices[index].contents.value) index += 1 if self.verbose: self.log(" %s" % repr(device_list)) From b598ce3c175a30b9cdbb7703cedde8634a11ed95 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Mon, 3 Jun 2013 10:52:40 +0530 Subject: [PATCH 002/105] Update Metro News NL Fixes #1186861 [Update of Metronews-NL](https://bugs.launchpad.net/calibre/+bug/1186861) --- recipes/metro_news_nl.recipe | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/recipes/metro_news_nl.recipe b/recipes/metro_news_nl.recipe index 0995719939..07b08bd5e5 100644 --- a/recipes/metro_news_nl.recipe +++ b/recipes/metro_news_nl.recipe @@ -39,6 +39,8 @@ from BeautifulSoup import BeautifulSoup Version 1.9.4 19-04-2013 Added regex filter for mailto Updated for new layout of metro-site + Version 1.9.5 28-05-2013 + Added some extra id's and classes to remove ''' class AdvancedUserRecipe1306097511(BasicNewsRecipe): @@ -46,7 +48,7 @@ class AdvancedUserRecipe1306097511(BasicNewsRecipe): oldest_article = 1.2 max_articles_per_feed = 25 __author__ = u'DrMerry' - description = u'Metro Nederland v1.9.4 2013-04-19' + description = u'Metro Nederland v1.9.5 2013-05-28, Download nieuws van de Nederlandse editie van de krant Metro' language = u'nl' simultaneous_downloads = 5 masthead_url = 'http://blog.metronieuws.nl/wp-content/themes/metro/images/header.gif' @@ -70,7 +72,7 @@ class AdvancedUserRecipe1306097511(BasicNewsRecipe): #(re.compile(r'<(a |/a)[^>]*>', re.DOTALL|re.IGNORECASE),lambda match:'') #(re.compile('( Date: Mon, 3 Jun 2013 11:03:41 +0530 Subject: [PATCH 003/105] DOCX: Floating and justified tables --- src/calibre/ebooks/docx/tables.py | 87 +++++++++++++++++++++++------- src/calibre/ebooks/docx/to_html.py | 9 ++-- 2 files changed, 75 insertions(+), 21 deletions(-) diff --git a/src/calibre/ebooks/docx/tables.py b/src/calibre/ebooks/docx/tables.py index 6732533b84..987c6bc53e 100644 --- a/src/calibre/ebooks/docx/tables.py +++ b/src/calibre/ebooks/docx/tables.py @@ -8,11 +8,13 @@ __copyright__ = '2013, Kovid Goyal ' from lxml.html.builder import TABLE, TR, TD -from calibre.ebooks.docx.block_styles import inherit, read_shd, read_border, binary_property, border_props, ParagraphStyle # noqa +from calibre.ebooks.docx.block_styles import inherit, read_shd as rs, read_border, binary_property, border_props, ParagraphStyle from calibre.ebooks.docx.char_styles import RunStyle from calibre.ebooks.docx.names import XPath, get, is_tag # Read from XML {{{ +read_shd = rs + def _read_width(elem): ans = inherit try: @@ -73,6 +75,12 @@ def read_spacing(parent, dest): ans = _read_width(cs) setattr(dest, 'spacing', ans) +def read_float(parent, dest): + ans = inherit + for x in XPath('./w:tblpPr')(parent): + ans = x.attrib + setattr(dest, 'float', ans) + def read_indent(parent, dest): ans = inherit for cs in XPath('./w:tblInd')(parent): @@ -139,7 +147,10 @@ def read_look(parent, dest): # }}} def clone(style): - ans = type(style)() + try: + ans = type(style)() + except TypeError: + return None ans.update(style) return ans @@ -147,12 +158,16 @@ class RowStyle(object): all_properties = ('height', 'cantSplit', 'hidden', 'spacing',) - def __init__(self, tcPr=None): - if tcPr is None: + def __init__(self, trPr=None): + if trPr is None: for p in self.all_properties: setattr(self, p, inherit) else: - pass + for p in ('hidden', 'cantSplit'): + setattr(self, p, binary_property(trPr, p)) + for p in ('spacing', 'height'): + f = globals()['read_%s' % p] + f(trPr, self) class CellStyle(object): @@ -160,19 +175,19 @@ class CellStyle(object): 'cell_padding_bottom', 'width', 'vertical_align', 'col_span', 'vMerge', 'hMerge', ) + tuple(k % edge for edge in border_edges for k in border_props) - def __init__(self, trPr=None): - if trPr is None: + def __init__(self, tcPr=None): + if tcPr is None: for p in self.all_properties: setattr(self, p, inherit) else: for x in ('borders', 'shd', 'padding', 'cell_width', 'vertical_align', 'col_span', 'merge'): f = globals()['read_%s' % x] - f(trPr, self) + f(tcPr, self) class TableStyle(object): all_properties = ( - 'width', 'cell_padding_left', 'cell_padding_right', 'cell_padding_top', + 'width', 'float', 'cell_padding_left', 'cell_padding_right', 'cell_padding_top', 'cell_padding_bottom', 'margin_left', 'margin_right', 'background_color', 'spacing', 'indent', 'overrides', 'col_band_size', 'row_band_size', 'look', ) + tuple(k % edge for edge in border_edges for k in border_props) @@ -183,7 +198,7 @@ class TableStyle(object): setattr(self, p, inherit) else: self.overrides = inherit - for x in ('width', 'padding', 'shd', 'justification', 'spacing', 'indent', 'borders', 'band_size', 'look'): + for x in ('width', 'float', 'padding', 'shd', 'justification', 'spacing', 'indent', 'borders', 'band_size', 'look'): f = globals()['read_%s' % x] f(tblPr, self) parent = tblPr.getparent() @@ -202,6 +217,7 @@ class TableStyle(object): orides['para'] = ParagraphStyle(pPr) for rPr in XPath('./w:rPr')(tblStylePr): orides['run'] = RunStyle(rPr) + self._css = None def update(self, other): for prop in self.all_properties: @@ -215,6 +231,37 @@ class TableStyle(object): if val is inherit: setattr(self, p, getattr(parent, p)) + @property + def css(self): + if self._css is None: + c = self._css = {} + for x in ('width', 'background_color', 'margin_left', 'margin_right'): + val = getattr(self, x) + if val is not inherit: + c[x.replace('_', '-')] = val + if self.indent not in (inherit, 'auto') and self.margin_left != 'auto': + c['margin-left'] = self.indent + if self.float is not inherit: + for x in ('left', 'top', 'right', 'bottom'): + val = self.float.get('%sFromText' % x, 0) + try: + val = '%.3gpt' % (int(val) / 20) + except (ValueError, TypeError): + val = '0' + c['margin-%s' % x] = val + if 'tblpXSpec' in self.float: + c['float'] = 'right' if self.float['tblpXSpec'] in {'right', 'outside'} else 'left' + else: + page = self.page + page_width = page.width - page.margin_left - page.margin_right + try: + x = int(self.float['tblpX']) / 20 + except (KeyError, ValueError, TypeError): + x = 0 + c['float'] = 'left' if (x/page_width) < 0.65 else 'right' + return self._css + + class Table(object): def __init__(self, tbl, styles, para_map): @@ -243,6 +290,9 @@ class Table(object): style['table'].update(TableStyle(tblPr)) self.table_style, self.paragraph_style = style['table'], style.get('paragraph', None) self.run_style = style.get('run', None) + self.overrides = self.table_style.overrides + if 'wholeTable' in self.overrides and 'table' in self.overrides['wholeTable']: + self.table_style.update(self.overrides['wholeTable']['table']) self.style_map = {} self.paragraphs = [] @@ -304,12 +354,11 @@ class Table(object): return tuple(filter(self.override_allowed, overrides)) def resolve_para_style(self, p, overrides): - text_styles = [None if self.paragraph_style is None else clone(self.paragraph_style), - None if self.run_style is None else clone(self.run_style)] + text_styles = [clone(self.paragraph_style), clone(self.run_style)] for o in overrides: - if o in self.table_style.overrides: - ovr = self.table_style.overrides[o] + if o in self.overrides: + ovr = self.overrides[o] for i, name in enumerate(('para', 'run')): ops = ovr.get(name, None) if ops is not None: @@ -326,8 +375,10 @@ class Table(object): for p in t: yield p - def apply_markup(self, rmap, parent=None): + def apply_markup(self, rmap, page, parent=None): table = TABLE('\n\t\t') + self.table_style.page = page + table.set('class', self.styles.register(self.table_style.css, 'table')) if parent is None: try: first_para = rmap[next(iter(self))] @@ -350,7 +401,7 @@ class Table(object): if x.tag.endswith('}p'): td.append(rmap[x]) else: - self.sub_tables[x].apply_markup(rmap, parent=td) + self.sub_tables[x].apply_markup(rmap, page, parent=td) if len(tr): tr[-1].tail = '\n\t\t' if len(table): @@ -366,10 +417,10 @@ class Tables(object): def register(self, tbl, styles): self.tables.append(Table(tbl, styles, self.para_map)) - def apply_markup(self, object_map): + def apply_markup(self, object_map, page_map): rmap = {v:k for k, v in object_map.iteritems()} for table in self.tables: - table.apply_markup(rmap) + table.apply_markup(rmap, page_map[table.tbl]) def para_style(self, p): table = self.para_map.get(p, None) diff --git a/src/calibre/ebooks/docx/to_html.py b/src/calibre/ebooks/docx/to_html.py index 2f945e8980..5a2a530d4f 100644 --- a/src/calibre/ebooks/docx/to_html.py +++ b/src/calibre/ebooks/docx/to_html.py @@ -85,8 +85,9 @@ class Convert(object): self.read_page_properties(doc) for wp, page_properties in self.page_map.iteritems(): self.current_page = page_properties - p = self.convert_p(wp) - self.body.append(p) + if wp.tag.endswith('}p'): + p = self.convert_p(wp) + self.body.append(p) notes_header = None if self.footnotes.has_notes: @@ -103,6 +104,7 @@ class Convert(object): for wp in note: if wp.tag.endswith('}tbl'): self.tables.register(wp, self.styles) + self.page_map[wp] = self.current_page p = self.convert_p(wp) dl[-1].append(p) @@ -110,7 +112,7 @@ class Convert(object): self.styles.cascade(self.layers) - self.tables.apply_markup(self.object_map) + self.tables.apply_markup(self.object_map, self.page_map) numbered = [] for html_obj, obj in self.object_map.iteritems(): @@ -162,6 +164,7 @@ class Convert(object): for p in descendants(doc, 'w:p', 'w:tbl'): if p.tag.endswith('}tbl'): self.tables.register(p, self.styles) + current.append(p) continue sect = tuple(descendants(p, 'w:sectPr')) if sect: From 279594b1a35f8324013238aa312f61d0fd204376 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Mon, 3 Jun 2013 13:08:11 +0530 Subject: [PATCH 004/105] DOCX Tables: Row styling --- src/calibre/ebooks/docx/tables.py | 92 ++++++++++++++++++++++--------- 1 file changed, 67 insertions(+), 25 deletions(-) diff --git a/src/calibre/ebooks/docx/tables.py b/src/calibre/ebooks/docx/tables.py index 987c6bc53e..89eb598b45 100644 --- a/src/calibre/ebooks/docx/tables.py +++ b/src/calibre/ebooks/docx/tables.py @@ -154,7 +154,15 @@ def clone(style): ans.update(style) return ans -class RowStyle(object): +class Style(object): + + def update(self, other): + for prop in self.all_properties: + nval = getattr(other, prop) + if nval is not inherit: + setattr(self, prop, nval) + +class RowStyle(Style): all_properties = ('height', 'cantSplit', 'hidden', 'spacing',) @@ -168,8 +176,26 @@ class RowStyle(object): for p in ('spacing', 'height'): f = globals()['read_%s' % p] f(trPr, self) + self._css = None -class CellStyle(object): + @property + def css(self): + if self._css is None: + c = self._css = {} + if self.hidden is True: + c['display'] = 'none' + if self.cantSplit is True: + c['page-break-inside'] = 'avoid' + if self.height is not inherit: + rule, val = self.height + if rule != 'auto': + try: + c['min-height' if rule == 'atLeast' else 'height'] = '%.3gpt' % (int(val)/20) + except (ValueError, TypeError): + pass + return self._css + +class CellStyle(Style): all_properties = ('background_color', 'cell_padding_left', 'cell_padding_right', 'cell_padding_top', 'cell_padding_bottom', 'width', 'vertical_align', 'col_span', 'vMerge', 'hMerge', @@ -184,7 +210,7 @@ class CellStyle(object): f = globals()['read_%s' % x] f(tcPr, self) -class TableStyle(object): +class TableStyle(Style): all_properties = ( 'width', 'float', 'cell_padding_left', 'cell_padding_right', 'cell_padding_top', @@ -219,12 +245,6 @@ class TableStyle(object): orides['run'] = RunStyle(rPr) self._css = None - def update(self, other): - for prop in self.all_properties: - nval = getattr(other, prop) - if nval is not inherit: - setattr(self, prop, nval) - def resolve_based_on(self, parent): for p in self.all_properties: val = getattr(self, p) @@ -299,6 +319,8 @@ class Table(object): rows = XPath('./w:tr')(tbl) for r, tr in enumerate(rows): + overrides = self.get_overrides(r, None, len(rows), None) + self.resolve_row_style(tr, overrides) cells = XPath('./w:tc')(tr) for c, tc in enumerate(cells): overrides = self.get_overrides(r, c, len(rows), len(cells)) @@ -329,30 +351,45 @@ class Table(object): overrides = ['wholeTable'] def divisor(m, n): return (m - (m % n)) // n - odd_column_band = (divisor(c, self.table_style.col_band_size) % 2) == 0 - overrides.append('band%dVert' % (1 if odd_column_band else 2)) + if c is not None: + odd_column_band = (divisor(c, self.table_style.col_band_size) % 2) == 0 + overrides.append('band%dVert' % (1 if odd_column_band else 2)) odd_row_band = (divisor(r, self.table_style.row_band_size) % 2) == 0 overrides.append('band%dHorz' % (1 if odd_row_band else 2)) if r == 0: overrides.append('firstRow') if r >= num_of_rows - 1: overrides.append('lastRow') - if c == 0: - overrides.append('firstCol') - if c >= num_of_cols_in_row - 1: - overrides.append('lastCol') - if r == 0: + if c is not None: if c == 0: - overrides.append('nwCell') - if c == num_of_cols_in_row - 1: - overrides.append('neCell') - if r == num_of_rows - 1: - if c == 0: - overrides.append('swCell') - if c == num_of_cols_in_row - 1: - overrides.append('seCell') + overrides.append('firstCol') + if c >= num_of_cols_in_row - 1: + overrides.append('lastCol') + if r == 0: + if c == 0: + overrides.append('nwCell') + if c == num_of_cols_in_row - 1: + overrides.append('neCell') + if r == num_of_rows - 1: + if c == 0: + overrides.append('swCell') + if c == num_of_cols_in_row - 1: + overrides.append('seCell') return tuple(filter(self.override_allowed, overrides)) + def resolve_row_style(self, tr, overrides): + rs = RowStyle() + for o in overrides: + if o in self.overrides: + ovr = self.overrides[o] + ors = ovr.get('row', None) + if ors is not None: + rs.update(ors) + + for trPr in XPath('./w:trPr')(tr): + rs.update(RowStyle(trPr)) + self.style_map[tr] = rs + def resolve_para_style(self, p, overrides): text_styles = [clone(self.paragraph_style), clone(self.run_style)] @@ -378,7 +415,9 @@ class Table(object): def apply_markup(self, rmap, page, parent=None): table = TABLE('\n\t\t') self.table_style.page = page - table.set('class', self.styles.register(self.table_style.css, 'table')) + table_style = self.table_style.css + if table_style: + table.set('class', self.styles.register(table_style, 'table')) if parent is None: try: first_para = rmap[next(iter(self))] @@ -391,6 +430,9 @@ class Table(object): parent.append(table) for row in XPath('./w:tr')(self.tbl): tr = TR('\n\t\t\t') + row_style = self.style_map[row].css + if row_style: + tr.set('class', self.styles.register(row_style, 'row')) tr.tail = '\n\t\t' table.append(tr) for tc in XPath('./w:tc')(row): From 230cbf46b00f08d438d047386fd183d43b59d873 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Mon, 3 Jun 2013 14:04:33 +0530 Subject: [PATCH 005/105] HTML Input: Avoid spurious log warnings HTML Input: Avoid spurious log warnings about unspecified language/creator when these are actually specified on the command line. Fixes #1186899 [Apparently-spurious "Language not specified" errors from caliber-convert](https://bugs.launchpad.net/calibre/+bug/1186899) --- .../ebooks/conversion/plugins/html_input.py | 28 ++++++++++++++----- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/src/calibre/ebooks/conversion/plugins/html_input.py b/src/calibre/ebooks/conversion/plugins/html_input.py index 676a82cd3e..de783cfabe 100644 --- a/src/calibre/ebooks/conversion/plugins/html_input.py +++ b/src/calibre/ebooks/conversion/plugins/html_input.py @@ -87,7 +87,7 @@ class HTMLInput(InputFormatPlugin): return self._is_case_sensitive if not path or not os.path.exists(path): return islinux or isbsd - self._is_case_sensitive = not (os.path.exists(path.lower()) \ + self._is_case_sensitive = not (os.path.exists(path.lower()) and os.path.exists(path.upper())) return self._is_case_sensitive @@ -101,6 +101,8 @@ class HTMLInput(InputFormatPlugin): from calibre.ebooks.oeb.transforms.metadata import \ meta_info_to_oeb_metadata from calibre.ebooks.html.input import get_filelist + from calibre.ebooks.metadata import string_to_authors + from calibre.utils.localization import canonicalize_lang import cssutils, logging cssutils.log.setLevel(logging.WARN) self.OEB_STYLES = OEB_STYLES @@ -111,11 +113,20 @@ class HTMLInput(InputFormatPlugin): metadata = oeb.metadata meta_info_to_oeb_metadata(mi, metadata, log) if not metadata.language: - oeb.logger.warn(u'Language not specified') - metadata.add('language', get_lang().replace('_', '-')) + l = canonicalize_lang(getattr(opts, 'language', None)) + if not l: + oeb.logger.warn(u'Language not specified') + l = get_lang().replace('_', '-') + metadata.add('language', l) if not metadata.creator: - oeb.logger.warn('Creator not specified') - metadata.add('creator', self.oeb.translate(__('Unknown'))) + a = getattr(opts, 'authors', None) + if a: + a = string_to_authors(a) + if not a: + oeb.logger.warn('Creator not specified') + a = [self.oeb.translate(__('Unknown'))] + for aut in a: + metadata.add('creator', aut) if not metadata.title: oeb.logger.warn('Title not specified') metadata.add('title', self.oeb.translate(__('Unknown'))) @@ -175,7 +186,8 @@ class HTMLInput(InputFormatPlugin): titles = [] headers = [] for item in self.oeb.spine: - if not item.linear: continue + if not item.linear: + continue html = item.data title = ''.join(xpath(html, '/h:html/h:head/h:title/text()')) title = re.sub(r'\s+', ' ', title.strip()) @@ -193,7 +205,8 @@ class HTMLInput(InputFormatPlugin): if len(titles) > len(set(titles)): use = headers for title, item in izip(use, self.oeb.spine): - if not item.linear: continue + if not item.linear: + continue toc.add(title, item.href) oeb.container = DirContainer(os.getcwdu(), oeb.log, ignore_opf=True) @@ -291,3 +304,4 @@ class HTMLInput(InputFormatPlugin): self.log.exception('Failed to read CSS file: %r'%link) return (None, None) return (None, raw) + From 5c9dea7064ab035f0a769907603bafab715e9db7 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Mon, 3 Jun 2013 15:22:20 +0530 Subject: [PATCH 006/105] E-book viewer: Keyboard shortcuts for Back/Forward Fixes #1186928 [Missing keyboard shortcut in the viewer](https://bugs.launchpad.net/calibre/+bug/1186928) --- src/calibre/gui2/viewer/documentview.py | 6 ++++++ src/calibre/gui2/viewer/keys.py | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/src/calibre/gui2/viewer/documentview.py b/src/calibre/gui2/viewer/documentview.py index 1878b5e760..41cd6433ca 100644 --- a/src/calibre/gui2/viewer/documentview.py +++ b/src/calibre/gui2/viewer/documentview.py @@ -1218,6 +1218,12 @@ class DocumentView(QWebView): # {{{ self.paged_col_scroll() else: self.scroll_by(x=15) + elif key == 'Back': + if self.manager is not None: + self.manager.back(None) + elif key == 'Forward': + if self.manager is not None: + self.manager.forward(None) else: handled = False return handled diff --git a/src/calibre/gui2/viewer/keys.py b/src/calibre/gui2/viewer/keys.py index 7d5884f624..b3489facb4 100644 --- a/src/calibre/gui2/viewer/keys.py +++ b/src/calibre/gui2/viewer/keys.py @@ -44,4 +44,10 @@ SHORTCUTS = { 'Right' : (['L', 'Right'], _('Scroll right')), + 'Back': (['Alt+Left'], + _('Back')), + + 'Forward': (['Alt+Right'], + _('Forward')), + } From aab5d9707a2b086140da92e7ca5f8ab90a7d5dab Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Mon, 3 Jun 2013 15:23:53 +0530 Subject: [PATCH 007/105] pep8 --- src/calibre/gui2/viewer/documentview.py | 52 +++++++++++++------------ 1 file changed, 28 insertions(+), 24 deletions(-) diff --git a/src/calibre/gui2/viewer/documentview.py b/src/calibre/gui2/viewer/documentview.py index 41cd6433ca..17ad36f908 100644 --- a/src/calibre/gui2/viewer/documentview.py +++ b/src/calibre/gui2/viewer/documentview.py @@ -29,7 +29,7 @@ from calibre.ebooks.oeb.display.webview import load_html from calibre.constants import isxp, iswindows # }}} -class Document(QWebPage): # {{{ +class Document(QWebPage): # {{{ page_turn = pyqtSignal(object) mark_element = pyqtSignal(QWebElement) @@ -356,7 +356,8 @@ class Document(QWebPage): # {{{ self.mainFrame().setScrollPosition(QPoint(x, y)) def jump_to_anchor(self, anchor): - if not self.loaded_javascript: return + if not self.loaded_javascript: + return self.javascript('window.paged_display.jump_to_anchor("%s")'%anchor) def element_ypos(self, elem): @@ -447,7 +448,7 @@ class Document(QWebPage): # {{{ @property def width(self): - return self.mainFrame().contentsSize().width() # offsetWidth gives inaccurate results + return self.mainFrame().contentsSize().width() # offsetWidth gives inaccurate results def set_bottom_padding(self, amount): s = QSize(-1, -1) if amount == 0 else QSize(self.viewportSize().width(), @@ -460,7 +461,7 @@ class Document(QWebPage): # {{{ # }}} -class DocumentView(QWebView): # {{{ +class DocumentView(QWebView): # {{{ magnification_changed = pyqtSignal(object) DISABLED_BRUSH = QBrush(Qt.lightGray, Qt.Dense5Pattern) @@ -766,8 +767,10 @@ class DocumentView(QWebView): # {{{ @dynamic_property def current_language(self): - def fget(self): return self.document.current_language - def fset(self, val): self.document.current_language = val + def fget(self): + return self.document.current_language + def fset(self, val): + self.document.current_language = val return property(fget=fget, fset=fset) def search(self, text, backwards=False): @@ -816,7 +819,6 @@ class DocumentView(QWebView): # {{{ self.scrollbar.blockSignals(False) self._ignore_scrollbar_signals = False - def load_finished(self, ok): if self.loading_url is None: # An