diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp index e752269ca1..d0a158a02c 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 bcf90917ed..db0ddf453f 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 0cb507501a..54e9d644fe 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 f1e8a5f1bc..3b8f8c76f8 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 ea1a4795c0..8e9aae1cb0 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