diff --git a/language/duchain/navigation/problemnavigationcontext.cpp b/language/duchain/navigation/problemnavigationcontext.cpp index 1cc00d607d..da6a987083 100644 --- a/language/duchain/navigation/problemnavigationcontext.cpp +++ b/language/duchain/navigation/problemnavigationcontext.cpp @@ -1,119 +1,119 @@ /* Copyright 2009 David Nolden This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License version 2 as published by the Free Software Foundation. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "problemnavigationcontext.h" #include #include #include #include #include #include #include #include #include using namespace KDevelop; -ProblemNavigationContext::ProblemNavigationContext(ProblemPointer problem): m_problem(problem) +ProblemNavigationContext::ProblemNavigationContext(const IProblem::Ptr& problem) + : m_problem(problem) + , m_widget(nullptr) { - m_widget = 0; - QExplicitlySharedDataPointer< IAssistant > solution = problem->solutionAssistant(); if(solution && !solution->actions().isEmpty()) { m_widget = new QWidget; QHBoxLayout* layout = new QHBoxLayout(m_widget); RichTextPushButton* button = new RichTextPushButton; // button->setPopupMode(QToolButton::InstantPopup); if(!solution->title().isEmpty()) button->setHtml(i18n("Solve: %1", solution->title())); else button->setHtml(i18n("Solve")); QMenu* menu = new QMenu; menu->setFocusPolicy(Qt::NoFocus); foreach(IAssistantAction::Ptr action, solution->actions()) { menu->addAction(action->toKAction()); } button->setMenu(menu); layout->addWidget(button); layout->setAlignment(button, Qt::AlignLeft); m_widget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Maximum); } } ProblemNavigationContext::~ProblemNavigationContext() { delete m_widget; } QWidget* ProblemNavigationContext::widget() const { return m_widget; } bool ProblemNavigationContext::isWidgetMaximized() const { return false; } QString ProblemNavigationContext::name() const { return i18n("Problem"); } QString ProblemNavigationContext::html(bool shorten) { clear(); m_shorten = shorten; modifyHtml() += QStringLiteral("

"); modifyHtml() += i18n("Problem in %1:
", m_problem->sourceString()); modifyHtml() += m_problem->description().toHtmlEscaped(); modifyHtml() += QStringLiteral("
"); modifyHtml() += "" + m_problem->explanation().toHtmlEscaped() + ""; const QVector diagnostics = m_problem->diagnostics(); if (!diagnostics.isEmpty()) { modifyHtml() += QStringLiteral("
"); DUChainReadLocker lock; for (auto diagnostic : diagnostics) { const DocumentRange range = diagnostic->finalLocation(); Declaration* declaration = DUChainUtils::itemUnderCursor(range.document.toUrl(), range.start()); modifyHtml() += labelHighlight(QStringLiteral("%1: ").arg(diagnostic->severityString())); modifyHtml() += diagnostic->description(); if (declaration) { modifyHtml() += QStringLiteral("
"); makeLink(declaration->toString(), KDevelop::DeclarationPointer(declaration), NavigationAction::NavigateDeclaration); modifyHtml() += i18n(" in "); makeLink(QStringLiteral("%1 :%2").arg(declaration->url().toUrl().fileName()).arg(declaration->rangeInCurrentRevision().start().line()+1), KDevelop::DeclarationPointer(declaration), NavigationAction::NavigateDeclaration); } modifyHtml() += QStringLiteral("
"); } } modifyHtml() += QStringLiteral("

"); return currentHtml(); } diff --git a/language/duchain/navigation/problemnavigationcontext.h b/language/duchain/navigation/problemnavigationcontext.h index 70728fe62c..c1bc01cc2e 100644 --- a/language/duchain/navigation/problemnavigationcontext.h +++ b/language/duchain/navigation/problemnavigationcontext.h @@ -1,46 +1,49 @@ /* Copyright 2009 David Nolden This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License version 2 as published by the Free Software Foundation. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef KDEVPLATFORM_PROBLEMNAVIGATIONCONTEXT_H #define KDEVPLATFORM_PROBLEMNAVIGATIONCONTEXT_H +#include #include -#include #include #include namespace KDevelop { class KDEVPLATFORMLANGUAGE_EXPORT ProblemNavigationContext : public AbstractNavigationContext { Q_OBJECT public: - explicit ProblemNavigationContext(KDevelop::ProblemPointer problem); + explicit ProblemNavigationContext(const IProblem::Ptr& problem); ~ProblemNavigationContext(); + virtual QString name() const override; virtual QString html(bool shorten = false) override; virtual QWidget* widget() const override; virtual bool isWidgetMaximized() const override; + private: + IProblem::Ptr m_problem; + QPointer m_widget; - ProblemPointer m_problem; }; } #endif // KDEVPLATFORM_PROBLEMNAVIGATIONCONTEXT_H diff --git a/plugins/problemreporter/CMakeLists.txt b/plugins/problemreporter/CMakeLists.txt index 10afdb7b23..3c52a993ef 100644 --- a/plugins/problemreporter/CMakeLists.txt +++ b/plugins/problemreporter/CMakeLists.txt @@ -1,18 +1,18 @@ add_definitions(-DTRANSLATION_DOMAIN=\"kdevproblemreporter\") ########### next target ############### set(kdevproblemreporter_PART_SRCS problemreporterplugin.cpp problemtreeview.cpp problemhighlighter.cpp problemsview.cpp - problemnavigationcontext.cpp + #problemnavigationcontext.cpp problemreportermodel.cpp ) qt5_add_resources(kdevproblemreporter_PART_SRCS kdevproblemreporter.qrc) kdevplatform_add_plugin(kdevproblemreporter JSON kdevproblemreporter.json SOURCES ${kdevproblemreporter_PART_SRCS}) target_link_libraries(kdevproblemreporter KF5::TextEditor KF5::Parts KDev::Language KDev::Interfaces KDev::Util KDev::Project KDev::Shell) add_subdirectory(tests) diff --git a/plugins/problemreporter/problemhighlighter.cpp b/plugins/problemreporter/problemhighlighter.cpp index 02848111e3..c91a967850 100644 --- a/plugins/problemreporter/problemhighlighter.cpp +++ b/plugins/problemreporter/problemhighlighter.cpp @@ -1,260 +1,260 @@ /* * KDevelop Problem Reporter * * Copyright 2008 Hamish Rodda * Copyright 2008-2009 David Nolden * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Library General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "problemhighlighter.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include +#include #include #include #include -#include "problemnavigationcontext.h" using namespace KTextEditor; using namespace KDevelop; namespace { QColor colorForSeverity(IProblem::Severity severity) { KColorScheme scheme(QPalette::Active); switch (severity) { case IProblem::Error: return scheme.foreground(KColorScheme::NegativeText).color(); case IProblem::Warning: return scheme.foreground(KColorScheme::NeutralText).color(); case IProblem::Hint: default: return scheme.foreground(KColorScheme::PositiveText).color(); } } } ProblemHighlighter::ProblemHighlighter(KTextEditor::Document* document) : m_document(document) , m_textHintProvider(this) { Q_ASSERT(m_document); foreach (KTextEditor::View* view, m_document->views()) viewCreated(document, view); connect(m_document.data(), &Document::viewCreated, this, &ProblemHighlighter::viewCreated); connect(ICore::self()->languageController()->completionSettings(), &ICompletionSettings::settingsChanged, this, &ProblemHighlighter::settingsChanged); connect(m_document.data(), &Document::aboutToReload, this, &ProblemHighlighter::clearProblems); if (qobject_cast(m_document)) { // can't use new signal/slot syntax here, MovingInterface is not a QObject connect(m_document, SIGNAL(aboutToInvalidateMovingInterfaceContent(KTextEditor::Document*)), this, SLOT(clearProblems())); } connect(m_document, SIGNAL(aboutToRemoveText(KTextEditor::Range)), this, SLOT(aboutToRemoveText(KTextEditor::Range))); } void ProblemHighlighter::settingsChanged() { // Re-highlight setProblems(m_problems); } void ProblemHighlighter::viewCreated(Document*, View* view) { KTextEditor::TextHintInterface* iface = dynamic_cast(view); if (!iface) return; iface->registerTextHintProvider(&m_textHintProvider); } ProblemTextHintProvider::ProblemTextHintProvider(ProblemHighlighter* highlighter) : m_highlighter(highlighter) { } QString ProblemTextHintProvider::textHint(View* view, const Cursor& pos) { KTextEditor::MovingInterface* moving = dynamic_cast(view->document()); if (moving) { ///@todo Sort the ranges when writing them, and do binary search instead of linear foreach (MovingRange* range, m_highlighter->m_topHLRanges) { if (m_highlighter->m_problemsForRanges.contains(range) && range->contains(pos)) { // There is a problem which's range contains the cursor IProblem::Ptr problem = m_highlighter->m_problemsForRanges[range]; if (problem->source() == IProblem::ToDo) { continue; } if (m_currentHintRange == range->toRange()) { continue; } m_currentHintRange = range->toRange(); KDevelop::AbstractNavigationWidget* widget = new KDevelop::AbstractNavigationWidget; widget->setContext(NavigationContextPointer(new ProblemNavigationContext(problem))); KDevelop::NavigationToolTip* tooltip = new KDevelop::NavigationToolTip(view, QCursor::pos() + QPoint(20, 40), widget); tooltip->resize(widget->sizeHint() + QSize(10, 10)); tooltip->setHandleRect(getItemBoundingRect(view, m_currentHintRange)); tooltip->connect(tooltip, &ActiveToolTip::destroyed, [&] () { m_currentHintRange = {}; }); ActiveToolTip::showToolTip(tooltip, 99, QStringLiteral("problem-tooltip")); return QString(); } } } return QString(); } ProblemHighlighter::~ProblemHighlighter() { if (m_topHLRanges.isEmpty() || !m_document) return; qDeleteAll(m_topHLRanges); } void ProblemHighlighter::setProblems(const QVector& problems) { if (!m_document) return; const bool hadProblems = !m_problems.isEmpty(); m_problems = problems; qDeleteAll(m_topHLRanges); m_topHLRanges.clear(); m_problemsForRanges.clear(); IndexedString url(m_document->url()); /// TODO: create a better MarkInterface that makes it possible to add the marks to the scrollbar /// but having no background. /// also make it nicer together with other plugins, this would currently fail with /// this method... const uint errorMarkType = KTextEditor::MarkInterface::Error; const uint warningMarkType = KTextEditor::MarkInterface::Warning; KTextEditor::MarkInterface* markIface = dynamic_cast(m_document.data()); if (markIface && hadProblems) { // clear previously added marks foreach (KTextEditor::Mark* mark, markIface->marks().values()) { if (mark->type == errorMarkType || mark->type == warningMarkType) { markIface->removeMark(mark->line, mark->type); } } } if (problems.isEmpty()) { return; } DUChainReadLocker lock; TopDUContext* top = DUChainUtils::standardContextForUrl(m_document->url()); KTextEditor::MovingInterface* iface = dynamic_cast(m_document.data()); Q_ASSERT(iface); foreach (const IProblem::Ptr& problem, problems) { if (problem->finalLocation().document != url || !problem->finalLocation().isValid()) continue; KTextEditor::Range range; if (top) range = top->transformFromLocalRevision(RangeInRevision::castFromSimpleRange(problem->finalLocation())); else range = problem->finalLocation(); if (range.end().line() >= m_document->lines()) range.end() = KTextEditor::Cursor(m_document->endOfLine(m_document->lines() - 1)); if (range.isEmpty()) { range.setEnd(range.end() + KTextEditor::Cursor(0, 1)); } KTextEditor::MovingRange* problemRange = iface->newMovingRange(range); m_problemsForRanges.insert(problemRange, problem); m_topHLRanges.append(problemRange); if (problem->source() != IProblem::ToDo && (problem->severity() != IProblem::Hint || ICore::self()->languageController()->completionSettings()->highlightSemanticProblems())) { KTextEditor::Attribute::Ptr attribute(new KTextEditor::Attribute()); attribute->setUnderlineStyle(QTextCharFormat::WaveUnderline); attribute->setUnderlineColor(colorForSeverity(problem->severity())); problemRange->setAttribute(attribute); } if (markIface && ICore::self()->languageController()->completionSettings()->highlightProblematicLines()) { uint mark; if (problem->severity() == IProblem::Error) { mark = errorMarkType; } else if (problem->severity() == IProblem::Warning) { mark = warningMarkType; } else { continue; } markIface->addMark(problem->finalLocation().start().line(), mark); } } } void ProblemHighlighter::aboutToRemoveText(const KTextEditor::Range& range) { if (range.onSingleLine()) { // no need to optimize this return; } QList::iterator it = m_topHLRanges.begin(); while (it != m_topHLRanges.end()) { if (range.contains((*it)->toRange())) { m_problemsForRanges.remove(*it); delete (*it); it = m_topHLRanges.erase(it); } else { ++it; } } } void ProblemHighlighter::clearProblems() { setProblems({}); } diff --git a/plugins/problemreporter/problemnavigationcontext.cpp b/plugins/problemreporter/problemnavigationcontext.cpp deleted file mode 100644 index 431c862a25..0000000000 --- a/plugins/problemreporter/problemnavigationcontext.cpp +++ /dev/null @@ -1,122 +0,0 @@ -/* - Copyright 2009 David Nolden - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License version 2 as published by the Free Software Foundation. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public License - along with this library; see the file COPYING.LIB. If not, write to - the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, USA. -*/ - -#include "problemnavigationcontext.h" - -#include -#include - -#include - -#include -#include -#include -#include -#include - -using namespace KDevelop; - -ProblemNavigationContext::ProblemNavigationContext(const IProblem::Ptr& problem) - : m_problem(problem) -{ - m_widget = 0; - - QExplicitlySharedDataPointer solution = problem->solutionAssistant(); - if (solution && !solution->actions().isEmpty()) { - m_widget = new QWidget; - QHBoxLayout* layout = new QHBoxLayout(m_widget); - RichTextPushButton* button = new RichTextPushButton; - // button->setPopupMode(QToolButton::InstantPopup); - if (!solution->title().isEmpty()) - button->setHtml(i18n("Solve: %1", solution->title())); - else - button->setHtml(i18n("Solve")); - - QMenu* menu = new QMenu; - menu->setFocusPolicy(Qt::NoFocus); - foreach (IAssistantAction::Ptr action, solution->actions()) { - menu->addAction(action->toKAction()); - } - button->setMenu(menu); - - layout->addWidget(button); - layout->setAlignment(button, Qt::AlignLeft); - m_widget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Maximum); - } -} - -ProblemNavigationContext::~ProblemNavigationContext() -{ - delete m_widget; -} - -QWidget* ProblemNavigationContext::widget() const -{ - return m_widget; -} - -bool ProblemNavigationContext::isWidgetMaximized() const -{ - return false; -} - -QString ProblemNavigationContext::name() const -{ - return i18n("Problem"); -} - -QString ProblemNavigationContext::html(bool shorten) -{ - clear(); - m_shorten = shorten; - modifyHtml() += QStringLiteral("

"); - - modifyHtml() += i18n("Problem in %1:
", m_problem->sourceString()); - modifyHtml() += m_problem->description().toHtmlEscaped(); - modifyHtml() += QStringLiteral("
"); - modifyHtml() += "" + m_problem->explanation().toHtmlEscaped() + ""; - - const QVector& diagnostics = m_problem->diagnostics(); - if (!diagnostics.isEmpty()) { - modifyHtml() += QStringLiteral("
"); - - DUChainReadLocker lock; - for (auto diagnostic : diagnostics) { - const DocumentRange range = diagnostic->finalLocation(); - Declaration* declaration = DUChainUtils::itemUnderCursor(range.document.toUrl(), range.start()); - - modifyHtml() += labelHighlight(QStringLiteral("%1: ").arg(diagnostic->severityString())); - modifyHtml() += diagnostic->description(); - - if (declaration) { - modifyHtml() += QStringLiteral("
"); - makeLink(declaration->toString(), KDevelop::DeclarationPointer(declaration), - NavigationAction::NavigateDeclaration); - modifyHtml() += i18n(" in "); - makeLink(QStringLiteral("%1 :%2") - .arg(declaration->url().toUrl().fileName()) - .arg(declaration->rangeInCurrentRevision().start().line() + 1), - KDevelop::DeclarationPointer(declaration), NavigationAction::NavigateDeclaration); - } - modifyHtml() += QStringLiteral("
"); - } - } - - modifyHtml() += QStringLiteral("

"); - return currentHtml(); -} diff --git a/plugins/problemreporter/problemnavigationcontext.h b/plugins/problemreporter/problemnavigationcontext.h deleted file mode 100644 index 22add5dc6e..0000000000 --- a/plugins/problemreporter/problemnavigationcontext.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - Copyright 2009 David Nolden - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License version 2 as published by the Free Software Foundation. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public License - along with this library; see the file COPYING.LIB. If not, write to - the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, USA. -*/ - -#ifndef KDEVPLATFORM_IPROBLEMNAVIGATIONCONTEXT_H -#define KDEVPLATFORM_IPROBLEMNAVIGATIONCONTEXT_H - -#include -#include - -#include - -namespace KDevelop -{ - -// Navigation context for IProblem -class ProblemNavigationContext : public AbstractNavigationContext -{ - Q_OBJECT -public: - explicit ProblemNavigationContext(const IProblem::Ptr& problem); - ~ProblemNavigationContext(); - virtual QString name() const override; - virtual QString html(bool shorten = false) override; - virtual QWidget* widget() const override; - virtual bool isWidgetMaximized() const override; - -private: - QPointer m_widget; - IProblem::Ptr m_problem; -}; -} - -#endif // KDEVPLATFORM_PROBLEMNAVIGATIONCONTEXT_H