summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/libs/utils/htmldocextractor.cpp2
-rw-r--r--src/plugins/cppeditor/cppeditor.qrc2
-rw-r--r--src/plugins/cppeditor/cpphoverhandler.cpp220
-rw-r--r--src/plugins/cppeditor/cpphoverhandler.h16
-rw-r--r--src/plugins/cppeditor/images/larrow.pngbin0 -> 455 bytes
-rw-r--r--src/plugins/cppeditor/images/rightarrow.pngbin0 -> 449 bytes
6 files changed, 205 insertions, 35 deletions
diff --git a/src/libs/utils/htmldocextractor.cpp b/src/libs/utils/htmldocextractor.cpp
index 2edb4c8385..90d2ee6e0f 100644
--- a/src/libs/utils/htmldocextractor.cpp
+++ b/src/libs/utils/htmldocextractor.cpp
@@ -96,7 +96,7 @@ QString HtmlDocExtractor::getClassOrNamespaceDescription(const QString &html,
contents = findByPattern(html, pattern);
}
if (!contents.isEmpty())
- contents.replace(QLatin1String("<h2>Detailed Description</h2>"), name);
+ contents.remove(QLatin1String("Detailed Description"));
formatContents(&contents);
return contents;
diff --git a/src/plugins/cppeditor/cppeditor.qrc b/src/plugins/cppeditor/cppeditor.qrc
index 61cf4a08a6..0df4508753 100644
--- a/src/plugins/cppeditor/cppeditor.qrc
+++ b/src/plugins/cppeditor/cppeditor.qrc
@@ -5,5 +5,7 @@
<file>CppEditor.mimetypes.xml</file>
<file>images/qt_c.png</file>
<file>images/f1.png</file>
+ <file>images/larrow.png</file>
+ <file>images/rightarrow.png</file>
</qresource>
</RCC>
diff --git a/src/plugins/cppeditor/cpphoverhandler.cpp b/src/plugins/cppeditor/cpphoverhandler.cpp
index 61d3f7a3f7..2b4f7a3cdc 100644
--- a/src/plugins/cppeditor/cpphoverhandler.cpp
+++ b/src/plugins/cppeditor/cpphoverhandler.cpp
@@ -40,7 +40,6 @@
#include <texteditor/basetexteditor.h>
#include <texteditor/displaysettings.h>
#include <debugger/debuggerconstants.h>
-#include <utils/htmldocextractor.h>
#include <FullySpecifiedType.h>
#include <Scope.h>
@@ -54,6 +53,8 @@
#include <QtCore/QDir>
#include <QtCore/QFileInfo>
+#include <QtCore/QtAlgorithms>
+#include <QtCore/QStringBuilder>
#include <QtGui/QToolTip>
#include <QtGui/QTextCursor>
@@ -81,6 +82,42 @@ namespace {
ch = doc->characterAt(tc->position());
}
}
+
+ void buildClassHierarchyHelper(Symbol *symbol,
+ const LookupContext &context,
+ const Overview &overview,
+ QList<QStringList> *hierarchy) {
+ if (ClassOrNamespace *classSymbol = context.lookupType(symbol)) {
+ const QList<ClassOrNamespace *> &bases = classSymbol->usings();
+ foreach (ClassOrNamespace *baseClass, bases) {
+ const QList<Symbol *> &symbols = baseClass->symbols();
+ foreach (Symbol *baseSymbol, symbols) {
+ if (baseSymbol->isClass()) {
+ hierarchy->back().append(overview.prettyName(baseSymbol->name()));
+ buildClassHierarchyHelper(baseSymbol, context, overview, hierarchy);
+ hierarchy->append(hierarchy->back());
+ hierarchy->back().removeLast();
+ }
+ }
+ }
+ }
+ }
+
+ void buildClassHierarchy(Symbol *symbol,
+ const LookupContext &context,
+ const Overview &overview,
+ QList<QStringList> *hierarchy) {
+ if (hierarchy->isEmpty())
+ hierarchy->append(QStringList());
+ buildClassHierarchyHelper(symbol, context, overview, hierarchy);
+ hierarchy->removeLast();
+ }
+
+ struct ClassHierarchyComp
+ {
+ bool operator()(const QStringList &a, const QStringList &b)
+ { return a.size() < b.size(); }
+ };
}
CppHoverHandler::CppHoverHandler(QObject *parent)
@@ -127,7 +164,8 @@ void CppHoverHandler::updateContextHelpId(TextEditor::ITextEditor *editor, int p
void CppHoverHandler::showToolTip(TextEditor::ITextEditor *editor, const QPoint &point, int pos)
{
- if (!editor)
+ TextEditor::BaseTextEditor *baseEditor = baseTextEditor(editor);
+ if (!baseEditor)
return;
editor->setContextHelpId(QString());
@@ -143,24 +181,13 @@ void CppHoverHandler::showToolTip(TextEditor::ITextEditor *editor, const QPoint
if (m_toolTip.isEmpty()) {
QToolTip::hideText();
} else {
- if (m_matchingHelpCandidate != -1) {
- QString contents;
- TextEditor::BaseTextEditor *baseEditor = baseTextEditor(editor);
- if (baseEditor && baseEditor->displaySettings().m_integrateDocsIntoTooltips)
- contents = getDocContents();
- if (!contents.isEmpty()) {
- m_toolTip = contents;
- } else {
- m_toolTip = Qt::escape(m_toolTip);
- m_toolTip.prepend(QLatin1String("<nobr>"));
- m_toolTip.append(QLatin1String("</nobr>"));
- }
+ if (!m_classHierarchy.isEmpty())
+ generateDiagramTooltip(baseEditor->displaySettings().m_integrateDocsIntoTooltips);
+ else
+ generateNormalTooltip(baseEditor->displaySettings().m_integrateDocsIntoTooltips);
- m_toolTip = QString(QLatin1String("<table><tr>"
- "<td valign=middle>%1</td>"
- "<td><img src=\":/cppeditor/images/f1.png\"></td>"
- "</tr></table>")).arg(m_toolTip);
- }
+ if (m_matchingHelpCandidate != -1)
+ addF1ToTooltip();
const QPoint pnt = point - QPoint(0,
#ifdef Q_WS_WIN
@@ -220,7 +247,7 @@ void CppHoverHandler::identifyMatch(TextEditor::ITextEditor *editor, int pos)
return;
const LookupItem &lookupItem = lookupItems.first(); // ### TODO: select the best candidate.
- handleLookupItemMatch(lookupItem, !extraSelectionTooltip);
+ handleLookupItemMatch(lookupItem, typeOfExpression.context(), !extraSelectionTooltip);
}
evaluateHelpCandidates();
@@ -244,7 +271,7 @@ bool CppHoverHandler::matchIncludeFile(const CPlusPlus::Document::Ptr &document,
if (includeFile.line() == line) {
m_toolTip = QDir::toNativeSeparators(includeFile.fileName());
const QString &fileName = QFileInfo(includeFile.fileName()).fileName();
- m_helpCandidates.append(HelpCandidate(fileName, fileName, HelpCandidate::Include));
+ m_helpCandidates.append(HelpCandidate(fileName, fileName, HelpCandidate::Brief));
return true;
}
}
@@ -267,7 +294,9 @@ bool CppHoverHandler::matchMacroInUse(const CPlusPlus::Document::Ptr &document,
return false;
}
-void CppHoverHandler::handleLookupItemMatch(const LookupItem &lookupItem, const bool assignTooltip)
+void CppHoverHandler::handleLookupItemMatch(const LookupItem &lookupItem,
+ const LookupContext &context,
+ const bool assignTooltip)
{
Symbol *matchingDeclaration = lookupItem.declaration();
FullySpecifiedType matchingType = lookupItem.type();
@@ -286,6 +315,11 @@ void CppHoverHandler::handleLookupItemMatch(const LookupItem &lookupItem, const
matchingDeclaration->enclosingSymbol()->isEnum()) {
qualifiedName.append(overview.prettyName(
LookupContext::fullyQualifiedName(matchingDeclaration)));
+
+ if (matchingDeclaration->isClass() ||
+ matchingDeclaration->isForwardClassDeclaration()) {
+ buildClassHierarchy(matchingDeclaration, context, overview, &m_classHierarchy);
+ }
} else {
qualifiedName.append(overview.prettyName(matchingDeclaration->name()));
}
@@ -310,15 +344,15 @@ void CppHoverHandler::handleLookupItemMatch(const LookupItem &lookupItem, const
helpCategory = HelpCandidate::Enum;
} else if (matchingDeclaration->isTypedef()) {
helpCategory = HelpCandidate::Typedef;
- } else if (matchingDeclaration->isStatic() && !matchingDeclaration->isFunction()) {
+ } else if (matchingDeclaration->isStatic() &&
+ !matchingDeclaration->type()->isFunctionType()) {
helpCategory = HelpCandidate::Var;
} else {
helpCategory = HelpCandidate::Function;
}
// Help identifiers are simply the name with no signature, arguments or return type.
- // They might or might not include a qualification. This is why two candidates are
- // created.
+ // They might or might not include a qualification. This is why two candidates are created.
overview.setShowArgumentNames(false);
overview.setShowReturnTypes(false);
overview.setShowFunctionSignatures(false);
@@ -350,12 +384,16 @@ bool CppHoverHandler::helpIdExists(const QString &helpId) const
return false;
}
-QString CppHoverHandler::getDocContents()
+QString CppHoverHandler::getDocContents() const
{
Q_ASSERT(m_matchingHelpCandidate >= 0);
+ return getDocContents(m_helpCandidates.at(m_matchingHelpCandidate));
+}
+
+QString CppHoverHandler::getDocContents(const HelpCandidate &help) const
+{
QString contents;
- const HelpCandidate &help = m_helpCandidates.at(m_matchingHelpCandidate);
QMap<QString, QUrl> helpLinks =
Core::HelpManager::instance()->linksForIdentifier(help.m_helpId);
foreach (const QUrl &url, helpLinks) {
@@ -363,15 +401,14 @@ QString CppHoverHandler::getDocContents()
const QString &name = removeQualificationIfAny(help.m_helpId);
const QByteArray &html = Core::HelpManager::instance()->fileData(url);
switch (help.m_category) {
- case HelpCandidate::Include:
+ case HelpCandidate::Brief:
contents = m_htmlDocExtractor.getClassOrNamespaceBrief(html, name);
break;
case HelpCandidate::ClassOrNamespace:
contents = m_htmlDocExtractor.getClassOrNamespaceDescription(html, name);
break;
case HelpCandidate::Function:
- contents =
- m_htmlDocExtractor.getFunctionDescription(html, help.m_markId, name);
+ contents = m_htmlDocExtractor.getFunctionDescription(html, help.m_markId, name);
break;
case HelpCandidate::Enum:
contents = m_htmlDocExtractor.getEnumDescription(html, name);
@@ -395,14 +432,137 @@ QString CppHoverHandler::getDocContents()
return contents;
}
+void CppHoverHandler::generateDiagramTooltip(const bool integrateDocs)
+{
+ QString clazz = m_toolTip;
+
+ qSort(m_classHierarchy.begin(), m_classHierarchy.end(), ClassHierarchyComp());
+
+ QStringList directBaseClasses;
+ foreach (const QStringList &hierarchy, m_classHierarchy) {
+ if (hierarchy.size() > 1)
+ break;
+ directBaseClasses.append(hierarchy.at(0));
+ }
+
+ QString diagram(QLatin1String("<table>"));
+ for (int i = 0; i < directBaseClasses.size(); ++i) {
+ if (i == 0) {
+ 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)));
+ } else {
+ diagram.append(QString(
+ "<tr><td></td><td>"
+ "<img src=\":/cppeditor/images/larrow.png\"></td>"
+ "<td>%1</td></tr>").arg(directBaseClasses.at(i)));
+ }
+ }
+ diagram.append(QLatin1String("</table>"));
+ m_toolTip = diagram;
+
+ if (integrateDocs) {
+ if (m_matchingHelpCandidate != -1) {
+ m_toolTip.append(getDocContents());
+ } else {
+ // Look for documented base classes. Diagram the nearest one or the nearest ones (in
+ // the case there are many at the same level).
+ int helpLevel = 0;
+ QList<int> baseClassesWithHelp;
+ for (int i = 0; i < m_classHierarchy.size(); ++i) {
+ const QStringList &hierarchy = m_classHierarchy.at(i);
+ if (helpLevel != 0 && hierarchy.size() != helpLevel)
+ break;
+
+ const QString &name = hierarchy.last();
+ if (helpIdExists(name)) {
+ baseClassesWithHelp.append(i);
+ if (helpLevel == 0)
+ helpLevel = hierarchy.size();
+ }
+ }
+
+ if (!baseClassesWithHelp.isEmpty()) {
+ // 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;
+
+ if (baseClassesWithHelp.size() == 1 && helpLevel == 1) {
+ m_toolTip.append(getDocContents(help));
+ } else {
+ foreach (int hierarchyIndex, baseClassesWithHelp) {
+ m_toolTip.append(QLatin1String("<p>"));
+ const QStringList &hierarchy = m_classHierarchy.at(hierarchyIndex);
+ Q_ASSERT(helpLevel <= hierarchy.size());
+
+ // Following contents are inside tables so they are on the exact same
+ // alignment as the top level diagram.
+ diagram = QString(QLatin1String("<table><tr><td>%1</td>")).arg(clazz);
+ for (int i = 0; i < helpLevel; ++i) {
+ diagram.append(
+ QLatin1String("<td><img src=\":/cppeditor/images/rightarrow.png\">"
+ "</td><td>") %
+ hierarchy.at(i) %
+ QLatin1String("</td>"));
+ }
+ diagram.append(QLatin1String("</tr></table>"));
+
+ base = hierarchy.at(helpLevel - 1);
+ QString contents =
+ getDocContents(HelpCandidate(base, base, HelpCandidate::Brief));
+ if (!contents.isEmpty()) {
+ m_toolTip.append(diagram % QLatin1String("<table><tr><td>") %
+ contents % QLatin1String("</td></tr></table>"));
+ }
+ m_toolTip.append(QLatin1String("</p>"));
+ }
+ }
+ }
+ }
+ }
+}
+
+void CppHoverHandler::generateNormalTooltip(const bool integrateDocs)
+{
+ if (m_matchingHelpCandidate != -1) {
+ QString contents;
+ if (integrateDocs)
+ contents = getDocContents();
+ if (!contents.isEmpty()) {
+ HelpCandidate::Category cat = m_helpCandidates.at(m_matchingHelpCandidate).m_category;
+ if (cat == HelpCandidate::ClassOrNamespace)
+ m_toolTip.append(contents);
+ else
+ m_toolTip = contents;
+ } else {
+ m_toolTip = Qt::escape(m_toolTip);
+ m_toolTip.prepend(QLatin1String("<nobr>"));
+ m_toolTip.append(QLatin1String("</nobr>"));
+ }
+ }
+}
+
+void CppHoverHandler::addF1ToTooltip()
+{
+ m_toolTip = QString(QLatin1String("<table><tr><td valign=middle>%1</td><td>&nbsp;&nbsp;"
+ "<img src=\":/cppeditor/images/f1.png\"></td>"
+ "</tr></table>")).arg(m_toolTip);
+}
+
void CppHoverHandler::resetMatchings()
{
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 84c58733d4..59c987d6d5 100644
--- a/src/plugins/cppeditor/cpphoverhandler.h
+++ b/src/plugins/cppeditor/cpphoverhandler.h
@@ -30,12 +30,12 @@
#ifndef CPPHOVERHANDLER_H
#define CPPHOVERHANDLER_H
+#include <cplusplus/CppDocument.h>
#include <utils/htmldocextractor.h>
#include <QtCore/QObject>
#include <QtCore/QList>
-
-#include <cplusplus/CppDocument.h>
+#include <QtCore/QStringList>
QT_BEGIN_NAMESPACE
class QPoint;
@@ -43,6 +43,7 @@ QT_END_NAMESPACE
namespace CPlusPlus {
class LookupItem;
+class LookupContext;
}
namespace Core {
@@ -83,7 +84,7 @@ private:
Typedef,
Var,
Macro,
- Include,
+ Brief,
Function
};
@@ -101,11 +102,17 @@ private:
bool matchIncludeFile(const CPlusPlus::Document::Ptr &document, unsigned line);
bool matchMacroInUse(const CPlusPlus::Document::Ptr &document, unsigned pos);
void handleLookupItemMatch(const CPlusPlus::LookupItem &lookupItem,
+ const CPlusPlus::LookupContext &lookupContext,
const bool assignTooltip);
void evaluateHelpCandidates();
bool helpIdExists(const QString &helpId) const;
- QString getDocContents();
+ QString getDocContents() const;
+ QString getDocContents(const HelpCandidate &helpCandidate) const;
+
+ void generateDiagramTooltip(const bool integrateDocs);
+ void generateNormalTooltip(const bool integrateDocs);
+ void addF1ToTooltip();
static TextEditor::BaseTextEditor *baseTextEditor(TextEditor::ITextEditor *editor);
@@ -113,6 +120,7 @@ private:
int m_matchingHelpCandidate;
QList<HelpCandidate> m_helpCandidates;
QString m_toolTip;
+ QList<QStringList> m_classHierarchy;
Utils::HtmlDocExtractor m_htmlDocExtractor;
};
diff --git a/src/plugins/cppeditor/images/larrow.png b/src/plugins/cppeditor/images/larrow.png
new file mode 100644
index 0000000000..0268658304
--- /dev/null
+++ b/src/plugins/cppeditor/images/larrow.png
Binary files differ
diff --git a/src/plugins/cppeditor/images/rightarrow.png b/src/plugins/cppeditor/images/rightarrow.png
new file mode 100644
index 0000000000..26b153d2aa
--- /dev/null
+++ b/src/plugins/cppeditor/images/rightarrow.png
Binary files differ