From 7ef94b446d70d096dae80f0a97be890c22580f1d Mon Sep 17 00:00:00 2001 From: mailchuck Date: Tue, 15 Dec 2015 03:51:06 +0100 Subject: [PATCH] Lazy rendering of message contents Message will render as user is scrolling down. This prevents interface freezes on long messages (such as inline img in text mode). Fixes Bitmessage##366 Also a minor fix in text mode rendering. --- src/bitmessageqt/messageview.py | 42 ++++++++++++++++++++++++++---- src/bitmessageqt/safehtmlparser.py | 12 +++++---- 2 files changed, 44 insertions(+), 10 deletions(-) diff --git a/src/bitmessageqt/messageview.py b/src/bitmessageqt/messageview.py index 049a2706..8d4b49c4 100644 --- a/src/bitmessageqt/messageview.py +++ b/src/bitmessageqt/messageview.py @@ -17,6 +17,11 @@ class MessageView(QtGui.QTextBrowser): self.setOpenExternalLinks(False) self.setOpenLinks(False) self.anchorClicked.connect(self.confirmURL) + self.out = "" + self.outpos = 0 + self.document().setUndoRedoEnabled(False) + self.rendering = False + self.verticalScrollBar().valueChanged.connect(self.lazyRender) def mousePressEvent(self, event): #text = textCursor.block().text() @@ -36,22 +41,49 @@ class MessageView(QtGui.QTextBrowser): if reply == QtGui.QMessageBox.Yes: QtGui.QDesktopServices.openUrl(link) + def lazyRender(self): + if self.rendering: + return + self.rendering = True + position = self.verticalScrollBar().value() + cursor = QtGui.QTextCursor(self.document()) + while self.outpos < len(self.out) and self.verticalScrollBar().value() >= self.document().size().height() - 2 * self.size().height(): + startpos = self.outpos + self.outpos += 10240 + # find next end of tag + if self.mode == MessageView.MODE_HTML: + pos = self.out.find(">", self.outpos) + if pos > self.outpos: + self.outpos = pos + cursor.movePosition(QtGui.QTextCursor.End, QtGui.QTextCursor.MoveAnchor) + cursor.insertHtml(QtCore.QString(self.out[startpos:self.outpos])) + self.verticalScrollBar().setValue(position) + self.rendering = False + def showPlain(self): self.mode = MessageView.MODE_PLAIN out = self.html.raw if self.html.has_html: - out = "
" + QtGui.QApplication.translate(type(self).__name__, MessageView.TEXT_PLAIN) + "

" + out - self.setHtml(QtCore.QString(out)) + out = "
" + str(QtGui.QApplication.translate(type(self).__name__, MessageView.TEXT_PLAIN)) + "

" + out + self.out = out + self.outpos = 0 + self.setHtml("") + self.lazyRender() def showHTML(self): self.mode = MessageView.MODE_HTML out = self.html.sanitised - out = "
" + QtGui.QApplication.translate(type(self).__name__, MessageView.TEXT_HTML) + "

" + out - self.setHtml(QtCore.QString(out)) + out = "
" + str(QtGui.QApplication.translate(type(self).__name__, MessageView.TEXT_HTML)) + "

" + out + self.out = out + self.outpos = 0 + self.setHtml("") + self.lazyRender() def setContent(self, data): self.html = SafeHTMLParser() self.html.allow_picture = True + self.html.reset() + self.html.reset_safe() self.html.feed(data) self.html.close() - self.showPlain() + self.showPlain() \ No newline at end of file diff --git a/src/bitmessageqt/safehtmlparser.py b/src/bitmessageqt/safehtmlparser.py index c058dd6f..cc8362b3 100644 --- a/src/bitmessageqt/safehtmlparser.py +++ b/src/bitmessageqt/safehtmlparser.py @@ -25,8 +25,10 @@ class SafeHTMLParser(HTMLParser): self.has_html = False def reset_safe(self): + self.elements = set() self.raw = u"" self.sanitised = u"" + self.has_html = False def add_if_acceptable(self, tag, attrs = None): if not tag in self.acceptable_elements: @@ -35,12 +37,12 @@ class SafeHTMLParser(HTMLParser): if inspect.stack()[1][3] == "handle_endtag": self.sanitised += "/" self.sanitised += tag - if attrs is not None: + if not attrs is None: for attr in attrs: if tag == "img" and attr[0] == "src" and not self.allow_picture: attr[1] = "" self.sanitised += " " + quote_plus(attr[0]) - if attr[1] is not None: + if not (attr[1] is None): self.sanitised += "=\"" + attr[1] + "\"" if inspect.stack()[1][3] == "handle_startendtag": self.sanitised += "/" @@ -51,13 +53,13 @@ class SafeHTMLParser(HTMLParser): if inspect.stack()[1][3] == "handle_endtag": self.raw += "/" self.raw += tag - if attrs is not None: + if not attrs is None: for attr in attrs: if tag == "img" and attr[0] == "src" and not self.allow_picture: attr[1] = "" self.raw += " " + attr[0] - if attr[1] is not None: - self.raw + "="" + attr[1] + """ + if not (attr[1] is None): + self.raw += "="" + attr[1] + """ if inspect.stack()[1][3] == "handle_startendtag": self.raw += "/" self.raw += ">"