mirror of
https://github.com/olivierkes/manuskript.git
synced 2024-06-14 08:54:34 +12:00
Fixed #549 and refactored the image tooltip also
Issue #549 was caused because the request and reply object urls are not guaranteed to be the same. Redirects are the most common cause, but a malformed URL apparently also qualifies. We now make sure to look at the original request. Because the code confused me while I was working on it, I decided to refactor and document it in order to understand what was going on. I am glad I did: I found another crashing bug involving the rapid-firing of tooltip requests, and the processing dict never had its entries removed either, leading to a (very slow) memory leak over time. All is good in the world of image tooltips now.
This commit is contained in:
parent
2b4943c36b
commit
0238ccec7b
|
@ -527,7 +527,7 @@ class MDEditView(textEditView):
|
||||||
+"<p><img src='data:image/png;base64,{}'></p>")
|
+"<p><img src='data:image/png;base64,{}'></p>")
|
||||||
tooltip = None
|
tooltip = None
|
||||||
pos = event.pos() + QPoint(0, ct.rect.height())
|
pos = event.pos() + QPoint(0, ct.rect.height())
|
||||||
imageTooltiper.fromUrl(ct.texts[2], pos, self)
|
ImageTooltip.fromUrl(ct.texts[2], pos, self)
|
||||||
|
|
||||||
elif ct.regex == self.inlineLinkRegex:
|
elif ct.regex == self.inlineLinkRegex:
|
||||||
tooltip = ct.texts[1] or ct.texts[2]
|
tooltip = ct.texts[1] or ct.texts[2]
|
||||||
|
@ -582,53 +582,85 @@ from PyQt5.QtNetwork import QNetworkRequest, QNetworkAccessManager, QNetworkRepl
|
||||||
from PyQt5.QtCore import QIODevice, QUrl, QBuffer
|
from PyQt5.QtCore import QIODevice, QUrl, QBuffer
|
||||||
from PyQt5.QtGui import QPixmap
|
from PyQt5.QtGui import QPixmap
|
||||||
|
|
||||||
class imageTooltiper:
|
class ImageTooltip:
|
||||||
|
"""
|
||||||
|
This class handles the retrieving and caching of images in order to display these in tooltips.
|
||||||
|
"""
|
||||||
|
|
||||||
cache = {}
|
cache = {}
|
||||||
manager = QNetworkAccessManager()
|
manager = QNetworkAccessManager()
|
||||||
data = {}
|
processing = {}
|
||||||
|
|
||||||
def fromUrl(url, pos, editor):
|
def fromUrl(url, pos, editor):
|
||||||
cache = imageTooltiper.cache
|
"""
|
||||||
imageTooltiper.editor = editor
|
Shows the image tooltip for the given url if available, or requests it for future use.
|
||||||
|
"""
|
||||||
|
ImageTooltip.editor = editor
|
||||||
|
|
||||||
if url in cache:
|
if ImageTooltip.showTooltip(url, pos):
|
||||||
if not cache[url][0]: # error, image was not found
|
return # the url already exists in the cache
|
||||||
imageTooltiper.tooltipError(cache[url][1], pos)
|
|
||||||
else:
|
|
||||||
imageTooltiper.tooltip(cache[url][1], pos)
|
|
||||||
return
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
imageTooltiper.manager.finished.connect(imageTooltiper.finished, F.AUC)
|
ImageTooltip.manager.finished.connect(ImageTooltip.finished, F.AUC)
|
||||||
except:
|
except:
|
||||||
pass
|
pass # already connected
|
||||||
|
|
||||||
request = QNetworkRequest(QUrl(url))
|
qurl = QUrl(url)
|
||||||
imageTooltiper.data[QUrl(url)] = (pos, url)
|
if (qurl in ImageTooltip.processing):
|
||||||
imageTooltiper.manager.get(request)
|
return # one download is more than enough
|
||||||
|
|
||||||
|
# Request the image for later processing.
|
||||||
|
request = QNetworkRequest(qurl)
|
||||||
|
ImageTooltip.processing[qurl] = (pos, url)
|
||||||
|
ImageTooltip.manager.get(request)
|
||||||
|
|
||||||
def finished(reply):
|
def finished(reply):
|
||||||
cache = imageTooltiper.cache
|
"""
|
||||||
pos, url = imageTooltiper.data[reply.url()]
|
After retrieving an image, we add it to the cache.
|
||||||
|
"""
|
||||||
|
cache = ImageTooltip.cache
|
||||||
|
|
||||||
|
# Update cache with retrieved data.
|
||||||
|
pos, url = ImageTooltip.processing[reply.request().url()]
|
||||||
if reply.error() != QNetworkReply.NoError:
|
if reply.error() != QNetworkReply.NoError:
|
||||||
cache[url] = (False, reply.errorString())
|
cache[url] = (False, reply.errorString())
|
||||||
imageTooltiper.tooltipError(reply.errorString(), pos)
|
|
||||||
else:
|
else:
|
||||||
px = QPixmap()
|
px = QPixmap()
|
||||||
px.loadFromData(reply.readAll())
|
px.loadFromData(reply.readAll())
|
||||||
px = px.scaled(800, 600, Qt.KeepAspectRatio)
|
px = px.scaled(800, 600, Qt.KeepAspectRatio)
|
||||||
cache[url] = (True, px)
|
cache[url] = (True, px)
|
||||||
imageTooltiper.tooltip(px, pos)
|
del ImageTooltip.processing[reply.request().url()]
|
||||||
|
|
||||||
|
ImageTooltip.showTooltip(url, pos)
|
||||||
|
|
||||||
|
def showTooltip(url, pos):
|
||||||
|
"""
|
||||||
|
Show a tooltip for the given url based on cached information.
|
||||||
|
"""
|
||||||
|
cache = ImageTooltip.cache
|
||||||
|
|
||||||
|
if url in cache:
|
||||||
|
if not cache[url][0]: # error, image was not found
|
||||||
|
ImageTooltip.tooltipError(cache[url][1], pos)
|
||||||
|
else:
|
||||||
|
ImageTooltip.tooltip(cache[url][1], pos)
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
def tooltipError(message, pos):
|
def tooltipError(message, pos):
|
||||||
imageTooltiper.editor.doTooltip(pos, message)
|
"""
|
||||||
|
Display a tooltip with an error message at the given position.
|
||||||
|
"""
|
||||||
|
ImageTooltip.editor.doTooltip(pos, message)
|
||||||
|
|
||||||
def tooltip(image, pos):
|
def tooltip(image, pos):
|
||||||
|
"""
|
||||||
|
Display a tooltip with an image at the given position.
|
||||||
|
"""
|
||||||
px = image
|
px = image
|
||||||
buffer = QBuffer()
|
buffer = QBuffer()
|
||||||
buffer.open(QIODevice.WriteOnly)
|
buffer.open(QIODevice.WriteOnly)
|
||||||
px.save(buffer, "PNG", quality=100)
|
px.save(buffer, "PNG", quality=100)
|
||||||
image = bytes(buffer.data().toBase64()).decode()
|
image = bytes(buffer.data().toBase64()).decode()
|
||||||
tt = "<p><img src='data:image/png;base64,{}'></p>".format(image)
|
tt = "<p><img src='data:image/png;base64,{}'></p>".format(image)
|
||||||
imageTooltiper.editor.doTooltip(pos, tt)
|
ImageTooltip.editor.doTooltip(pos, tt)
|
||||||
|
|
Loading…
Reference in a new issue