7ef94b446d
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.
89 lines
3.6 KiB
Python
89 lines
3.6 KiB
Python
from PyQt4 import QtCore, QtGui
|
|
|
|
from safehtmlparser import *
|
|
|
|
class MessageView(QtGui.QTextBrowser):
|
|
MODE_PLAIN = 0
|
|
MODE_HTML = 1
|
|
TEXT_PLAIN = "HTML detected, click here to display"
|
|
TEXT_HTML = "Click here to disable HTML"
|
|
CONFIRM_TITLE = "Follow external link"
|
|
CONFIRM_TEXT = "The link \"%1\" will open in a browser. It may be a security risk, it could de-anonymise you or download malicious data. Are you sure?"
|
|
|
|
def __init__(self, parent = 0):
|
|
super(MessageView, self).__init__(parent)
|
|
self.mode = MessageView.MODE_PLAIN
|
|
self.html = None
|
|
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()
|
|
if event.button() == QtCore.Qt.LeftButton and self.html.has_html and self.cursorForPosition(event.pos()).block().blockNumber() == 0:
|
|
if self.mode == MessageView.MODE_PLAIN:
|
|
self.showHTML()
|
|
else:
|
|
self.showPlain()
|
|
else:
|
|
super(MessageView, self).mousePressEvent(event)
|
|
|
|
def confirmURL(self, link):
|
|
reply = QtGui.QMessageBox.question(self,
|
|
QtGui.QApplication.translate(type(self).__name__, MessageView.CONFIRM_TITLE),
|
|
QtGui.QApplication.translate(type(self).__name__, MessageView.CONFIRM_TEXT).arg(str(link.toString())),
|
|
QtGui.QMessageBox.Yes, QtGui.QMessageBox.No)
|
|
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 = "<div align=\"center\" style=\"text-decoration: underline;\"><b>" + str(QtGui.QApplication.translate(type(self).__name__, MessageView.TEXT_PLAIN)) + "</b></div><br/>" + out
|
|
self.out = out
|
|
self.outpos = 0
|
|
self.setHtml("")
|
|
self.lazyRender()
|
|
|
|
def showHTML(self):
|
|
self.mode = MessageView.MODE_HTML
|
|
out = self.html.sanitised
|
|
out = "<div align=\"center\" style=\"text-decoration: underline;\"><b>" + str(QtGui.QApplication.translate(type(self).__name__, MessageView.TEXT_HTML)) + "</b></div><br/>" + 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() |