summaryrefslogtreecommitdiff
path: root/src/plugins/cppeditor
diff options
context:
space:
mode:
authorMarc Reilly <marc@cpdesign.com.au>2016-08-10 20:18:48 +1000
committerMarc Reilly <marc.reilly@gmail.com>2016-08-11 07:43:42 +0000
commit4bbd9dc0dc15e0378f040aae971a52ac33486351 (patch)
tree5e046b046726ff5d0ffc21eb2c04e440a5ef4683 /src/plugins/cppeditor
parent5652aef54a61c30efef93d781ab712fdf825982a (diff)
downloadqt-creator-4bbd9dc0dc15e0378f040aae971a52ac33486351.tar.gz
cppeditor: add resource preview hover handler class
This adds a hover handler which will preview images from within project resource. Change-Id: I88bcb56a977e41ed4dc5bfe165e2c80d4396a21f Reviewed-by: André Hartmann <aha_1980@gmx.de> Reviewed-by: David Schulz <david.schulz@qt.io> Reviewed-by: Orgad Shaneh <orgads@gmail.com>
Diffstat (limited to 'src/plugins/cppeditor')
-rw-r--r--src/plugins/cppeditor/cppeditor.pro6
-rw-r--r--src/plugins/cppeditor/cppeditor.qbs1
-rw-r--r--src/plugins/cppeditor/cppeditorplugin.cpp2
-rw-r--r--src/plugins/cppeditor/resourcepreviewhoverhandler.cpp209
-rw-r--r--src/plugins/cppeditor/resourcepreviewhoverhandler.h50
5 files changed, 266 insertions, 2 deletions
diff --git a/src/plugins/cppeditor/cppeditor.pro b/src/plugins/cppeditor/cppeditor.pro
index 6394bba5bb..ae3129617a 100644
--- a/src/plugins/cppeditor/cppeditor.pro
+++ b/src/plugins/cppeditor/cppeditor.pro
@@ -29,7 +29,8 @@ HEADERS += \
cpptypehierarchy.h \
cppuseselectionsupdater.h \
cppvirtualfunctionassistprovider.h \
- cppvirtualfunctionproposalitem.h
+ cppvirtualfunctionproposalitem.h \
+ resourcepreviewhoverhandler.h
SOURCES += \
cppautocompleter.cpp \
@@ -56,7 +57,8 @@ SOURCES += \
cpptypehierarchy.cpp \
cppuseselectionsupdater.cpp \
cppvirtualfunctionassistprovider.cpp \
- cppvirtualfunctionproposalitem.cpp
+ cppvirtualfunctionproposalitem.cpp \
+ resourcepreviewhoverhandler.cpp
FORMS += \
cpppreprocessordialog.ui \
diff --git a/src/plugins/cppeditor/cppeditor.qbs b/src/plugins/cppeditor/cppeditor.qbs
index 8267939e14..5f02e689e7 100644
--- a/src/plugins/cppeditor/cppeditor.qbs
+++ b/src/plugins/cppeditor/cppeditor.qbs
@@ -50,6 +50,7 @@ QtcPlugin {
"cppuseselectionsupdater.cpp", "cppuseselectionsupdater.h",
"cppvirtualfunctionassistprovider.cpp", "cppvirtualfunctionassistprovider.h",
"cppvirtualfunctionproposalitem.cpp", "cppvirtualfunctionproposalitem.h",
+ "resoucepreviewhoverhandler.cpp", "resoucepreviewhoverhandler.h",
]
Group {
diff --git a/src/plugins/cppeditor/cppeditorplugin.cpp b/src/plugins/cppeditor/cppeditorplugin.cpp
index 46b5f4cb26..39b4fc0f2e 100644
--- a/src/plugins/cppeditor/cppeditorplugin.cpp
+++ b/src/plugins/cppeditor/cppeditorplugin.cpp
@@ -38,6 +38,7 @@
#include "cppquickfixes.h"
#include "cppsnippetprovider.h"
#include "cpptypehierarchy.h"
+#include "resourcepreviewhoverhandler.h"
#include <coreplugin/editormanager/editormanager.h>
@@ -106,6 +107,7 @@ public:
addHoverHandler(new CppHoverHandler);
addHoverHandler(new ColorPreviewHoverHandler);
+ addHoverHandler(new ResourcePreviewHoverHandler);
}
};
diff --git a/src/plugins/cppeditor/resourcepreviewhoverhandler.cpp b/src/plugins/cppeditor/resourcepreviewhoverhandler.cpp
new file mode 100644
index 0000000000..fdb41c40f7
--- /dev/null
+++ b/src/plugins/cppeditor/resourcepreviewhoverhandler.cpp
@@ -0,0 +1,209 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 Marc Reilly <marc.reilly+qtc@gmail.com>
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+#include "resourcepreviewhoverhandler.h"
+
+#include <coreplugin/icore.h>
+#include <utils/tooltip/tooltip.h>
+#include <utils/fileutils.h>
+#include <utils/qtcassert.h>
+#include <utils/mimetypes/mimedatabase.h>
+#include <projectexplorer/projecttree.h>
+#include <projectexplorer/project.h>
+#include <texteditor/texteditor.h>
+
+#include <QPoint>
+#include <QTextBlock>
+
+using namespace Core;
+using namespace TextEditor;
+
+namespace CppEditor {
+namespace Internal {
+
+/*
+ * finds a quoted sub-string around the pos in the given string
+ *
+ * note: the returned string includes the quotes.
+ */
+static QString extractQuotedString(const QString &s, int pos)
+{
+ if (s.length() < 2 || pos < 0 || pos >= s.length())
+ return QString();
+
+ const int firstQuote = s.lastIndexOf('"', pos);
+ if (firstQuote >= 0) {
+ int endQuote = s.indexOf('"', firstQuote + 1);
+ if (endQuote > firstQuote)
+ return s.mid(firstQuote, endQuote - firstQuote);
+ }
+
+ return QString();
+}
+
+static QString makeResourcePath(const QStringList &prefixList, const QString &file)
+{
+ QTC_ASSERT(!prefixList.isEmpty(), return QString());
+
+ const QChar sep = '/';
+ auto prefix = prefixList.join(sep);
+ if (prefix == sep)
+ return prefix + file;
+
+ return prefix + sep + file;
+}
+
+/*
+ * tries to match a resource within a given .qrc file, including by alias
+ *
+ * note: resource name should not have any semi-colon in front of it
+ */
+static QString findResourceInFile(const QString &resName, const QString &filePathName)
+{
+ Utils::FileReader reader;
+ if (!reader.fetch(filePathName))
+ return QString();
+
+ const QByteArray contents = reader.data();
+ QXmlStreamReader xmlr(contents);
+
+ QStringList prefixStack;
+
+ while (!xmlr.atEnd() && !xmlr.hasError()) {
+ const QXmlStreamReader::TokenType token = xmlr.readNext();
+ if (token == QXmlStreamReader::StartElement) {
+ if (xmlr.name() == "qresource") {
+ const QXmlStreamAttributes sa = xmlr.attributes();
+ const QString prefixName = sa.value("prefix").toString();
+ if (!prefixName.isEmpty())
+ prefixStack.push_back(prefixName);
+ } else if (xmlr.name() == "file") {
+ const QXmlStreamAttributes sa = xmlr.attributes();
+ const QString aliasName = sa.value("alias").toString();
+ const QString fileName = xmlr.readElementText();
+
+ if (!aliasName.isEmpty()) {
+ const QString fullAliasName = makeResourcePath(prefixStack, aliasName);
+ if (resName == fullAliasName)
+ return fileName;
+ }
+
+ const QString fullResName = makeResourcePath(prefixStack, fileName);
+ if (resName == fullResName)
+ return fileName;
+ }
+ } else if (token == QXmlStreamReader::EndElement) {
+ if (xmlr.name() == "qresource") {
+ if (!prefixStack.isEmpty())
+ prefixStack.pop_back();
+ }
+ }
+ }
+
+ return QString();
+}
+
+/*
+ * A more efficient way to do this would be to parse the relevant project files
+ * before hand, or cache them as we go - but this works well enough so far.
+ */
+static QString findResourceInProject(const QString &resName)
+{
+ QString s = resName;
+ s.remove('"');
+
+ if (s.startsWith(":/"))
+ s.remove(0, 1);
+ else if (s.startsWith("qrc://"))
+ s.remove(0, 5);
+ else
+ return QString();
+
+ if (auto *project = ProjectExplorer::ProjectTree::currentProject()) {
+ const QStringList files = project->files(ProjectExplorer::Project::AllFiles);
+ for (const QString &file : files) {
+ if (!file.endsWith(".qrc"))
+ continue;
+ const QFileInfo fi(file);
+ if (!fi.isReadable())
+ continue;
+ const QString fileName = findResourceInFile(s, file);
+ if (fileName.isEmpty())
+ continue;
+
+ QString ret = fi.absolutePath();
+ if (!ret.endsWith('/'))
+ ret.append('/');
+ ret.append(fileName);
+ return ret;
+ }
+ }
+
+ return QString();
+}
+
+void ResourcePreviewHoverHandler::identifyMatch(TextEditorWidget *editorWidget, int pos)
+{
+ if (editorWidget->extraSelectionTooltip(pos).isEmpty()) {
+ const QTextBlock tb = editorWidget->document()->findBlock(pos);
+ const int tbpos = pos - tb.position();
+ const QString tbtext = tb.text();
+
+ const QString resPath = extractQuotedString(tbtext, tbpos);
+ m_resPath = findResourceInProject(resPath);
+
+ setPriority(m_resPath.isEmpty() ? Priority_None : Priority_Diagnostic + 1);
+ }
+}
+
+void ResourcePreviewHoverHandler::operateTooltip(TextEditorWidget *editorWidget, const QPoint &point)
+{
+ const QString tt = makeTooltip();
+ if (!tt.isEmpty())
+ Utils::ToolTip::show(point, tt, editorWidget);
+ else
+ Utils::ToolTip::hide();
+}
+
+QString ResourcePreviewHoverHandler::makeTooltip() const
+{
+ if (m_resPath.isEmpty())
+ return QString();
+
+ QString ret;
+
+ Utils::MimeDatabase mdb;
+ const Utils::MimeType mimeType = mdb.mimeTypeForFile(m_resPath);
+ if (mimeType.isValid()) {
+ if (mimeType.name().startsWith("image", Qt::CaseInsensitive))
+ ret += QString("<img src=\"file:///%1\" /><br/>").arg(m_resPath);
+
+ ret += QString("<a href=\"file:///%1\">%2</a>").arg(m_resPath).arg(m_resPath);
+ }
+ return ret;
+}
+
+} // namespace Internal
+} // namespace CppEditor
diff --git a/src/plugins/cppeditor/resourcepreviewhoverhandler.h b/src/plugins/cppeditor/resourcepreviewhoverhandler.h
new file mode 100644
index 0000000000..7f10db83d8
--- /dev/null
+++ b/src/plugins/cppeditor/resourcepreviewhoverhandler.h
@@ -0,0 +1,50 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 Marc Reilly <marc.reilly+qtc@gmail.com>
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+#pragma once
+
+#include <texteditor/basehoverhandler.h>
+
+#include <QString>
+
+namespace CppEditor {
+namespace Internal {
+
+class ResourcePreviewHoverHandler : public TextEditor::BaseHoverHandler
+{
+public:
+
+private:
+ void identifyMatch(TextEditor::TextEditorWidget *editorWidget, int pos) override;
+ void operateTooltip(TextEditor::TextEditorWidget *editorWidget, const QPoint &point) override;
+
+private:
+ QString makeTooltip() const;
+
+ QString m_resPath;
+};
+
+} // namespace Internal
+} // namespace CppEditor