diff --git a/interfaces/iassistant.cpp b/interfaces/iassistant.cpp index 8d433a3395..8446fb4fa7 100644 --- a/interfaces/iassistant.cpp +++ b/interfaces/iassistant.cpp @@ -1,138 +1,133 @@ /* 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 "iassistant.h" #include #include -#include + +#include using namespace KDevelop; Q_DECLARE_METATYPE(KSharedPtr) -// Very slow and ugly, but very secure -static QString removeHtmlFromString(QString string) -{ - return QTextEdit(string).toPlainText(); -} - //BEGIN IAssistant KAction* IAssistantAction::toKAction() const { KAction* ret = new KAction(KIcon(icon()), removeHtmlFromString(description()), 0); ret->setToolTip(toolTip()); qRegisterMetaType >("KSharedPtr()"); //Add the data as a KSharedPtr to the action, so this assistant stays alive at least as long as the KAction ret->setData(QVariant::fromValue(KSharedPtr(const_cast(this)))); connect(ret, SIGNAL(triggered(bool)), SLOT(execute()), Qt::QueuedConnection); return ret; } IAssistant::~IAssistant() { } IAssistantAction::IAssistantAction() : KSharedObject(*(QObject*)this) { } IAssistantAction::~IAssistantAction() { } QIcon IAssistantAction::icon() const { return QIcon(); } QString IAssistantAction::toolTip() const { return QString(); } //END IAssistantAction //BEGIN AssistantLabelAction AssistantLabelAction::AssistantLabelAction(const QString& description) : m_description(description) { } QString AssistantLabelAction::description() const { return m_description; } void AssistantLabelAction::execute() { // do nothing } KAction* AssistantLabelAction::toKAction() const { return 0; } //END AssistantLabelAction //BEGIN: IAssistant IAssistant::IAssistant() : KSharedObject(*(QObject*)this) { } QIcon IAssistant::icon() const { return QIcon(); } QString IAssistant::title() const { return QString(); } void IAssistant::doHide() { emit hide(); } QList< IAssistantAction::Ptr > IAssistant::actions() const { return m_actions; } void IAssistant::addAction(const IAssistantAction::Ptr& action) { m_actions << action; } void IAssistant::clearActions() { m_actions.clear(); } //END IAssistant #include "iassistant.moc" diff --git a/plugins/problemreporter/problemreporterplugin.cpp b/plugins/problemreporter/problemreporterplugin.cpp index 27e41ee2aa..2f6c2776bf 100644 --- a/plugins/problemreporter/problemreporterplugin.cpp +++ b/plugins/problemreporter/problemreporterplugin.cpp @@ -1,201 +1,203 @@ /* * KDevelop Problem Reporter * * Copyright 2006 Adam Treat * Copyright 2006-2007 Hamish Rodda * Copyright 2007-2008 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 "problemreporterplugin.h" #include #include #include #include #include #include #include #include #include #include +#include + #include #include #include #include #include #include "problemhighlighter.h" #include "problemwidget.h" #include "problemmodel.h" #include #include #include #include #include #include K_PLUGIN_FACTORY(KDevProblemReporterFactory, registerPlugin(); ) K_EXPORT_PLUGIN(KDevProblemReporterFactory(KAboutData("kdevproblemreporter","kdevproblemreporter", ki18n("Problem Reporter"), "0.1", ki18n("Shows errors in source code"), KAboutData::License_GPL))) using namespace KDevelop; class ProblemReporterFactory: public KDevelop::IToolViewFactory { public: ProblemReporterFactory(ProblemReporterPlugin *plugin): m_plugin(plugin) {} virtual QWidget* create(QWidget *parent = 0) { ProblemWidget* widget = new ProblemWidget(parent, m_plugin); ProblemModel* model = m_plugin->getModel(); widget->setModel(model); return widget; } virtual Qt::DockWidgetArea defaultPosition() { return Qt::BottomDockWidgetArea; } virtual QString id() const { return "org.kdevelop.ProblemReporterView"; } private: ProblemReporterPlugin *m_plugin; }; ProblemReporterPlugin::ProblemReporterPlugin(QObject *parent, const QVariantList&) : KDevelop::IPlugin(KDevProblemReporterFactory::componentData(), parent) , m_factory(new ProblemReporterFactory(this)), m_model(new ProblemModel(this)) { core()->uiController()->addToolView(i18n("Problems"), m_factory); setXMLFile( "kdevproblemreporter.rc" ); connect(ICore::self()->documentController(), SIGNAL(documentClosed(KDevelop::IDocument*)), this, SLOT(documentClosed(KDevelop::IDocument*))); connect(ICore::self()->documentController(), SIGNAL(textDocumentCreated(KDevelop::IDocument*)), this, SLOT(textDocumentCreated(KDevelop::IDocument*))); connect(ICore::self()->languageController()->backgroundParser(), SIGNAL(parseJobFinished(KDevelop::ParseJob*)), this, SLOT(parseJobFinished(KDevelop::ParseJob*)), Qt::DirectConnection); } ProblemReporterPlugin::~ProblemReporterPlugin() { qDeleteAll(m_highlighters); } ProblemModel* ProblemReporterPlugin::getModel() const { return m_model; } void ProblemReporterPlugin::unload() { core()->uiController()->removeToolView(m_factory); } void ProblemReporterPlugin::documentClosed(IDocument* doc) { if(!doc->textDocument()) return; QMutableHashIterator it = m_highlighters; IndexedString url(doc->url().pathOrUrl()); if (m_highlighters.contains(url)) delete m_highlighters.take(url); } void ProblemReporterPlugin::textDocumentCreated(KDevelop::IDocument* document) { Q_ASSERT(document->textDocument()); m_highlighters.insert(IndexedString(document->url()), new ProblemHighlighter(document->textDocument())); DUChainReadLocker lock(DUChain::lock()); DUChain::self()->updateContextForUrl(IndexedString(document->url()), KDevelop::TopDUContext::AllDeclarationsContextsAndUses, this); } void ProblemReporterPlugin::updateReady(KDevelop::IndexedString url, KDevelop::ReferencedTopDUContext) { m_model->problemsUpdated(url); if (m_highlighters.contains(url)) { ProblemHighlighter* ph = m_highlighters[url]; if (!ph) return; QList allProblems = m_model->getProblems(url, false); ph->setProblems(allProblems); } } void ProblemReporterPlugin::parseJobFinished(KDevelop::ParseJob* parseJob) { if(parseJob->duChain()) updateReady(parseJob->document(), parseJob->duChain()); } KDevelop::ContextMenuExtension ProblemReporterPlugin::contextMenuExtension(KDevelop::Context* context) { KDevelop::ContextMenuExtension extension; KDevelop::EditorContext* editorContext = dynamic_cast(context); if(editorContext) { DUChainReadLocker lock(DUChain::lock(), 1000); if(!lock.locked()) { kDebug() << "failed to lock duchain in time"; return extension; } QString title; QList actions; TopDUContext* top = DUChainUtils::standardContextForUrl(editorContext->url()); if(top) { foreach(KDevelop::ProblemPointer problem, top->problems()) { if(problem->range().contains(top->transformToLocalRevision(KDevelop::SimpleCursor(editorContext->position())))) { KDevelop::IAssistant::Ptr solution = problem ->solutionAssistant(); if(solution) { - title = solution->title(); + title = removeHtmlFromString(solution->title()); foreach(KDevelop::IAssistantAction::Ptr action, solution->actions()) actions << action->toKAction(); } } } } if(!actions.isEmpty()) { QString text = i18n("Solve Problem"); if(!title.isEmpty()) text = i18n("Solve: %1", title); QAction* menuAction = new QAction(text, 0); QMenu* menu(new QMenu(text, 0)); menuAction->setMenu(menu); foreach(QAction* action, actions) menu->addAction(action); extension.addAction(ContextMenuExtension::ExtensionGroup, menuAction); } } return extension; } #include "problemreporterplugin.moc" // kate: space-indent on; indent-width 2; tab-width 4; replace-tabs on; auto-insert-doxygen on diff --git a/util/formattinghelpers.cpp b/util/formattinghelpers.cpp index b646068712..37b2362372 100644 --- a/util/formattinghelpers.cpp +++ b/util/formattinghelpers.cpp @@ -1,192 +1,200 @@ /* This file is part of KDevelop * Copyright 2011 David Nolden This program is free software; you can redistribute it and/or modify it under the terms of the GNU 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; see the file COPYING. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "formattinghelpers.h" #include +#include #include #include namespace KDevelop { ///Matches the given prefix to the given text, ignoring all whitespace ///Returns -1 if mismatched, else the position in @p text where the @p prefix match ends int matchPrefixIgnoringWhitespace(QString text, QString prefix, QString fuzzyCharacters) { int prefixPos = 0; int textPos = 0; while (prefixPos < prefix.length() && textPos < text.length()) { skipWhiteSpace: while (prefixPos < prefix.length() && prefix[prefixPos].isSpace()) ++prefixPos; while (textPos < text.length() && text[textPos].isSpace()) ++textPos; if(prefixPos == prefix.length() || textPos == text.length()) break; if(prefix[prefixPos] != text[textPos]) { bool skippedFuzzy = false; while( prefixPos < prefix.length() && fuzzyCharacters.indexOf(prefix[prefixPos]) != -1 ) { ++prefixPos; skippedFuzzy = true; } while( textPos < text.length() && fuzzyCharacters.indexOf(text[textPos]) != -1 ) { ++textPos; skippedFuzzy = true; } if( skippedFuzzy ) goto skipWhiteSpace; return -1; } ++prefixPos; ++textPos; } return textPos; } static QString reverse( const QString& str ) { QString ret; for(int a = str.length()-1; a >= 0; --a) ret.append(str[a]); return ret; } // Returns the text start position with all whitespace that is redundant in the given context skipped int skipRedundantWhiteSpace( QString context, QString text, int tabWidth ) { if( context.isEmpty() || !context[context.size()-1].isSpace() || text.isEmpty() || !text[0].isSpace() ) return 0; int textPosition = 0; // Extract trailing whitespace in the context int contextPosition = context.size()-1; while( contextPosition > 0 && context[contextPosition-1].isSpace() ) --contextPosition; int textWhitespaceEnd = 0; while(textWhitespaceEnd < text.size() && text[textWhitespaceEnd].isSpace()) ++textWhitespaceEnd; QString contextWhiteSpace = context.mid(contextPosition); contextPosition = 0; QString textWhiteSpace = text.left(textWhitespaceEnd); // Step 1: Remove redundant newlines while(contextWhiteSpace.contains('\n') && textWhiteSpace.contains('\n')) { int contextOffset = contextWhiteSpace.indexOf('\n')+1; int textOffset = textWhiteSpace.indexOf('\n')+1; contextPosition += contextOffset; contextWhiteSpace.remove(0, contextOffset); textPosition += textOffset; textWhiteSpace.remove(0, textOffset); } int contextOffset = 0; int textOffset = 0; // Skip redundant ordinary whitespace while( contextOffset < contextWhiteSpace.size() && textOffset < textWhiteSpace.size() && contextWhiteSpace[contextOffset].isSpace() && contextWhiteSpace[contextOffset] != '\n' && textWhiteSpace[textOffset].isSpace() && textWhiteSpace[textOffset] != '\n' ) { bool contextWasTab = contextWhiteSpace[contextOffset] == ' '; bool textWasTab = textWhiteSpace[contextOffset] == ' '; ++contextOffset; ++textOffset; if( contextWasTab != textWasTab ) { // Problem: We have a mismatch of tabs and/or ordinary whitespaces if( contextWasTab ) { for( int s = 1; s < tabWidth; ++s ) if( textOffset < textWhiteSpace.size() && textWhiteSpace[textOffset] == ' ' ) ++textOffset; }else if( textWasTab ) { for( int s = 1; s < tabWidth; ++s ) if( contextOffset < contextWhiteSpace.size() && contextWhiteSpace[contextOffset] == ' ' ) ++contextOffset; } } } return textPosition+textOffset; } QString extractFormattedTextFromContext( const QString& _formattedMergedText, const QString& text, const QString& leftContext, const QString& rightContext, int tabWidth, const QString& fuzzyCharacters) { QString formattedMergedText = _formattedMergedText; //Now remove "leftContext" and "rightContext" from the sides if(!leftContext.isEmpty()) { int endOfLeftContext = matchPrefixIgnoringWhitespace( formattedMergedText, leftContext, QString() ); if(endOfLeftContext == -1) { // Try 2: Ignore the fuzzy characters while matching endOfLeftContext = matchPrefixIgnoringWhitespace( formattedMergedText, leftContext, fuzzyCharacters ); if(endOfLeftContext == -1) { kWarning() << "problem matching the left context"; return text; } } int startOfWhiteSpace = endOfLeftContext; // Include all leading whitespace while(startOfWhiteSpace > 0 && formattedMergedText[startOfWhiteSpace-1].isSpace()) --startOfWhiteSpace; formattedMergedText = formattedMergedText.mid(startOfWhiteSpace); int skip = skipRedundantWhiteSpace( leftContext, formattedMergedText, tabWidth ); formattedMergedText = formattedMergedText.mid(skip); } if(!rightContext.isEmpty()) { //Add a whitespace behind the text for matching, so that we definitely capture all trailing whitespace int endOfText = matchPrefixIgnoringWhitespace( formattedMergedText, text+' ', QString() ); if(endOfText == -1) { // Try 2: Ignore the fuzzy characters while matching endOfText = matchPrefixIgnoringWhitespace( formattedMergedText, text+' ', fuzzyCharacters ); if(endOfText == -1) { kWarning() << "problem matching the text while formatting"; return text; } } formattedMergedText = formattedMergedText.left(endOfText); int skip = skipRedundantWhiteSpace( reverse(rightContext), reverse(formattedMergedText), tabWidth ); formattedMergedText = formattedMergedText.left(formattedMergedText.size() - skip); } return formattedMergedText; } +QString removeHtmlFromString( const QString& htmlString ) +{ + QTextDocument doc; + doc.setHtml( htmlString ); + return doc.toPlainText(); +} + } diff --git a/util/formattinghelpers.h b/util/formattinghelpers.h index d82d421573..6a65376faf 100644 --- a/util/formattinghelpers.h +++ b/util/formattinghelpers.h @@ -1,47 +1,58 @@ /* This file is part of KDevelop * Copyright 2011 David Nolden This program is free software; you can redistribute it and/or modify it under the terms of the GNU 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; see the file COPYING. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef FORMATTINGHELPERS_H #define FORMATTINGHELPERS_H #include "utilexport.h" #include class QString; namespace KDevelop { /** * Helps extracting a re-formatted version of a text fragment, within a specific left and right context. * The re-formatting must be an operation which only changes whitespace, and keeps whitespace boundaries * between identifiers intact. If this is not the case, the original text is returned. * * @param formattedMergedText The re-formatted merged text: format(leftContext + text + rightContext) * @param originalMergedText The original merged text: (leftContext + text + rightContext) * @param text The text fragment of which the re-formatted version will be returned * @param leftContext The left context of the text fragment * @param rightContext The right context of the text fragment * @param tabWidth The width of one tab, required while matching tabs vs. spaces * @param fuzzyCharacters Characters which are ignored in case of mismatches * * @return The re-formatted version of @p text * */ KDEVPLATFORMUTIL_EXPORT QString extractFormattedTextFromContext(const QString& formattedMergedText, const QString& text, const QString& leftContext, const QString& rightContext, int tabWidth = 4, const QString& fuzzyCharacters = "{}()/*/"); + +/** + * + * Helps to convert HTML-encoded string into plain text + * (strips tags, unescapes sequences like "&apos"). + * + * @param htmlString A rich-text/HTML-encoded string + * @returns The plain text representation of the argument. + */ +KDEVPLATFORMUTIL_EXPORT QString removeHtmlFromString(const QString& htmlString); + } #endif // FORMATTINGHELPERS_H