forked from qt-creator/qt-creator
Add link support to the output pane
The user can now click on issues to jump into source files and open web pages.
Links have to be wrapped into a html href attribute.
Fixes: QDS-13722
Change-Id: If66f2c61adaad0ab7a9b949912264b583011071e
Reviewed-by: Thomas Hartmann <thomas.hartmann@qt.io>
(cherry picked from commit b2052cf807
)
Reviewed-by: Tim Jenssen <tim.jenssen@qt.io>
This commit is contained in:
committed by
Thomas Hartmann
parent
b156abad0d
commit
c77f8ea08f
@@ -77,6 +77,12 @@ ScrollView {
|
|||||||
hoverEnabled: true
|
hoverEnabled: true
|
||||||
cursorShape: mouseArea.containsMouse ? Qt.PointingHandCursor
|
cursorShape: mouseArea.containsMouse ? Qt.PointingHandCursor
|
||||||
: Qt.ArrowCursor
|
: Qt.ArrowCursor
|
||||||
|
Connections {
|
||||||
|
target: mouseArea
|
||||||
|
function onClicked() {
|
||||||
|
messageModel.jumpToCode(index)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -84,11 +90,26 @@ ScrollView {
|
|||||||
id: labelInfo
|
id: labelInfo
|
||||||
color: (type == "Warning") ? StudioTheme.Values.themeAmberLight
|
color: (type == "Warning") ? StudioTheme.Values.themeAmberLight
|
||||||
: StudioTheme.Values.themeRedLight
|
: StudioTheme.Values.themeRedLight
|
||||||
|
|
||||||
|
linkColor: StudioTheme.Values.themeInteraction
|
||||||
text: message
|
text: message
|
||||||
font.pixelSize: StudioTheme.Values.baseFontSize
|
font.pixelSize: StudioTheme.Values.baseFontSize
|
||||||
verticalAlignment: Text.AlignTop
|
verticalAlignment: Text.AlignTop
|
||||||
wrapMode: Text.WordWrap
|
wrapMode: Text.WordWrap
|
||||||
width: row.width - labelIcon.width - labelLocation.width - row.spacing * 2
|
width: row.width - labelIcon.width - labelLocation.width - row.spacing * 2
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
anchors.fill: parent
|
||||||
|
acceptedButtons: Qt.NoButton
|
||||||
|
cursorShape: labelInfo.hoveredLink === "" ? Qt.ArrowCursor : Qt.PointingHandCursor
|
||||||
|
}
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
target: labelInfo
|
||||||
|
function onLinkActivated(link) {
|
||||||
|
messageModel.openLink(link)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -511,6 +511,11 @@ const AbstractView *ViewManager::view() const
|
|||||||
return &d->nodeInstanceView;
|
return &d->nodeInstanceView;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TextEditorView *ViewManager::textEditorView()
|
||||||
|
{
|
||||||
|
return &d->textEditorView;
|
||||||
|
}
|
||||||
|
|
||||||
void ViewManager::emitCustomNotification(const QString &identifier, const QList<ModelNode> &nodeList,
|
void ViewManager::emitCustomNotification(const QString &identifier, const QList<ModelNode> &nodeList,
|
||||||
const QList<QVariant> &data)
|
const QList<QVariant> &data)
|
||||||
{
|
{
|
||||||
|
@@ -25,6 +25,7 @@ class DesignerActionManager;
|
|||||||
class NodeInstanceView;
|
class NodeInstanceView;
|
||||||
class RewriterView;
|
class RewriterView;
|
||||||
class Edit3DView;
|
class Edit3DView;
|
||||||
|
class TextEditorView;
|
||||||
|
|
||||||
namespace Internal { class DesignModeWidget; }
|
namespace Internal { class DesignModeWidget; }
|
||||||
|
|
||||||
@@ -71,6 +72,8 @@ public:
|
|||||||
void nextFileIsCalledInternally();
|
void nextFileIsCalledInternally();
|
||||||
|
|
||||||
const AbstractView *view() const;
|
const AbstractView *view() const;
|
||||||
|
TextEditorView *textEditorView();
|
||||||
|
|
||||||
void emitCustomNotification(const QString &identifier, const QList<ModelNode> &nodeList,
|
void emitCustomNotification(const QString &identifier, const QList<ModelNode> &nodeList,
|
||||||
const QList<QVariant> &data);
|
const QList<QVariant> &data);
|
||||||
|
|
||||||
|
@@ -168,6 +168,11 @@ void TextEditorView::qmlJSEditorContextHelp(const Core::IContext::HelpCallback &
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TextEditor::BaseTextEditor *TextEditorView::textEditor()
|
||||||
|
{
|
||||||
|
return m_widget->textEditor();
|
||||||
|
}
|
||||||
|
|
||||||
void TextEditorView::nodeIdChanged(const ModelNode& /*node*/, const QString &/*newId*/, const QString &/*oldId*/)
|
void TextEditorView::nodeIdChanged(const ModelNode& /*node*/, const QString &/*newId*/, const QString &/*oldId*/)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@@ -4,6 +4,11 @@
|
|||||||
|
|
||||||
#include <coreplugin/actionmanager/actionmanager.h>
|
#include <coreplugin/actionmanager/actionmanager.h>
|
||||||
#include <coreplugin/editormanager/editormanager.h>
|
#include <coreplugin/editormanager/editormanager.h>
|
||||||
|
#include <qmldesignerplugin.h>
|
||||||
|
#include <texteditor/texteditorview.h>
|
||||||
|
|
||||||
|
#include <QDesktopServices>
|
||||||
|
#include <QWindow>
|
||||||
|
|
||||||
MessageModel::MessageModel(QObject *parent)
|
MessageModel::MessageModel(QObject *parent)
|
||||||
: QAbstractListModel(parent)
|
: QAbstractListModel(parent)
|
||||||
@@ -47,20 +52,31 @@ void MessageModel::jumpToCode(const QVariant &index)
|
|||||||
bool ok = false;
|
bool ok = false;
|
||||||
if (int idx = index.toInt(&ok); ok) {
|
if (int idx = index.toInt(&ok); ok) {
|
||||||
if (idx >= 0 && std::cmp_less(idx, m_tasks.size())) {
|
if (idx >= 0 && std::cmp_less(idx, m_tasks.size())) {
|
||||||
// TODO:
|
ProjectExplorer::Task task = m_tasks.at(static_cast<size_t>(idx));
|
||||||
// - Check why this does not jump to line/column
|
|
||||||
// - Only call this when sure that the task, file row etc are valid.
|
|
||||||
ProjectExplorer::Task task = m_tasks.at(idx);
|
|
||||||
const int column = task.column ? task.column - 1 : 0;
|
const int column = task.column ? task.column - 1 : 0;
|
||||||
|
|
||||||
Utils::Link link(task.file, task.line, column);
|
if (Core::EditorManager::openEditor(task.file,
|
||||||
Core::EditorManager::openEditorAt(link,
|
Utils::Id(),
|
||||||
{},
|
Core::EditorManager::DoNotMakeVisible)) {
|
||||||
Core::EditorManager::SwitchSplitIfAlreadyVisible);
|
|
||||||
|
auto &viewManager = QmlDesigner::QmlDesignerPlugin::instance()->viewManager();
|
||||||
|
if (auto *editorView = viewManager.textEditorView()) {
|
||||||
|
if (TextEditor::BaseTextEditor *editor = editorView->textEditor()) {
|
||||||
|
editor->gotoLine(task.line, column);
|
||||||
|
editor->widget()->setFocus();
|
||||||
|
editor->editorWidget()->updateFoldingHighlight(QTextCursor());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MessageModel::openLink(const QVariant &url)
|
||||||
|
{
|
||||||
|
QDesktopServices::openUrl(QUrl::fromUserInput(url.toString()));
|
||||||
|
}
|
||||||
|
|
||||||
int MessageModel::rowCount(const QModelIndex &) const
|
int MessageModel::rowCount(const QModelIndex &) const
|
||||||
{
|
{
|
||||||
return static_cast<int>(m_tasks.size());
|
return static_cast<int>(m_tasks.size());
|
||||||
@@ -78,7 +94,7 @@ QHash<int, QByteArray> MessageModel::roleNames() const
|
|||||||
QVariant MessageModel::data(const QModelIndex &index, int role) const
|
QVariant MessageModel::data(const QModelIndex &index, int role) const
|
||||||
{
|
{
|
||||||
if (index.isValid() && index.row() < rowCount()) {
|
if (index.isValid() && index.row() < rowCount()) {
|
||||||
int row = index.row();
|
size_t row = static_cast<size_t>(index.row());
|
||||||
if (role == MessageRole) {
|
if (role == MessageRole) {
|
||||||
return m_tasks.at(row).description();
|
return m_tasks.at(row).description();
|
||||||
} else if (role == FileNameRole) {
|
} else if (role == FileNameRole) {
|
||||||
@@ -140,7 +156,7 @@ void MessageModel::removeTask(const ProjectExplorer::Task &task)
|
|||||||
void MessageModel::clearTasks(const Utils::Id &categoryId)
|
void MessageModel::clearTasks(const Utils::Id &categoryId)
|
||||||
{
|
{
|
||||||
beginResetModel();
|
beginResetModel();
|
||||||
std::erase_if(m_tasks, [categoryId](const ProjectExplorer::Task& task) {
|
std::erase_if(m_tasks, [categoryId](const ProjectExplorer::Task &task) {
|
||||||
return task.category == categoryId;
|
return task.category == categoryId;
|
||||||
});
|
});
|
||||||
endResetModel();
|
endResetModel();
|
||||||
|
@@ -34,6 +34,7 @@ public:
|
|||||||
int warningCount() const;
|
int warningCount() const;
|
||||||
Q_INVOKABLE void resetModel();
|
Q_INVOKABLE void resetModel();
|
||||||
Q_INVOKABLE void jumpToCode(const QVariant &index);
|
Q_INVOKABLE void jumpToCode(const QVariant &index);
|
||||||
|
Q_INVOKABLE void openLink(const QVariant &url);
|
||||||
|
|
||||||
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
|
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
|
||||||
QHash<int, QByteArray> roleNames() const override;
|
QHash<int, QByteArray> roleNames() const override;
|
||||||
|
Reference in New Issue
Block a user