From 3793fa09ff920fc720dfad3738f105d2c9563662 Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Fri, 13 Apr 2012 17:10:50 +0200 Subject: [PATCH] Allow Qt to wrap long tooltips (fixes #1063) Implemented without having to touch any translation: by listening for QEvent::ToolTipChange events, then rewriting the tooltips to prefix `` if it is not yet rich text. --- src/qt/bitcoin.cpp | 4 ++++ src/qt/bitcoingui.cpp | 9 ++++++--- src/qt/guiconstants.h | 5 +++++ src/qt/guiutil.cpp | 24 ++++++++++++++++++++++++ src/qt/guiutil.h | 18 ++++++++++++++++++ 5 files changed, 57 insertions(+), 3 deletions(-) diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp index e752269ca..d0a158a02 100644 --- a/src/qt/bitcoin.cpp +++ b/src/qt/bitcoin.cpp @@ -6,6 +6,7 @@ #include "walletmodel.h" #include "optionsmodel.h" #include "guiutil.h" +#include "guiconstants.h" #include "init.h" #include "ui_interface.h" @@ -164,6 +165,9 @@ int main(int argc, char *argv[]) Q_INIT_RESOURCE(bitcoin); QApplication app(argc, argv); + // Install global event filter that makes sure that long tooltips can be word-wrapped + app.installEventFilter(new GUIUtil::ToolTipToRichTextFilter(TOOLTIP_WRAP_THRESHOLD, &app)); + // Command-line options take precedence: ParseParameters(argc, argv); diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index bcf90917e..db0ddf453 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -551,22 +551,25 @@ void BitcoinGUI::setNumBlocks(int count) // Set icon state: spinning if catching up, tick otherwise if(secs < 90*60 && count >= nTotalBlocks) { - tooltip = tr("Up to date") + QString(".\n") + tooltip; + tooltip = tr("Up to date") + QString(".
") + tooltip; labelBlocksIcon->setPixmap(QIcon(":/icons/synced").pixmap(STATUSBAR_ICONSIZE, STATUSBAR_ICONSIZE)); } else { - tooltip = tr("Catching up...") + QString("\n") + tooltip; + tooltip = tr("Catching up...") + QString("
") + tooltip; labelBlocksIcon->setMovie(syncIconMovie); syncIconMovie->start(); } if(!text.isEmpty()) { - tooltip += QString("\n"); + tooltip += QString("
"); tooltip += tr("Last received block was generated %1.").arg(text); } + // Don't word-wrap this (fixed-width) tooltip + tooltip = QString("") + tooltip + QString(""); + labelBlocksIcon->setToolTip(tooltip); progressBarLabel->setToolTip(tooltip); progressBar->setToolTip(tooltip); diff --git a/src/qt/guiconstants.h b/src/qt/guiconstants.h index 0cb507501..54e9d644f 100644 --- a/src/qt/guiconstants.h +++ b/src/qt/guiconstants.h @@ -20,4 +20,9 @@ static const int STATUSBAR_ICONSIZE = 16; /* Transaction list -- bare address (without label) */ #define COLOR_BAREADDRESS QColor(140, 140, 140) +/* Tooltips longer than this (in characters) are converted into rich text, + so that they can be word-wrapped. + */ +static const int TOOLTIP_WRAP_THRESHOLD = 80; + #endif // GUICONSTANTS_H diff --git a/src/qt/guiutil.cpp b/src/qt/guiutil.cpp index f1e8a5f1b..3b8f8c76f 100644 --- a/src/qt/guiutil.cpp +++ b/src/qt/guiutil.cpp @@ -214,5 +214,29 @@ bool isObscured(QWidget *w) && checkPoint(QPoint(w->width()/2, w->height()/2), w)); } +ToolTipToRichTextFilter::ToolTipToRichTextFilter(int size_threshold, QObject *parent): + size_threshold(size_threshold), QObject(parent) +{ + +} + +bool ToolTipToRichTextFilter::eventFilter(QObject *obj, QEvent *evt) +{ + if(evt->type() == QEvent::ToolTipChange) + { + QWidget *widget = static_cast(obj); + QString tooltip = widget->toolTip(); + if(!Qt::mightBeRichText(tooltip) && tooltip.size() > size_threshold) + { + // Prefix to make sure Qt detects this as rich text + // Escape the current message as HTML and replace \n by
+ tooltip = "" + HtmlEscape(tooltip, true); + widget->setToolTip(tooltip); + return true; + } + } + return QObject::eventFilter(obj, evt); +} + } // namespace GUIUtil diff --git a/src/qt/guiutil.h b/src/qt/guiutil.h index ea1a4795c..8e9aae1cb 100644 --- a/src/qt/guiutil.h +++ b/src/qt/guiutil.h @@ -2,6 +2,7 @@ #define GUIUTIL_H #include +#include QT_BEGIN_NAMESPACE class QFont; @@ -69,6 +70,23 @@ namespace GUIUtil // Determine whether a widget is hidden behind other windows bool isObscured(QWidget *w); + /** Qt event filter that intercepts ToolTipChange events, and replaces the tooltip with a rich text + representation if needed. This assures that Qt can word-wrap long tooltip messages. + Tooltips longer than the provided size threshold (in characters) are wrapped. + */ + class ToolTipToRichTextFilter: public QObject + { + Q_OBJECT + public: + ToolTipToRichTextFilter(int size_threshold, QObject *parent); + + protected: + bool eventFilter(QObject *obj, QEvent *evt); + + private: + int size_threshold; + }; + } // namespace GUIUtil #endif // GUIUTIL_H