diff --git a/src/libs/utils/htmldocextractor.cpp b/src/libs/utils/htmldocextractor.cpp index 478795f90457397ef0abe9bcb601a4b884bfa905..2f6481379b50c96cc892ccadf5c671b6aa429ef2 100644 --- a/src/libs/utils/htmldocextractor.cpp +++ b/src/libs/utils/htmldocextractor.cpp @@ -149,6 +149,11 @@ QString HtmlDocExtractor::getFunctionDescription(const QString &html, return contents; } +QString HtmlDocExtractor::getQMLItemDescription(const QString &html, const QString &mark) const +{ + return getClassOrNamespaceDescription(html, mark); +} + QString HtmlDocExtractor::getClassOrNamespaceMemberDescription(const QString &html, const QString &startMark, const QString &endMark) const diff --git a/src/libs/utils/htmldocextractor.h b/src/libs/utils/htmldocextractor.h index a752c1ef80ca9f039bc6f3af4a86b299967b2add..a9acf79a5fd7e4a2bfd291ac92f2001d1ad6e03d 100644 --- a/src/libs/utils/htmldocextractor.h +++ b/src/libs/utils/htmldocextractor.h @@ -54,6 +54,7 @@ public: QString getFunctionDescription(const QString &html, const QString &mark, const bool mainOverload = true) const; + QString getQMLItemDescription(const QString &html, const QString &mark) const; private: QString getClassOrNamespaceMemberDescription(const QString &html, diff --git a/src/plugins/cppeditor/cpphoverhandler.cpp b/src/plugins/cppeditor/cpphoverhandler.cpp index baf9d68854037f79fe2c3f4b48ec4953bf1280a5..6efc3ae1b17ad1b4f4de36db5ec89cdbc0db9d7a 100644 --- a/src/plugins/cppeditor/cpphoverhandler.cpp +++ b/src/plugins/cppeditor/cpphoverhandler.cpp @@ -30,17 +30,12 @@ #include "cpphoverhandler.h" #include "cppeditor.h" -#include <coreplugin/icore.h> -#include <coreplugin/helpmanager.h> -#include <coreplugin/uniqueidmanager.h> +#include <coreplugin/editormanager/ieditor.h> #include <coreplugin/editormanager/editormanager.h> #include <cpptools/cppmodelmanagerinterface.h> #include <extensionsystem/pluginmanager.h> #include <texteditor/itexteditor.h> #include <texteditor/basetexteditor.h> -#include <texteditor/displaysettings.h> -#include <texteditor/tooltip/tooltip.h> -#include <debugger/debuggerconstants.h> #include <FullySpecifiedType.h> #include <Names.h> @@ -128,89 +123,22 @@ namespace { }; } -CppHoverHandler::CppHoverHandler(QObject *parent) - : QObject(parent), m_modelManager(0), m_matchingHelpCandidate(-1) +CppHoverHandler::CppHoverHandler(QObject *parent) : BaseHoverHandler(parent), m_modelManager(0) { m_modelManager = ExtensionSystem::PluginManager::instance()->getObject<CppTools::CppModelManagerInterface>(); - - // Listen for editor opened events in order to connect to tooltip/helpid requests - connect(ICore::instance()->editorManager(), SIGNAL(editorOpened(Core::IEditor *)), - this, SLOT(editorOpened(Core::IEditor *))); } -void CppHoverHandler::editorOpened(IEditor *editor) +bool CppHoverHandler::acceptEditor(IEditor *editor) { CPPEditorEditable *cppEditor = qobject_cast<CPPEditorEditable *>(editor); - if (!cppEditor) - return; - - connect(cppEditor, SIGNAL(tooltipRequested(TextEditor::ITextEditor*, QPoint, int)), - this, SLOT(showToolTip(TextEditor::ITextEditor*, QPoint, int))); - - connect(cppEditor, SIGNAL(contextHelpIdRequested(TextEditor::ITextEditor*, int)), - this, SLOT(updateContextHelpId(TextEditor::ITextEditor*, int))); -} - -void CppHoverHandler::updateContextHelpId(TextEditor::ITextEditor *editor, int pos) -{ - if (!editor) - return; - - // If the tooltip is visible and there is a help match, this match is used to update the help - // id. Otherwise, the identification process happens. - if (!TextEditor::ToolTip::instance()->isVisible() || m_matchingHelpCandidate == -1) - identifyMatch(editor, pos); - - if (m_matchingHelpCandidate != -1) - editor->setContextHelpId(m_helpCandidates.at(m_matchingHelpCandidate).m_helpId); - else - editor->setContextHelpId(QString()); -} - -void CppHoverHandler::showToolTip(TextEditor::ITextEditor *editor, const QPoint &point, int pos) -{ - TextEditor::BaseTextEditor *baseEditor = baseTextEditor(editor); - if (!baseEditor) - return; - - editor->setContextHelpId(QString()); - - ICore *core = ICore::instance(); - const int dbgContext = - core->uniqueIDManager()->uniqueIdentifier(Debugger::Constants::C_DEBUGMODE); - if (core->hasContext(dbgContext)) - return; - - identifyMatch(editor, pos); - - if (m_toolTip.isEmpty()) { - TextEditor::ToolTip::instance()->hide(); - } else { - if (!m_classHierarchy.isEmpty()) - generateDiagramTooltip(baseEditor->displaySettings().m_extendTooltips); - else - generateNormalTooltip(baseEditor->displaySettings().m_extendTooltips); - - if (m_matchingHelpCandidate != -1) - addF1ToTooltip(); - - const QPoint pnt = point - QPoint(0, -#ifdef Q_WS_WIN - 24 -#else - 16 -#endif - ); - - TextEditor::ToolTip::instance()->showText(pnt, m_toolTip, editor->widget()); - } + if (cppEditor) + return true; + return false; } void CppHoverHandler::identifyMatch(TextEditor::ITextEditor *editor, int pos) { - resetMatchings(); - if (!m_modelManager) return; @@ -231,7 +159,7 @@ void CppHoverHandler::identifyMatch(TextEditor::ITextEditor *editor, int pos) bool extraSelectionTooltip = false; if (!baseEditor->extraSelectionTooltip(pos).isEmpty()) { - m_toolTip = baseEditor->extraSelectionTooltip(pos); + setToolTip(baseEditor->extraSelectionTooltip(pos)); extraSelectionTooltip = true; } @@ -253,8 +181,6 @@ void CppHoverHandler::identifyMatch(TextEditor::ITextEditor *editor, int pos) const LookupItem &lookupItem = lookupItems.first(); // ### TODO: select best candidate. handleLookupItemMatch(lookupItem, typeOfExpression.context(), !extraSelectionTooltip); } - - evaluateHelpCandidates(); } } @@ -263,7 +189,7 @@ bool CppHoverHandler::matchDiagnosticMessage(const CPlusPlus::Document::Ptr &doc { foreach (const Document::DiagnosticMessage &m, document->diagnosticMessages()) { if (m.line() == line) { - m_toolTip = m.text(); + setToolTip(m.text()); return true; } } @@ -274,9 +200,9 @@ bool CppHoverHandler::matchIncludeFile(const CPlusPlus::Document::Ptr &document, { foreach (const Document::Include &includeFile, document->includes()) { if (includeFile.line() == line) { - m_toolTip = QDir::toNativeSeparators(includeFile.fileName()); + setToolTip(QDir::toNativeSeparators(includeFile.fileName())); const QString &fileName = QFileInfo(includeFile.fileName()).fileName(); - m_helpCandidates.append(HelpCandidate(fileName, fileName, HelpCandidate::Brief)); + addHelpCandidate(HelpCandidate(fileName, fileName, HelpCandidate::Brief)); return true; } } @@ -290,8 +216,8 @@ bool CppHoverHandler::matchMacroInUse(const CPlusPlus::Document::Ptr &document, const unsigned begin = use.begin(); const QString &name = use.macro().name(); if (pos < begin + name.length()) { - m_toolTip = use.macro().toString(); - m_helpCandidates.append(HelpCandidate(name, name, HelpCandidate::Macro)); + setToolTip(use.macro().toString()); + addHelpCandidate(HelpCandidate(name, name, HelpCandidate::Macro)); return true; } } @@ -311,7 +237,7 @@ void CppHoverHandler::handleLookupItemMatch(const LookupItem &lookupItem, overview.setShowReturnTypes(true); if (!matchingDeclaration && assignTooltip) { - m_toolTip = overview.prettyType(matchingType, QString()); + setToolTip(overview.prettyType(matchingType, QString())); } else { QString name; if (matchingDeclaration->enclosingSymbol()->isClass() || @@ -333,9 +259,9 @@ void CppHoverHandler::handleLookupItemMatch(const LookupItem &lookupItem, matchingDeclaration->isNamespace() || matchingDeclaration->isForwardClassDeclaration() || matchingDeclaration->isEnum()) { - m_toolTip = name; + setToolTip(name); } else { - m_toolTip = overview.prettyType(matchingType, name); + setToolTip(overview.prettyType(matchingType, name)); } } @@ -372,7 +298,7 @@ void CppHoverHandler::handleLookupItemMatch(const LookupItem &lookupItem, Symbol *symbol = clazz->symbols().at(0); matchingDeclaration = symbol; name = overview.prettyName(LookupContext::fullyQualifiedName(symbol)); - m_toolTip = name; + setToolTip(name); buildClassHierarchy(symbol, context, overview, &m_classHierarchy); helpCategory = HelpCandidate::ClassOrNamespace; } @@ -391,93 +317,46 @@ void CppHoverHandler::handleLookupItemMatch(const LookupItem &lookupItem, docMark = overview.prettyType(matchingType, docMark); overview.setShowFunctionSignatures(false); const QString &functionName = overview.prettyName(matchingDeclaration->name()); - m_helpCandidates.append(HelpCandidate(functionName, docMark, helpCategory)); + addHelpCandidate(HelpCandidate(functionName, docMark, helpCategory)); } else if (matchingDeclaration->enclosingSymbol()->isEnum()) { Symbol *enumSymbol = matchingDeclaration->enclosingSymbol()->asEnum(); docMark = overview.prettyName(enumSymbol->name()); } - m_helpCandidates.append(HelpCandidate(name, docMark, helpCategory)); + addHelpCandidate(HelpCandidate(name, docMark, helpCategory)); } } } void CppHoverHandler::evaluateHelpCandidates() { - for (int i = 0; i < m_helpCandidates.size() && m_matchingHelpCandidate == -1; ++i) { - if (helpIdExists(m_helpCandidates.at(i).m_helpId)) { - m_matchingHelpCandidate = i; + for (int i = 0; i < helpCandidates().size() && matchingHelpCandidate() == -1; ++i) { + if (helpIdExists(helpCandidates().at(i).m_helpId)) { + setMatchingHelpCandidate(i); } else { // There are class help ids with and without qualification. - HelpCandidate &candidate = m_helpCandidates[i]; + HelpCandidate candidate = helpCandidates().at(i); const QString &helpId = removeClassNameQualification(candidate.m_helpId); if (helpIdExists(helpId)) { candidate.m_helpId = helpId; - m_matchingHelpCandidate = i; + setHelpCandidate(candidate, i); + setMatchingHelpCandidate(i); } } } } -bool CppHoverHandler::helpIdExists(const QString &helpId) const +void CppHoverHandler::decorateToolTip(TextEditor::ITextEditor *editor) { - QMap<QString, QUrl> helpLinks = Core::HelpManager::instance()->linksForIdentifier(helpId); - if (!helpLinks.isEmpty()) - return true; - return false; -} - -QString CppHoverHandler::getDocContents(const bool extended) -{ - Q_ASSERT(m_matchingHelpCandidate >= 0); - - return getDocContents(m_helpCandidates.at(m_matchingHelpCandidate), extended); -} - -QString CppHoverHandler::getDocContents(const HelpCandidate &help, const bool extended) -{ - if (extended) - m_htmlDocExtractor.extractExtendedContents(1500, true); + if (!m_classHierarchy.isEmpty()) + generateDiagramTooltip(extendToolTips(editor)); else - m_htmlDocExtractor.extractFirstParagraphOnly(); - - QString contents; - QMap<QString, QUrl> helpLinks = - Core::HelpManager::instance()->linksForIdentifier(help.m_helpId); - foreach (const QUrl &url, helpLinks) { - const QByteArray &html = Core::HelpManager::instance()->fileData(url); - switch (help.m_category) { - case HelpCandidate::Brief: - contents = m_htmlDocExtractor.getClassOrNamespaceBrief(html, help.m_docMark); - break; - case HelpCandidate::ClassOrNamespace: - contents = m_htmlDocExtractor.getClassOrNamespaceDescription(html, help.m_docMark); - break; - case HelpCandidate::Function: - contents = m_htmlDocExtractor.getFunctionDescription(html, help.m_docMark); - break; - case HelpCandidate::Enum: - contents = m_htmlDocExtractor.getEnumDescription(html, help.m_docMark); - break; - case HelpCandidate::Typedef: - contents = m_htmlDocExtractor.getTypedefDescription(html, help.m_docMark); - break; - case HelpCandidate::Macro: - contents = m_htmlDocExtractor.getMacroDescription(html, help.m_docMark); - break; - default: - break; - } - - if (!contents.isEmpty()) - break; - } - return contents; + generateNormalTooltip(extendToolTips(editor)); } void CppHoverHandler::generateDiagramTooltip(const bool extendTooltips) { - QString clazz = m_toolTip; + QString clazz = toolTip(); qSort(m_classHierarchy.begin(), m_classHierarchy.end(), ClassHierarchyComp()); @@ -498,7 +377,7 @@ void CppHoverHandler::generateDiagramTooltip(const bool extendTooltips) diagram.append(QString( "<tr><td>%1</td><td>" "<img src=\":/cppeditor/images/rightarrow.png\"></td>" - "<td>%2</td></tr>").arg(m_toolTip).arg(directBaseClasses.at(i))); + "<td>%2</td></tr>").arg(toolTip()).arg(directBaseClasses.at(i))); } else { diagram.append(QString( "<tr><td></td><td>" @@ -507,10 +386,10 @@ void CppHoverHandler::generateDiagramTooltip(const bool extendTooltips) } } diagram.append(QLatin1String("</table>")); - m_toolTip = diagram; + setToolTip(diagram); - if (m_matchingHelpCandidate != -1) { - m_toolTip.append(getDocContents(extendTooltips)); + if (matchingHelpCandidate() != -1) { + appendToolTip(getDocContents(extendTooltips)); } else { // Look for documented base classes. Diagram the nearest one or the nearest ones (in // the case there are many at the same level). @@ -521,8 +400,18 @@ void CppHoverHandler::generateDiagramTooltip(const bool extendTooltips) if (helpLevel != 0 && hierarchy.size() != helpLevel) break; - const QString &name = hierarchy.last(); + bool exists = false; + QString name = hierarchy.last(); if (helpIdExists(name)) { + exists = true; + } else { + name = removeClassNameQualification(name); + if (helpIdExists(name)) { + exists = true; + m_classHierarchy[i].last() = name; + } + } + if (exists) { baseClassesWithHelp.append(i); if (helpLevel == 0) helpLevel = hierarchy.size(); @@ -533,14 +422,14 @@ void CppHoverHandler::generateDiagramTooltip(const bool extendTooltips) // Choose the first one as the help match. QString base = m_classHierarchy.at(baseClassesWithHelp.at(0)).last(); HelpCandidate help(base, base, HelpCandidate::ClassOrNamespace); - m_helpCandidates.append(help); - m_matchingHelpCandidate = m_helpCandidates.size() - 1; + addHelpCandidate(help); + setMatchingHelpCandidate(helpCandidates().size() - 1); if (baseClassesWithHelp.size() == 1 && helpLevel == 1) { - m_toolTip.append(getDocContents(help, extendTooltips)); + appendToolTip(getDocContents(help, extendTooltips)); } else { foreach (int hierarchyIndex, baseClassesWithHelp) { - m_toolTip.append(QLatin1String("<p>")); + appendToolTip(QLatin1String("<p>")); const QStringList &hierarchy = m_classHierarchy.at(hierarchyIndex); Q_ASSERT(helpLevel <= hierarchy.size()); @@ -557,13 +446,13 @@ void CppHoverHandler::generateDiagramTooltip(const bool extendTooltips) diagram.append(QLatin1String("</tr></table>")); base = hierarchy.at(helpLevel - 1); - QString contents = + const QString &contents = getDocContents(HelpCandidate(base, base, HelpCandidate::Brief), false); if (!contents.isEmpty()) { - m_toolTip.append(diagram % QLatin1String("<table><tr><td>") % - contents % QLatin1String("</td></tr></table>")); + appendToolTip(diagram % QLatin1String("<table><tr><td>") % + contents % QLatin1String("</td></tr></table>")); } - m_toolTip.append(QLatin1String("</p>")); + appendToolTip(QLatin1String("</p>")); } } } @@ -572,40 +461,24 @@ void CppHoverHandler::generateDiagramTooltip(const bool extendTooltips) void CppHoverHandler::generateNormalTooltip(const bool extendTooltips) { - if (m_matchingHelpCandidate != -1) { + if (matchingHelpCandidate() != -1) { const QString &contents = getDocContents(extendTooltips); if (!contents.isEmpty()) { - HelpCandidate::Category cat = m_helpCandidates.at(m_matchingHelpCandidate).m_category; + HelpCandidate::Category cat = helpCandidate(matchingHelpCandidate()).m_category; if (cat == HelpCandidate::ClassOrNamespace) - m_toolTip.append(contents); + appendToolTip(contents); else - m_toolTip = contents; + setToolTip(contents); } else { - m_toolTip = Qt::escape(m_toolTip); - m_toolTip.prepend(QLatin1String("<nobr>")); - m_toolTip.append(QLatin1String("</nobr>")); + QString tip = Qt::escape(toolTip()); + tip.prepend(QLatin1String("<nobr>")); + tip.append(QLatin1String("</nobr>")); + setToolTip(tip); } } } -void CppHoverHandler::addF1ToTooltip() -{ - m_toolTip = QString(QLatin1String("<table><tr><td valign=middle>%1</td><td> " - "<img src=\":/cppeditor/images/f1.png\"></td>" - "</tr></table>")).arg(m_toolTip); -} - -void CppHoverHandler::resetMatchings() +void CppHoverHandler::resetExtras() { - m_matchingHelpCandidate = -1; - m_helpCandidates.clear(); - m_toolTip.clear(); m_classHierarchy.clear(); } - -TextEditor::BaseTextEditor *CppHoverHandler::baseTextEditor(TextEditor::ITextEditor *editor) -{ - if (!editor) - return 0; - return qobject_cast<TextEditor::BaseTextEditor *>(editor->widget()); -} diff --git a/src/plugins/cppeditor/cpphoverhandler.h b/src/plugins/cppeditor/cpphoverhandler.h index 094bf68b4b2d52f2a00e65121d1d2ebdd73f8e23..1fab49b1d2e06658b23a81f3435745e97f02c394 100644 --- a/src/plugins/cppeditor/cpphoverhandler.h +++ b/src/plugins/cppeditor/cpphoverhandler.h @@ -31,16 +31,12 @@ #define CPPHOVERHANDLER_H #include <cplusplus/CppDocument.h> -#include <utils/htmldocextractor.h> +#include <texteditor/basehoverhandler.h> #include <QtCore/QObject> #include <QtCore/QList> #include <QtCore/QStringList> -QT_BEGIN_NAMESPACE -class QPoint; -QT_END_NAMESPACE - namespace CPlusPlus { class LookupItem; class LookupContext; @@ -56,48 +52,24 @@ class CppModelManagerInterface; namespace TextEditor { class ITextEditor; -class BaseTextEditor; } namespace CppEditor { namespace Internal { -class CppHoverHandler : public QObject +class CppHoverHandler : public TextEditor::BaseHoverHandler { Q_OBJECT public: CppHoverHandler(QObject *parent = 0); -public slots: - void showToolTip(TextEditor::ITextEditor *editor, const QPoint &point, int pos); - void updateContextHelpId(TextEditor::ITextEditor *editor, int pos); - -private slots: - void editorOpened(Core::IEditor *editor); - private: - struct HelpCandidate - { - enum Category { - ClassOrNamespace, - Enum, - Typedef, - Macro, - Brief, - Function, - Unknown - }; + virtual bool acceptEditor(Core::IEditor *editor); + virtual void identifyMatch(TextEditor::ITextEditor *editor, int pos); + virtual void resetExtras(); + virtual void evaluateHelpCandidates(); + virtual void decorateToolTip(TextEditor::ITextEditor *editor); - HelpCandidate(const QString &helpId, const QString &docMark, Category category) : - m_helpId(helpId), m_docMark(docMark), m_category(category) - {} - QString m_helpId; - QString m_docMark; - Category m_category; - }; - - void resetMatchings(); - void identifyMatch(TextEditor::ITextEditor *editor, int pos); bool matchDiagnosticMessage(const CPlusPlus::Document::Ptr &document, unsigned line); bool matchIncludeFile(const CPlusPlus::Document::Ptr &document, unsigned line); bool matchMacroInUse(const CPlusPlus::Document::Ptr &document, unsigned pos); @@ -105,23 +77,11 @@ private: const CPlusPlus::LookupContext &lookupContext, const bool assignTooltip); - void evaluateHelpCandidates(); - bool helpIdExists(const QString &helpId) const; - QString getDocContents(const bool extended); - QString getDocContents(const HelpCandidate &helpCandidate, const bool extended); - void generateDiagramTooltip(const bool extendTooltips); void generateNormalTooltip(const bool extendTooltips); - void addF1ToTooltip(); - - static TextEditor::BaseTextEditor *baseTextEditor(TextEditor::ITextEditor *editor); CppTools::CppModelManagerInterface *m_modelManager; - int m_matchingHelpCandidate; - QList<HelpCandidate> m_helpCandidates; - QString m_toolTip; QList<QStringList> m_classHierarchy; - Utils::HtmlDocExtractor m_htmlDocExtractor; }; } // namespace Internal diff --git a/src/plugins/qmljseditor/qmljshoverhandler.cpp b/src/plugins/qmljseditor/qmljshoverhandler.cpp index aa7e22d60fe136438fb97e48e1ec3fafe2c8915b..b12377d751905122a4863684fc30bc48d2aca382 100644 --- a/src/plugins/qmljseditor/qmljshoverhandler.cpp +++ b/src/plugins/qmljseditor/qmljshoverhandler.cpp @@ -31,11 +31,8 @@ #include "qmlexpressionundercursor.h" #include "qmljshoverhandler.h" -#include <coreplugin/icore.h> -#include <coreplugin/helpmanager.h> -#include <coreplugin/uniqueidmanager.h> +#include <coreplugin/editormanager/ieditor.h> #include <coreplugin/editormanager/editormanager.h> -#include <debugger/debuggerconstants.h> #include <extensionsystem/pluginmanager.h> #include <qmljs/qmljsinterpreter.h> #include <qmljs/parser/qmljsast_p.h> @@ -81,97 +78,22 @@ namespace { } } -HoverHandler::HoverHandler(QObject *parent) : - QObject(parent), m_modelManager(0), m_matchingHelpCandidate(-1) +HoverHandler::HoverHandler(QObject *parent) : BaseHoverHandler(parent), m_modelManager(0) { m_modelManager = ExtensionSystem::PluginManager::instance()->getObject<QmlJS::ModelManagerInterface>(); - - // Listen for editor opened events in order to connect to tooltip/helpid requests - connect(ICore::instance()->editorManager(), SIGNAL(editorOpened(Core::IEditor *)), - this, SLOT(editorOpened(Core::IEditor *))); } -void HoverHandler::editorOpened(IEditor *editor) +bool HoverHandler::acceptEditor(IEditor *editor) { QmlJSEditorEditable *qmlEditor = qobject_cast<QmlJSEditorEditable *>(editor); - if (!qmlEditor) - return; - - connect(qmlEditor, SIGNAL(tooltipRequested(TextEditor::ITextEditor*, QPoint, int)), - this, SLOT(showToolTip(TextEditor::ITextEditor*, QPoint, int))); - - connect(qmlEditor, SIGNAL(contextHelpIdRequested(TextEditor::ITextEditor*, int)), - this, SLOT(updateContextHelpId(TextEditor::ITextEditor*, int))); -} - -void HoverHandler::showToolTip(TextEditor::ITextEditor *editor, const QPoint &point, int pos) -{ - if (!editor) - return; - - ICore *core = ICore::instance(); - const int dbgcontext = - core->uniqueIDManager()->uniqueIdentifier(Debugger::Constants::C_DEBUGMODE); - if (core->hasContext(dbgcontext)) - return; - - editor->setContextHelpId(QString()); - - identifyMatch(editor, pos); - - if (m_toolTip.isEmpty()) - TextEditor::ToolTip::instance()->hide(); - else { - const QPoint &pnt = point - QPoint(0, -#ifdef Q_WS_WIN - 24 -#else - 16 -#endif - ); - - if (m_colorTip.isValid()) { - TextEditor::ToolTip::instance()->showColor(pnt, m_colorTip, editor->widget()); - } else { - m_toolTip = Qt::escape(m_toolTip); - if (m_matchingHelpCandidate != -1) { - m_toolTip = QString::fromUtf8( - "<table><tr><td valign=middle><nobr>%1</td><td>" - "<img src=\":/cppeditor/images/f1.png\"></td></tr></table>").arg(m_toolTip); - } else { - m_toolTip = QString::fromUtf8("<nobr>%1</nobr>").arg(m_toolTip); - } - TextEditor::ToolTip::instance()->showText(pnt, m_toolTip, editor->widget()); - } - } -} - -void HoverHandler::updateContextHelpId(TextEditor::ITextEditor *editor, int pos) -{ - // If the tooltip is visible and there is a help match, use it to update the help id. - // Otherwise, identify the match. - if (!TextEditor::ToolTip::instance()->isVisible() || m_matchingHelpCandidate == -1) - identifyMatch(editor, pos); - - if (m_matchingHelpCandidate != -1) - editor->setContextHelpId(m_helpCandidates.at(m_matchingHelpCandidate)); - else - editor->setContextHelpId(QString()); -} - -void HoverHandler::resetMatchings() -{ - m_matchingHelpCandidate = -1; - m_helpCandidates.clear(); - m_toolTip.clear(); - m_colorTip = QColor(); + if (qmlEditor) + return true; + return false; } void HoverHandler::identifyMatch(TextEditor::ITextEditor *editor, int pos) { - resetMatchings(); - if (!m_modelManager) return; @@ -195,8 +117,6 @@ void HoverHandler::identifyMatch(TextEditor::ITextEditor *editor, int pos) if (!matchColorItem(lookupContext, qmlDocument, astPath, pos)) handleOrdinaryMatch(lookupContext, semanticInfo.nodeUnderCursor(pos)); } - - evaluateHelpCandidates(); } bool HoverHandler::matchDiagnosticMessage(QmlJSTextEditor *qmlEditor, int pos) @@ -204,7 +124,7 @@ bool HoverHandler::matchDiagnosticMessage(QmlJSTextEditor *qmlEditor, int pos) foreach (const QTextEdit::ExtraSelection &sel, qmlEditor->extraSelections(TextEditor::BaseTextEditor::CodeWarningsSelection)) { if (pos >= sel.cursor.selectionStart() && pos <= sel.cursor.selectionEnd()) { - m_toolTip = sel.format.toolTip(); + setToolTip(sel.format.toolTip()); return true; } } @@ -260,7 +180,7 @@ bool HoverHandler::matchColorItem(const LookupContext::Ptr &lookupContext, m_colorTip = QmlJS::toQColor(color); if (m_colorTip.isValid()) { - m_toolTip = color; + setToolTip(color); return true; } } @@ -272,23 +192,59 @@ void HoverHandler::handleOrdinaryMatch(const LookupContext::Ptr &lookupContext, if (node && !(AST::cast<AST::StringLiteral *>(node) != 0 || AST::cast<AST::NumericLiteral *>(node) != 0)) { const Interpreter::Value *value = lookupContext->evaluate(node); - m_toolTip = prettyPrint(value, lookupContext->context()); + setToolTip(prettyPrint(value, lookupContext->context())); } } +void HoverHandler::resetExtras() +{ + m_colorTip = QColor(); +} + void HoverHandler::evaluateHelpCandidates() { - for (int i = 0; i < m_helpCandidates.size(); ++i) { - QString helpId = m_helpCandidates.at(i); - helpId.prepend(QLatin1String("QML.")); - if (!Core::HelpManager::instance()->linksForIdentifier(helpId).isEmpty()) { - m_matchingHelpCandidate = i; - m_helpCandidates[i] = helpId; + for (int i = 0; i < helpCandidates().size(); ++i) { + HelpCandidate helpCandidate = helpCandidates().at(i); + helpCandidate.m_helpId.prepend(QLatin1String("QML.")); + if (helpIdExists(helpCandidate.m_helpId)) { + setMatchingHelpCandidate(i); + setHelpCandidate(helpCandidate, i); break; } } } +void HoverHandler::decorateToolTip(TextEditor::ITextEditor *editor) +{ + if (matchingHelpCandidate() != -1) { + const QString &contents = getDocContents(extendToolTips(editor)); + if (!contents.isEmpty()) { + appendToolTip(contents); + } else { + QString tip = Qt::escape(toolTip()); + tip.prepend(QLatin1String("<nobr>")); + tip.append(QLatin1String("</nobr>")); + setToolTip(tip); + } + } +} + +void HoverHandler::operateTooltip(TextEditor::ITextEditor *editor, const QPoint &point) +{ + if (toolTip().isEmpty()) + TextEditor::ToolTip::instance()->hide(); + else { + if (m_colorTip.isValid()) { + TextEditor::ToolTip::instance()->showColor(point, m_colorTip, editor->widget()); + } else { + if (matchingHelpCandidate() != -1) + addF1ToToolTip(); + + TextEditor::ToolTip::instance()->showText(point, toolTip(), editor->widget()); + } + } +} + QString HoverHandler::prettyPrint(const QmlJS::Interpreter::Value *value, QmlJS::Interpreter::Context *context) { @@ -300,13 +256,13 @@ QString HoverHandler::prettyPrint(const QmlJS::Interpreter::Value *value, const QString className = objectValue->className(); if (! className.isEmpty()) - m_helpCandidates.append(className); + addHelpCandidate(HelpCandidate(className, HelpCandidate::QML)); objectValue = objectValue->prototype(context); } while (objectValue); - if (! m_helpCandidates.isEmpty()) - return m_helpCandidates.first(); + if (! helpCandidates().isEmpty()) + return helpCandidates().first().m_helpId; } else if (const Interpreter::QmlEnumValue *enumValue = dynamic_cast<const Interpreter::QmlEnumValue *>(value)) { return enumValue->name(); diff --git a/src/plugins/qmljseditor/qmljshoverhandler.h b/src/plugins/qmljseditor/qmljshoverhandler.h index 49f763deef236a8c9ebdaf0d4dac54b656d597b7..13d0cb2db57f2a509ae53838e33a928a673e381a 100644 --- a/src/plugins/qmljseditor/qmljshoverhandler.h +++ b/src/plugins/qmljseditor/qmljshoverhandler.h @@ -32,15 +32,12 @@ #include <qmljs/qmljsmodelmanagerinterface.h> #include <qmljs/qmljslookupcontext.h> +#include <texteditor/basehoverhandler.h> #include <QtCore/QObject> #include <QtCore/QStringList> #include <QtGui/QColor> -QT_BEGIN_NAMESPACE -class QPoint; -QT_END_NAMESPACE - namespace Core { class IEditor; } @@ -55,23 +52,20 @@ namespace Internal { class SemanticInfo; class QmlJSTextEditor; -class HoverHandler : public QObject +class HoverHandler : public TextEditor::BaseHoverHandler { Q_OBJECT - public: HoverHandler(QObject *parent = 0); -public slots: - void showToolTip(TextEditor::ITextEditor *editor, const QPoint &point, int pos); - void updateContextHelpId(TextEditor::ITextEditor *editor, int pos); - -private slots: - void editorOpened(Core::IEditor *editor); - private: - void resetMatchings(); - void identifyMatch(TextEditor::ITextEditor *editor, int pos); + virtual bool acceptEditor(Core::IEditor *editor); + virtual void identifyMatch(TextEditor::ITextEditor *editor, int pos); + virtual void resetExtras(); + virtual void evaluateHelpCandidates(); + virtual void decorateToolTip(TextEditor::ITextEditor *editor); + virtual void operateTooltip(TextEditor::ITextEditor *editor, const QPoint &point); + bool matchDiagnosticMessage(QmlJSTextEditor *qmlEditor, int pos); bool matchColorItem(const QmlJS::LookupContext::Ptr &lookupContext, const QmlJS::Document::Ptr &qmlDocument, @@ -80,15 +74,10 @@ private: void handleOrdinaryMatch(const QmlJS::LookupContext::Ptr &lookupContext, QmlJS::AST::Node *node); - void evaluateHelpCandidates(); - QString prettyPrint(const QmlJS::Interpreter::Value *value, QmlJS::Interpreter::Context *context); QmlJS::ModelManagerInterface *m_modelManager; - int m_matchingHelpCandidate; - QStringList m_helpCandidates; - QString m_toolTip; QColor m_colorTip; }; diff --git a/src/plugins/texteditor/basehoverhandler.cpp b/src/plugins/texteditor/basehoverhandler.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d993bb124664312ff7eb8667d65974bc29bda0e7 --- /dev/null +++ b/src/plugins/texteditor/basehoverhandler.cpp @@ -0,0 +1,260 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** GNU Lesser General Public License Usage +** +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ + +#include "basehoverhandler.h" +#include "itexteditor.h" +#include "basetexteditor.h" +#include "displaysettings.h" +#include "tooltip.h" + +#include <coreplugin/icore.h> +#include <coreplugin/editormanager/editormanager.h> +#include <coreplugin/helpmanager.h> +#include <coreplugin/uniqueidmanager.h> +#include <debugger/debuggerconstants.h> + +#include <QtCore/QPoint> + +using namespace TextEditor; +using namespace Core; + +BaseHoverHandler::BaseHoverHandler(QObject *parent) : + QObject(parent), m_matchingHelpCandidate(-1) +{ + // Listen for editor opened events in order to connect to tooltip/helpid requests + connect(ICore::instance()->editorManager(), SIGNAL(editorOpened(Core::IEditor *)), + this, SLOT(editorOpened(Core::IEditor *))); +} + +void BaseHoverHandler::editorOpened(Core::IEditor *editor) +{ + if (acceptEditor(editor)) { + BaseTextEditorEditable *textEditor = qobject_cast<BaseTextEditorEditable *>(editor); + if (textEditor) { + connect(textEditor, SIGNAL(tooltipRequested(TextEditor::ITextEditor*, QPoint, int)), + this, SLOT(showToolTip(TextEditor::ITextEditor*, QPoint, int))); + + connect(textEditor, SIGNAL(contextHelpIdRequested(TextEditor::ITextEditor*, int)), + this, SLOT(updateContextHelpId(TextEditor::ITextEditor*, int))); + } + } +} + +void BaseHoverHandler::showToolTip(TextEditor::ITextEditor *editor, const QPoint &point, int pos) +{ + BaseTextEditor *baseEditor = baseTextEditor(editor); + if (!baseEditor) + return; + + editor->setContextHelpId(QString()); + + ICore *core = ICore::instance(); + const int dbgContext = + core->uniqueIDManager()->uniqueIdentifier(Debugger::Constants::C_DEBUGMODE); + if (core->hasContext(dbgContext)) + return; + + process(editor, pos); + + const QPoint &actualPoint = point - QPoint(0, +#ifdef Q_WS_WIN + 24 +#else + 16 +#endif + ); + + operateTooltip(editor, actualPoint); +} + +void BaseHoverHandler::updateContextHelpId(TextEditor::ITextEditor *editor, int pos) +{ + // If the tooltip is visible and there is a help match, this match is used to update + // the help id. Otherwise, let the identification process happen. + if (!ToolTip::instance()->isVisible() || m_matchingHelpCandidate == -1) + process(editor, pos); + + if (m_matchingHelpCandidate != -1) + editor->setContextHelpId(m_helpCandidates.at(m_matchingHelpCandidate).m_helpId); + else + editor->setContextHelpId(QString()); +} + +void BaseHoverHandler::setToolTip(const QString &tooltip) +{ m_toolTip = tooltip; } + +const QString &BaseHoverHandler::toolTip() const +{ return m_toolTip; } + +void BaseHoverHandler::appendToolTip(const QString &extension) +{ m_toolTip.append(extension); } + +void BaseHoverHandler::addF1ToToolTip() +{ + m_toolTip = QString(QLatin1String("<table><tr><td valign=middle>%1</td><td> " + "<img src=\":/cppeditor/images/f1.png\"></td>" + "</tr></table>")).arg(m_toolTip); +} + +void BaseHoverHandler::reset() +{ + m_matchingHelpCandidate = -1; + m_helpCandidates.clear(); + m_toolTip.clear(); + + resetExtras(); +} + +void BaseHoverHandler::process(ITextEditor *editor, int pos) +{ + reset(); + identifyMatch(editor, pos); + evaluateHelpCandidates(); + decorateToolTip(editor); +} + +void BaseHoverHandler::resetExtras() +{} + +void BaseHoverHandler::evaluateHelpCandidates() +{ + for (int i = 0; i < m_helpCandidates.size(); ++i) { + if (helpIdExists(m_helpCandidates.at(i).m_helpId)) { + m_matchingHelpCandidate = i; + return; + } + } +} + +void BaseHoverHandler::decorateToolTip(ITextEditor *) +{} + +void BaseHoverHandler::operateTooltip(ITextEditor *editor, const QPoint &point) +{ + if (m_toolTip.isEmpty()) { + TextEditor::ToolTip::instance()->hide(); + } else { + if (m_matchingHelpCandidate != -1) + addF1ToToolTip(); + + TextEditor::ToolTip::instance()->showText(point, m_toolTip, editor->widget()); + } +} + +bool BaseHoverHandler::helpIdExists(const QString &helpId) const +{ + if (!Core::HelpManager::instance()->linksForIdentifier(helpId).isEmpty()) + return true; + return false; +} + +void BaseHoverHandler::addHelpCandidate(const HelpCandidate &helpCandidate) +{ m_helpCandidates.append(helpCandidate); } + +void BaseHoverHandler::setHelpCandidate(const HelpCandidate &helpCandidate, int index) +{ m_helpCandidates[index] = helpCandidate; } + +const QList<BaseHoverHandler::HelpCandidate> &BaseHoverHandler::helpCandidates() const +{ return m_helpCandidates; } + +const BaseHoverHandler::HelpCandidate &BaseHoverHandler::helpCandidate(int index) const +{ return m_helpCandidates.at(index); } + +void BaseHoverHandler::setMatchingHelpCandidate(int index) +{ m_matchingHelpCandidate = index; } + +int BaseHoverHandler::matchingHelpCandidate() const +{ return m_matchingHelpCandidate; } + +QString BaseHoverHandler::getDocContents(const bool extended) +{ + Q_ASSERT(m_matchingHelpCandidate >= 0); + + return getDocContents(m_helpCandidates.at(m_matchingHelpCandidate), extended); +} + +QString BaseHoverHandler::getDocContents(const HelpCandidate &help, const bool extended) +{ + if (extended) + m_htmlDocExtractor.extractExtendedContents(1500, true); + else + m_htmlDocExtractor.extractFirstParagraphOnly(); + + QString contents; + QMap<QString, QUrl> helpLinks = + Core::HelpManager::instance()->linksForIdentifier(help.m_helpId); + foreach (const QUrl &url, helpLinks) { + const QByteArray &html = Core::HelpManager::instance()->fileData(url); + switch (help.m_category) { + case HelpCandidate::Brief: + contents = m_htmlDocExtractor.getClassOrNamespaceBrief(html, help.m_docMark); + break; + case HelpCandidate::ClassOrNamespace: + contents = m_htmlDocExtractor.getClassOrNamespaceDescription(html, help.m_docMark); + break; + case HelpCandidate::Function: + contents = m_htmlDocExtractor.getFunctionDescription(html, help.m_docMark); + break; + case HelpCandidate::Enum: + contents = m_htmlDocExtractor.getEnumDescription(html, help.m_docMark); + break; + case HelpCandidate::Typedef: + contents = m_htmlDocExtractor.getTypedefDescription(html, help.m_docMark); + break; + case HelpCandidate::Macro: + contents = m_htmlDocExtractor.getMacroDescription(html, help.m_docMark); + break; + case HelpCandidate::QML: + contents = m_htmlDocExtractor.getQMLItemDescription(html, help.m_docMark); + break; + + default: + break; + } + + if (!contents.isEmpty()) + break; + } + return contents; +} + +BaseTextEditor *BaseHoverHandler::baseTextEditor(ITextEditor *editor) +{ + if (!editor) + return 0; + return qobject_cast<BaseTextEditor *>(editor->widget()); +} + +bool BaseHoverHandler::extendToolTips(ITextEditor *editor) +{ + BaseTextEditor *baseEditor = baseTextEditor(editor); + if (baseEditor && baseEditor->displaySettings().m_extendTooltips) + return true; + return false; +} diff --git a/src/plugins/texteditor/basehoverhandler.h b/src/plugins/texteditor/basehoverhandler.h new file mode 100644 index 0000000000000000000000000000000000000000..587f257210bd9ba5837a94a2fdc545b898dc1489 --- /dev/null +++ b/src/plugins/texteditor/basehoverhandler.h @@ -0,0 +1,133 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** GNU Lesser General Public License Usage +** +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ + +#ifndef BASEHOVERHANDLER_H +#define BASEHOVERHANDLER_H + +#include "texteditor_global.h" + +#include <utils/htmldocextractor.h> + +#include <QtCore/QObject> +#include <QtCore/QString> +#include <QtCore/QList> + +QT_BEGIN_NAMESPACE +class QPoint; +QT_END_NAMESPACE + +namespace Core { +class IEditor; +} + +namespace TextEditor { + +class ITextEditor; +class BaseTextEditor; + +class TEXTEDITOR_EXPORT BaseHoverHandler : public QObject +{ + Q_OBJECT +public: + BaseHoverHandler(QObject *parent = 0); + +private slots: + void editorOpened(Core::IEditor *editor); + +public slots: + void showToolTip(TextEditor::ITextEditor *editor, const QPoint &point, int pos); + void updateContextHelpId(TextEditor::ITextEditor *editor, int pos); + +protected: + void setToolTip(const QString &tooltip); + const QString &toolTip() const; + void appendToolTip(const QString &extension); + void addF1ToToolTip(); + + struct HelpCandidate + { + enum Category { + ClassOrNamespace, + Enum, + Typedef, + Macro, + Brief, + Function, + QML, + Unknown + }; + + HelpCandidate(const QString &helpId, Category category) : + m_helpId(helpId), m_docMark(helpId), m_category(category) + {} + HelpCandidate(const QString &helpId, const QString &docMark, Category category) : + m_helpId(helpId), m_docMark(docMark), m_category(category) + {} + QString m_helpId; + QString m_docMark; + Category m_category; + }; + + void addHelpCandidate(const HelpCandidate &helpCandidate); + void setHelpCandidate(const HelpCandidate &helpCandidate, int index); + const QList<HelpCandidate> &helpCandidates() const; + const HelpCandidate &helpCandidate(int index) const; + + void setMatchingHelpCandidate(int index); + int matchingHelpCandidate() const; + + bool helpIdExists(const QString &helpId) const; + + QString getDocContents(const bool extended); + QString getDocContents(const HelpCandidate &help, const bool extended); + + static BaseTextEditor *baseTextEditor(ITextEditor *editor); + static bool extendToolTips(ITextEditor *editor); + +private: + void reset(); + void process(ITextEditor *editor, int pos); + + virtual bool acceptEditor(Core::IEditor *editor) = 0; + virtual void identifyMatch(ITextEditor *editor, int pos) = 0; + + virtual void resetExtras(); + virtual void evaluateHelpCandidates(); + virtual void decorateToolTip(ITextEditor *editor); + virtual void operateTooltip(ITextEditor *editor, const QPoint &point); + + int m_matchingHelpCandidate; + QList<HelpCandidate> m_helpCandidates; + QString m_toolTip; + Utils::HtmlDocExtractor m_htmlDocExtractor; +}; + +} // namespace TextEditor + +#endif // BASEHOVERHANDLER_H diff --git a/src/plugins/texteditor/texteditor.pro b/src/plugins/texteditor/texteditor.pro index 14314433f46bd2d2a206a0115dbc2285f3fd7a8f..df3e8f380de7c39ee719c7fd9c5bed3877ff9a89 100644 --- a/src/plugins/texteditor/texteditor.pro +++ b/src/plugins/texteditor/texteditor.pro @@ -67,7 +67,8 @@ SOURCES += texteditorplugin.cpp \ outlinefactory.cpp \ tooltip/tooltip.cpp \ tooltip/tips.cpp \ - tooltip/tipcontents.cpp + tooltip/tipcontents.cpp \ + basehoverhandler.cpp HEADERS += texteditorplugin.h \ textfilewizard.h \ @@ -136,7 +137,8 @@ HEADERS += texteditorplugin.h \ ioutlinewidget.h \ tooltip/tooltip.h \ tooltip/tips.h \ - tooltip/tipcontents.h + tooltip/tipcontents.h \ + basehoverhandler.h FORMS += behaviorsettingspage.ui \ displaysettingspage.ui \