forked from qt-creator/qt-creator
DiagnosticView: Add copy action to context menu
Task-number: QCE-22 Change-Id: I22a71bd99689e4eaece3b2595b28e0d434a52453 Reviewed-by: Riitta-Leena Miettinen <riitta-leena.miettinen@digia.com> Reviewed-by: Nikolai Kosjar <nikolai.kosjar@theqtcompany.com>
This commit is contained in:
@@ -21,12 +21,19 @@
|
|||||||
#include "clangstaticanalyzerlogfilereader.h"
|
#include "clangstaticanalyzerlogfilereader.h"
|
||||||
#include "clangstaticanalyzerutils.h"
|
#include "clangstaticanalyzerutils.h"
|
||||||
|
|
||||||
|
#include <coreplugin/coreconstants.h>
|
||||||
|
|
||||||
#include <utils/qtcassert.h>
|
#include <utils/qtcassert.h>
|
||||||
|
|
||||||
|
#include <QAction>
|
||||||
|
#include <QApplication>
|
||||||
|
#include <QClipboard>
|
||||||
|
#include <QContextMenuEvent>
|
||||||
#include <QCoreApplication>
|
#include <QCoreApplication>
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
#include <QFileInfo>
|
#include <QFileInfo>
|
||||||
#include <QLabel>
|
#include <QLabel>
|
||||||
|
#include <QMenu>
|
||||||
#include <QVBoxLayout>
|
#include <QVBoxLayout>
|
||||||
|
|
||||||
using namespace Analyzer;
|
using namespace Analyzer;
|
||||||
@@ -90,29 +97,32 @@ QLabel *createExplainingStepLabel(const QFont &font, bool useAlternateRowPalette
|
|||||||
}
|
}
|
||||||
|
|
||||||
QString createLocationString(const ClangStaticAnalyzer::Internal::Location &location,
|
QString createLocationString(const ClangStaticAnalyzer::Internal::Location &location,
|
||||||
bool withMarkup)
|
bool withMarkup, bool withAbsolutePath)
|
||||||
{
|
{
|
||||||
const QString filePath = location.filePath;
|
const QString filePath = location.filePath;
|
||||||
const QString fileName = QFileInfo(filePath).fileName();
|
|
||||||
const QString lineNumber = QString::number(location.line);
|
const QString lineNumber = QString::number(location.line);
|
||||||
const QString columnNumber = QString::number(location.column - 1);
|
const QString columnNumber = QString::number(location.column - 1);
|
||||||
const QString fileNameAndLine = fileName + QLatin1Char(':') + lineNumber;
|
const QString fileAndLine = (withAbsolutePath ? filePath : QFileInfo(filePath).fileName())
|
||||||
|
+ QLatin1Char(':') + lineNumber;
|
||||||
|
|
||||||
if (withMarkup) {
|
if (withMarkup) {
|
||||||
return QLatin1String("in <a href=\"file://")
|
return QLatin1String("in <a href=\"file://")
|
||||||
+ filePath + QLatin1Char(':') + lineNumber + QLatin1Char(':') + columnNumber
|
+ filePath + QLatin1Char(':') + lineNumber + QLatin1Char(':') + columnNumber
|
||||||
+ QLatin1String("\">")
|
+ QLatin1String("\">")
|
||||||
+ fileNameAndLine
|
+ fileAndLine
|
||||||
+ QLatin1String("</a>");
|
+ QLatin1String("</a>");
|
||||||
} else {
|
} else {
|
||||||
return QLatin1String("in ") + fileNameAndLine;
|
return QLatin1String("in ") + fileAndLine;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QString createExplainingStepNumberString(int number)
|
QString createExplainingStepNumberString(int number, bool withMarkup)
|
||||||
{
|
{
|
||||||
const int fieldWidth = 2;
|
const int fieldWidth = 2;
|
||||||
return QString::fromLatin1("<code style='white-space:pre'>%1:</code>").arg(number, fieldWidth);
|
const QString result = QString::fromLatin1("%1:").arg(number, fieldWidth);
|
||||||
|
return withMarkup
|
||||||
|
? QLatin1String("<code style='white-space:pre'>") + result + QLatin1String("</code>")
|
||||||
|
: result;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString createExplainingStepToolTipString(const ClangStaticAnalyzer::Internal::ExplainingStep &step)
|
QString createExplainingStepToolTipString(const ClangStaticAnalyzer::Internal::ExplainingStep &step)
|
||||||
@@ -154,6 +164,17 @@ QString createExplainingStepToolTipString(const ClangStaticAnalyzer::Internal::E
|
|||||||
return html;
|
return html;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString createExplainingStepString(
|
||||||
|
const ClangStaticAnalyzer::Internal::ExplainingStep &explainingStep,
|
||||||
|
int number, bool withMarkup, bool withAbsolutePath)
|
||||||
|
{
|
||||||
|
return createExplainingStepNumberString(number, withMarkup)
|
||||||
|
+ QLatin1Char(' ')
|
||||||
|
+ explainingStep.extendedMessage
|
||||||
|
+ QLatin1Char(' ')
|
||||||
|
+ createLocationString(explainingStep.location, withMarkup, withAbsolutePath);
|
||||||
|
}
|
||||||
|
|
||||||
} // anonymous namespace
|
} // anonymous namespace
|
||||||
|
|
||||||
namespace ClangStaticAnalyzer {
|
namespace ClangStaticAnalyzer {
|
||||||
@@ -172,13 +193,36 @@ DetailedErrorDelegate::SummaryLineInfo ClangStaticAnalyzerDiagnosticDelegate::su
|
|||||||
|
|
||||||
DetailedErrorDelegate::SummaryLineInfo info;
|
DetailedErrorDelegate::SummaryLineInfo info;
|
||||||
info.errorText = diagnostic.description;
|
info.errorText = diagnostic.description;
|
||||||
info.errorLocation = createLocationString(diagnostic.location, /*withMarkup=*/ false);
|
info.errorLocation = createLocationString(diagnostic.location,
|
||||||
|
/*withMarkup=*/ false,
|
||||||
|
/*withAbsolutePath=*/ false);
|
||||||
return info;
|
return info;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClangStaticAnalyzerDiagnosticDelegate::copy()
|
void ClangStaticAnalyzerDiagnosticDelegate::copy()
|
||||||
{
|
{
|
||||||
qDebug() << Q_FUNC_INFO;
|
QTC_ASSERT(m_detailsIndex.isValid(), return);
|
||||||
|
|
||||||
|
const Diagnostic diagnostic = m_detailsIndex.data(Qt::UserRole).value<Diagnostic>();
|
||||||
|
QTC_ASSERT(diagnostic.isValid(), return);
|
||||||
|
|
||||||
|
// Create summary
|
||||||
|
QString clipboardText = diagnostic.category + QLatin1String(": ") + diagnostic.type;
|
||||||
|
if (diagnostic.type != diagnostic.description)
|
||||||
|
clipboardText += QLatin1String(": ") + diagnostic.description;
|
||||||
|
clipboardText += QLatin1Char('\n');
|
||||||
|
|
||||||
|
// Create explaining steps
|
||||||
|
int explainingStepNumber = 1;
|
||||||
|
foreach (const ExplainingStep &explainingStep, diagnostic.explainingSteps) {
|
||||||
|
clipboardText += createExplainingStepString(explainingStep,
|
||||||
|
explainingStepNumber++,
|
||||||
|
/*withMarkup=*/ false,
|
||||||
|
/*withAbsolutePath=*/ true) + QLatin1Char('\n');
|
||||||
|
}
|
||||||
|
|
||||||
|
clipboardText.chop(1); // Remove \n
|
||||||
|
QApplication::clipboard()->setText(clipboardText);
|
||||||
}
|
}
|
||||||
|
|
||||||
QWidget *ClangStaticAnalyzerDiagnosticDelegate::createDetailsWidget(const QFont &font,
|
QWidget *ClangStaticAnalyzerDiagnosticDelegate::createDetailsWidget(const QFont &font,
|
||||||
@@ -201,12 +245,10 @@ QWidget *ClangStaticAnalyzerDiagnosticDelegate::createDetailsWidget(const QFont
|
|||||||
// Add labels for explaining steps
|
// Add labels for explaining steps
|
||||||
int explainingStepNumber = 1;
|
int explainingStepNumber = 1;
|
||||||
foreach (const ExplainingStep &explainingStep, diagnostic.explainingSteps) {
|
foreach (const ExplainingStep &explainingStep, diagnostic.explainingSteps) {
|
||||||
const QString text = createExplainingStepNumberString(explainingStepNumber++)
|
const QString text = createExplainingStepString(explainingStep,
|
||||||
+ QLatin1Char(' ')
|
explainingStepNumber++,
|
||||||
+ explainingStep.extendedMessage
|
/*withMarkup=*/ true,
|
||||||
+ QLatin1Char(' ')
|
/*withAbsolutePath=*/ false);
|
||||||
+ createLocationString(explainingStep.location, /*withMarkup=*/ true);
|
|
||||||
|
|
||||||
QLabel *label = createExplainingStepLabel(font, explainingStepNumber % 2 == 0);
|
QLabel *label = createExplainingStepLabel(font, explainingStepNumber % 2 == 0);
|
||||||
label->setParent(widget);
|
label->setParent(widget);
|
||||||
label->setText(text);
|
label->setText(text);
|
||||||
@@ -222,5 +264,32 @@ QWidget *ClangStaticAnalyzerDiagnosticDelegate::createDetailsWidget(const QFont
|
|||||||
return widget;
|
return widget;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ClangStaticAnalyzerDiagnosticView::ClangStaticAnalyzerDiagnosticView(QWidget *parent)
|
||||||
|
: Analyzer::DetailedErrorView(parent)
|
||||||
|
{
|
||||||
|
ClangStaticAnalyzerDiagnosticDelegate *delegate
|
||||||
|
= new ClangStaticAnalyzerDiagnosticDelegate(this);
|
||||||
|
setItemDelegate(delegate);
|
||||||
|
|
||||||
|
m_copyAction = new QAction(this);
|
||||||
|
m_copyAction->setText(tr("Copy"));
|
||||||
|
m_copyAction->setIcon(QIcon(QLatin1String(Core::Constants::ICON_COPY)));
|
||||||
|
m_copyAction->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_C));
|
||||||
|
m_copyAction->setShortcutContext(Qt::WidgetWithChildrenShortcut);
|
||||||
|
connect(m_copyAction, &QAction::triggered,
|
||||||
|
delegate, &ClangStaticAnalyzerDiagnosticDelegate::copy);
|
||||||
|
addAction(m_copyAction);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClangStaticAnalyzerDiagnosticView::contextMenuEvent(QContextMenuEvent *e)
|
||||||
|
{
|
||||||
|
if (selectionModel()->selectedRows().isEmpty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
QMenu menu;
|
||||||
|
menu.addAction(m_copyAction);
|
||||||
|
menu.exec(e->globalPos());
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace Internal
|
} // namespace Internal
|
||||||
} // namespace ClangStaticAnalyzer
|
} // namespace ClangStaticAnalyzer
|
||||||
|
@@ -24,6 +24,19 @@
|
|||||||
namespace ClangStaticAnalyzer {
|
namespace ClangStaticAnalyzer {
|
||||||
namespace Internal {
|
namespace Internal {
|
||||||
|
|
||||||
|
class ClangStaticAnalyzerDiagnosticView : public Analyzer::DetailedErrorView
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
ClangStaticAnalyzerDiagnosticView(QWidget *parent = 0);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void contextMenuEvent(QContextMenuEvent *e);
|
||||||
|
|
||||||
|
QAction *m_copyAction;
|
||||||
|
};
|
||||||
|
|
||||||
class ClangStaticAnalyzerDiagnosticDelegate : public Analyzer::DetailedErrorDelegate
|
class ClangStaticAnalyzerDiagnosticDelegate : public Analyzer::DetailedErrorDelegate
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@@ -70,8 +70,7 @@ QWidget *ClangStaticAnalyzerTool::createWidgets()
|
|||||||
//
|
//
|
||||||
// Diagnostic View
|
// Diagnostic View
|
||||||
//
|
//
|
||||||
m_diagnosticView = new DetailedErrorView;
|
m_diagnosticView = new ClangStaticAnalyzerDiagnosticView;
|
||||||
m_diagnosticView->setItemDelegate(new ClangStaticAnalyzerDiagnosticDelegate(m_diagnosticView));
|
|
||||||
m_diagnosticView->setObjectName(QLatin1String("ClangStaticAnalyzerIssuesView"));
|
m_diagnosticView->setObjectName(QLatin1String("ClangStaticAnalyzerIssuesView"));
|
||||||
m_diagnosticView->setFrameStyle(QFrame::NoFrame);
|
m_diagnosticView->setFrameStyle(QFrame::NoFrame);
|
||||||
m_diagnosticView->setAttribute(Qt::WA_MacShowFocusRect, false);
|
m_diagnosticView->setAttribute(Qt::WA_MacShowFocusRect, false);
|
||||||
|
Reference in New Issue
Block a user