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:
Nikolai Kosjar
2014-11-14 13:39:59 +01:00
parent 802a7d653c
commit 30b77eb032
3 changed files with 98 additions and 17 deletions

View File

@@ -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

View File

@@ -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:

View File

@@ -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);