class PreviewTooltip(QWidget): def __init__(self, url): QWidget.__init__(self, None, Qt.ToolTip) self.url = url self.font = QFont(QApplication.font(self)) self.font.setPointSize(8) desktop = QApplication.desktop().availableGeometry(self) cursor = QCursor.pos() rect = QRect(cursor + QPoint(-10, 10), QSize(240,180 + QFontMetrics(self.font).height())) if rect.left() < desktop.left(): rect.moveLeft(desktop.left()) if rect.right() > desktop.right(): rect.moveRight(cursor.x() - 10) if rect.bottom() > desktop.bottom(): rect.moveBottom(cursor.y() - 10) self.setGeometry(rect) self.pixmap = None self.progress = 0 self.title = unicode(self.url) self.webView = QWebView() self.webView.page().mainFrame().setScrollBarPolicy(Qt.Horizontal, Qt.ScrollBarAlwaysOff) self.webView.page().mainFrame().setScrollBarPolicy(Qt.Vertical, Qt.ScrollBarAlwaysOff) self.webView.resize(1024,768) self.webView.load(QUrl(url)) self.timer = QTimer(self) self.connect(self.timer, SIGNAL("timeout()"), self.refresh) self.timer.start(3000) self.connect(self.webView, SIGNAL("loadFinished(bool)"), self.refresh) self.connect(self.webView, SIGNAL("loadProgress(int)"), self.updateProgress) self.connect(self.webView, SIGNAL("urlChanged(const QUrl&)"), self.newUrl) self.connect(self.webView, SIGNAL("titleChanged(const QString&)"), self.newTitle) def updateProgress(self, progress): self.progress = progress self.update() def newUrl(self, url): self.title = unicode(url.toString()) self.update() def newTitle(self, title): self.title = unicode(title) self.update() def refresh(self): view = QPixmap(self.webView.size()) self.webView.render(view) self.pixmap = view.scaled(QSize(240,180), Qt.IgnoreAspectRatio, Qt.SmoothTransformation) self.update() def paintEvent(self, event): QWidget.paintEvent(self, event) p = QPainter(self) p.setFont(self.font) if self.pixmap: p.drawPixmap(QPoint(0,0), self.pixmap) r = QRect(self.rect().topLeft() + QPoint(0, 180), QSize(self.rect().size().width(), p.fontMetrics().height())) p.fillRect(r, self.palette().midlight()) if self.progress: pr = QRect(r) pr.setWidth( (r.width() * self.progress) / 100 ) p.fillRect(pr, self.palette().dark()) p.setBrush(Qt.NoBrush) p.setPen(QPen(self.palette().text(), 1)) p.drawText(QRectF(r), self.title, QTextOption(Qt.AlignHCenter)) p.setPen(QPen(self.palette().shadow(), 1)) p.drawRect(self.rect().adjusted(0,0,-1,-1))
class MListWidget(QListWidget): '''Allows setting HTML items instead of just text. This is a nasty hack, unfortunately - thanks to some unfortunate Qt API decicions (QLabel inconsistently hides certain internals :( ) ''' gainedFocus = pyqtSignal() lostFocus = pyqtSignal() def __init__(self, parent = None): QListWidget.__init__(self, parent) self._htmlItemLabel = None self._htmlItemWidget = None self._htmlItemWidgetFinishedLoading = False self._prepHtmlItemWidget() #def focusInEvent(self, event): #self.gainedFocus.emit() #event.accept() #QListWidget.focusInEvent(self, event) #def focusOutEvent(self, event): #self.lostFocus.emit() #event.accept() #QListWidget.focusOutEvent(self, event) #def event(self, event): #if event.type() == QEvent.InputMethod: #print 'ionout pmethod' #self.inputMethodEvent(event) #elif event.type() == QEvent.KeyPress: #print 'key pressed' #return QListWidget.event(self, event) #@pyqtSignature('QInputMethodEvent') #def inputMethodEvent(self, event): #print 'custom input event!' #print event def event(self, event): '''Intercept enter/return presses. ''' if event.type() == QEvent.KeyPress: key_press = QKeyEvent(event) if key_press.key() in [Qt.Key_Enter, Qt.Key_Return]: self.returnPressed.emit() return True return QListWidget.event(self, event) def _htmlItemWidgetLoadedSignal(self, ok): self._htmlItemWidgetFinishedLoading = True def _prepHtmlItemWidget(self): self._htmlItemWidget = QWebView() hw = self._htmlItemWidget hw.loadFinished.connect(self._htmlItemWidgetLoadedSignal) #TODO hw.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) #hw.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) # font ws = hw.settings() font_size = self.font().pointSize() ws.setFontSize(QWebSettings.DefaultFontSize, font_size) ws.setFontFamily(QWebSettings.StandardFont, self.font().family()) # transparency palette = hw.palette() palette.setBrush(QPalette.Base, Qt.transparent) hw.page().setPalette(palette) hw.setAttribute(Qt.WA_OpaquePaintEvent, False) # better rendering hw.setRenderHint(QPainter.Antialiasing, True) hw.setRenderHint(QPainter.TextAntialiasing, True) hw.setRenderHint(QPainter.SmoothPixmapTransform, True) hw.setRenderHint(QPainter.HighQualityAntialiasing, True) hw.setHtml(u'') h = font_size + 6 hw.setFixedHeight(h) def addHtmlItem(self, html, data): '''Adds a new QTextEdit widget containing the given HTMl as an item in the list. ''' item = QListWidgetItem() item.setData(Qt.UserRole, data) self.addItem(item) item.setSizeHint(self._htmlItemWidget.frameSize()) label = QLabel() label.setTextInteractionFlags(Qt.NoTextInteraction) html = u'<html><body style="margin:0px 0px 0px 4px">{0}</body></html>'.format(html) if '<img' in html: self._htmlItemWidgetFinishedLoading = False self._htmlItemWidget.setHtml(html) pm = QImage(self._htmlItemWidget.size(), QImage.Format_ARGB32) pm.fill(Qt.transparent) # wait for it to finish loading, then render q_app = QApplication.instance() while not self._htmlItemWidgetFinishedLoading: q_app.processEvents(QEventLoop.WaitForMoreEvents | QEventLoop.ExcludeUserInputEvents) self._htmlItemWidget.render(pm, flags=QWidget.DrawChildren) label.setPixmap(QPixmap.fromImage(pm)) else: label.setText(html) self.setItemWidget(item, label)