diff --git a/src/libs/utils/tooltip/tips.cpp b/src/libs/utils/tooltip/tips.cpp index 116b0832ad2..7e847dcef23 100644 --- a/src/libs/utils/tooltip/tips.cpp +++ b/src/libs/utils/tooltip/tips.cpp @@ -171,12 +171,7 @@ bool TextTip::isInteractive() const void TextTip::configure(const QPoint &pos, QWidget *w) { - if (contextHelp().isNull()) - setText(m_text); - else - setText(QString::fromLatin1("" - "
%1  " - "
").arg(m_text)); + setText(m_text); // Make it look good with the default ToolTip font on Mac, which has a small descent. QFontMetrics fm(font()); diff --git a/src/libs/utils/tooltip/tooltip.cpp b/src/libs/utils/tooltip/tooltip.cpp index 3dfb6d9b863..28fb3b4f76c 100644 --- a/src/libs/utils/tooltip/tooltip.cpp +++ b/src/libs/utils/tooltip/tooltip.cpp @@ -35,6 +35,7 @@ #include #include #include +#include #include #include #include @@ -60,14 +61,47 @@ ToolTip *ToolTip::instance() return &tooltip; } -void ToolTip::show(const QPoint &pos, const QString &content, QWidget *w, const QVariant &contextHelp, const QRect &rect) +static QWidget *createF1Icon() { - if (content.isEmpty()) - instance()->hideTipWithDelay(); - else - instance()->showInternal(pos, QVariant(content), TextContent, w, contextHelp, rect); + auto label = new QLabel; + label->setPixmap({":/utils/tooltip/images/f1.png"}); + label->setAlignment(Qt::AlignTop); + return label; } +/*! + Shows a tool tip with the text \a content. If \a contextHelp is given, a context help icon + is shown as well. + \a contextHelp of the current shown tool tip can be retrieved via ToolTip::contextHelp(). +*/ +void ToolTip::show(const QPoint &pos, const QString &content, QWidget *w, const QVariant &contextHelp, const QRect &rect) +{ + if (content.isEmpty()) { + instance()->hideTipWithDelay(); + } else { + if (contextHelp.isNull()) { + instance()->showInternal(pos, QVariant(content), TextContent, w, contextHelp, rect); + } else { + auto tooltipWidget = new FakeToolTip; + auto layout = new QHBoxLayout; + layout->setContentsMargins(0, 0, 0, 0); + tooltipWidget->setLayout(layout); + layout->addWidget(new QLabel(content)); + layout->addWidget(createF1Icon()); + instance()->showInternal(pos, + QVariant::fromValue(tooltipWidget), + WidgetContent, + w, + contextHelp, + rect); + } + } +} + +/*! + Shows a tool tip with a small rectangle in the given \a color. + \a contextHelp of the current shown tool tip can be retrieved via ToolTip::contextHelp(). +*/ void ToolTip::show(const QPoint &pos, const QColor &color, QWidget *w, const QVariant &contextHelp, const QRect &rect) { if (!color.isValid()) @@ -76,6 +110,10 @@ void ToolTip::show(const QPoint &pos, const QColor &color, QWidget *w, const QVa instance()->showInternal(pos, QVariant(color), ColorContent, w, contextHelp, rect); } +/*! + Shows the widget \a content as a tool tip. The tool tip takes ownership of the widget. + \a contextHelp of the current shown tool tip can be retrieved via ToolTip::contextHelp(). +*/ void ToolTip::show(const QPoint &pos, QWidget *content, QWidget *w, const QVariant &contextHelp, const QRect &rect) { if (!content) @@ -84,11 +122,25 @@ void ToolTip::show(const QPoint &pos, QWidget *content, QWidget *w, const QVaria instance()->showInternal(pos, QVariant::fromValue(content), WidgetContent, w, contextHelp, rect); } -void ToolTip::show(const QPoint &pos, QLayout *content, QWidget *w, const QVariant &contextHelp, const QRect &rect) +/*! + Shows the layout \a content as a tool tip. The tool tip takes ownership of the layout. + If \a contextHelp is given, a context help icon is shown as well. + \a contextHelp of the current shown tool tip can be retrieved via ToolTip::contextHelp(). +*/ +void ToolTip::show( + const QPoint &pos, QLayout *content, QWidget *w, const QVariant &contextHelp, const QRect &rect) { if (content && content->count()) { auto tooltipWidget = new FakeToolTip; - tooltipWidget->setLayout(content); + if (contextHelp.isNull()) { + tooltipWidget->setLayout(content); + } else { + auto layout = new QHBoxLayout; + layout->setContentsMargins(0, 0, 0, 0); + tooltipWidget->setLayout(layout); + layout->addLayout(content); + layout->addWidget(createF1Icon()); + } instance()->showInternal(pos, QVariant::fromValue(tooltipWidget), WidgetContent, w, contextHelp, rect); } else { instance()->hideTipWithDelay(); diff --git a/src/plugins/coreplugin/helpitem.cpp b/src/plugins/coreplugin/helpitem.cpp index 6349ad17cdc..544c9be9c94 100644 --- a/src/plugins/coreplugin/helpitem.cpp +++ b/src/plugins/coreplugin/helpitem.cpp @@ -107,6 +107,13 @@ bool HelpItem::isValid() const return !links().empty(); } +QString HelpItem::firstParagraph() const +{ + if (!m_firstParagraph) + m_firstParagraph = extractContent(false); + return *m_firstParagraph; +} + QString HelpItem::extractContent(bool extended) const { Utils::HtmlDocExtractor htmlExtractor; diff --git a/src/plugins/coreplugin/helpitem.h b/src/plugins/coreplugin/helpitem.h index c258eed0d8a..3bcd4da4f8b 100644 --- a/src/plugins/coreplugin/helpitem.h +++ b/src/plugins/coreplugin/helpitem.h @@ -79,19 +79,21 @@ public: bool isEmpty() const; bool isValid() const; - QString extractContent(bool extended) const; - + QString firstParagraph() const; const Links &links() const; const Links bestLinks() const; const QString keyword() const; bool isFuzzyMatch() const; private: + QString extractContent(bool extended) const; + QUrl m_helpUrl; QStringList m_helpIds; QString m_docMark; Category m_category = Unknown; mutable Utils::optional m_helpLinks; // cached help links + mutable Utils::optional m_firstParagraph; mutable QString m_keyword; mutable bool m_isFuzzyMatch = false; }; diff --git a/src/plugins/cpptools/cpphoverhandler.cpp b/src/plugins/cpptools/cpphoverhandler.cpp index 057a9de73f6..0598e1fb9cd 100644 --- a/src/plugins/cpptools/cpphoverhandler.cpp +++ b/src/plugins/cpptools/cpphoverhandler.cpp @@ -62,7 +62,7 @@ void CppHoverHandler::identifyMatch(TextEditorWidget *editorWidget, int pos, Rep const QSharedPointer &cppElement = evaluator.cppElement(); const QStringList candidates = cppElement->helpIdCandidates; const HelpItem helpItem(candidates + fallback, cppElement->helpMark, cppElement->helpCategory); - setLastHelpItemIdentified(helpItem); // tool tip appended by BaseHoverHandler::decorateToolTip + setLastHelpItemIdentified(helpItem); if (!helpItem.isValid()) tip += cppElement->tooltip; } else { diff --git a/src/plugins/texteditor/basehoverhandler.cpp b/src/plugins/texteditor/basehoverhandler.cpp index d7d53ca5f0c..52f1990d116 100644 --- a/src/plugins/texteditor/basehoverhandler.cpp +++ b/src/plugins/texteditor/basehoverhandler.cpp @@ -30,14 +30,14 @@ #include #include +#include + namespace TextEditor { BaseHoverHandler::~BaseHoverHandler() = default; -void BaseHoverHandler::showToolTip(TextEditorWidget *widget, const QPoint &point, bool decorate) +void BaseHoverHandler::showToolTip(TextEditorWidget *widget, const QPoint &point) { - if (decorate) - decorateToolTip(); operateTooltip(widget, point); } @@ -140,31 +140,32 @@ void BaseHoverHandler::identifyMatch(TextEditorWidget *editorWidget, int pos, Re setToolTip(tooltip); } -void BaseHoverHandler::decorateToolTip() +void BaseHoverHandler::operateTooltip(TextEditorWidget *editorWidget, const QPoint &point) { - if (!m_toolTip.isEmpty()) - m_toolTip = "

" + m_toolTip.toHtmlEscaped().replace('\n', "
") + "

"; - - if (lastHelpItemIdentified().isValid() && !lastHelpItemIdentified().isFuzzyMatch()) { - const QString &helpContents = lastHelpItemIdentified().extractContent(false); - if (!helpContents.isEmpty()) { - m_toolTip = m_toolTip.isEmpty() ? helpContents - : (m_toolTip + "

" + helpContents + "

"); + const QVariant helpItem = m_lastHelpItemIdentified.isEmpty() + ? QVariant() + : QVariant::fromValue(m_lastHelpItemIdentified); + const bool extractHelp = m_lastHelpItemIdentified.isValid() + && !m_lastHelpItemIdentified.isFuzzyMatch(); + const QString helpContents = extractHelp ? m_lastHelpItemIdentified.firstParagraph() + : QString(); + if (m_toolTip.isEmpty() && helpContents.isEmpty()) { + Utils::ToolTip::hide(); + } else { + if (helpContents.isEmpty()) { + Utils::ToolTip::show(point, m_toolTip, editorWidget, helpItem); + } else if (m_toolTip.isEmpty()) { + Utils::ToolTip::show(point, helpContents, editorWidget, helpItem); + } else { + // separate labels for tool tip text and help, + // so the text format (plain, rich, markdown) can be handled differently + auto layout = new QVBoxLayout; + layout->setContentsMargins(0, 0, 0, 0); + layout->addWidget(new QLabel(m_toolTip)); + layout->addWidget(new QLabel("
" + helpContents)); + Utils::ToolTip::show(point, layout, editorWidget, helpItem); } } } -void BaseHoverHandler::operateTooltip(TextEditorWidget *editorWidget, const QPoint &point) -{ - if (m_toolTip.isEmpty()) - Utils::ToolTip::hide(); - else - Utils::ToolTip::show(point, - m_toolTip, - editorWidget, - m_lastHelpItemIdentified.isEmpty() - ? QVariant() - : QVariant::fromValue(m_lastHelpItemIdentified)); -} - } // namespace TextEditor diff --git a/src/plugins/texteditor/basehoverhandler.h b/src/plugins/texteditor/basehoverhandler.h index d7ff52aa9a8..2f8058bfdb0 100644 --- a/src/plugins/texteditor/basehoverhandler.h +++ b/src/plugins/texteditor/basehoverhandler.h @@ -53,7 +53,7 @@ public: void checkPriority(TextEditorWidget *widget, int pos, ReportPriority report); virtual void abort() {} // Implement for asynchronous priority reporter - void showToolTip(TextEditorWidget *widget, const QPoint &point, bool decorate = true); + void showToolTip(TextEditorWidget *widget, const QPoint &point); protected: enum { @@ -84,7 +84,6 @@ protected: private: void process(TextEditorWidget *widget, int pos, ReportPriority report); - void decorateToolTip(); QString m_toolTip; Core::HelpItem m_lastHelpItemIdentified; diff --git a/src/plugins/texteditor/texteditor.cpp b/src/plugins/texteditor/texteditor.cpp index b03cef1de39..1cedb6bad95 100644 --- a/src/plugins/texteditor/texteditor.cpp +++ b/src/plugins/texteditor/texteditor.cpp @@ -310,7 +310,7 @@ public: const int documentRevision = textCursor.document()->revision(); const int position = Text::wordStartCursor(textCursor).position(); if (m_lastHandlerInfo.applies(documentRevision, position)) { - m_lastHandlerInfo.handler->showToolTip(m_widget, point, /*decorate=*/ false); + m_lastHandlerInfo.handler->showToolTip(m_widget, point); return; }