mirror of
https://bitbucket.org/smil3y/kde-extraapps.git
synced 2025-02-25 03:12:53 +00:00
659 lines
23 KiB
C++
659 lines
23 KiB
C++
/* This file is part of KDevelop
|
|
Copyright 2009 Andreas Pakulat <apaku@gmx.de>
|
|
Copyright (C) 2008 Cédric Pasteur <cedric.pasteur@free.fr>
|
|
|
|
This library 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 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 "sourceformattercontroller.h"
|
|
|
|
#include <QVariant>
|
|
#include <QStringList>
|
|
#include <QRegExp>
|
|
#include <KPluginInfo>
|
|
#include <KDebug>
|
|
|
|
#include <interfaces/icore.h>
|
|
#include <interfaces/iplugincontroller.h>
|
|
#include <interfaces/ilanguagecontroller.h>
|
|
#include <language/interfaces/ilanguagesupport.h>
|
|
#include <language/codegen/coderepresentation.h>
|
|
#include <interfaces/isourceformatter.h>
|
|
#include "core.h"
|
|
#include <ktexteditor/view.h>
|
|
#include <project/projectmodel.h>
|
|
#include <util/path.h>
|
|
#include <kio/netaccess.h>
|
|
#include <kmessagebox.h>
|
|
#include <qfile.h>
|
|
#include <interfaces/context.h>
|
|
#include <interfaces/contextmenuextension.h>
|
|
#include <ktexteditor/commandinterface.h>
|
|
#include <kactioncollection.h>
|
|
#include <kaction.h>
|
|
#include <interfaces/idocument.h>
|
|
#include <interfaces/idocumentcontroller.h>
|
|
#include <ktexteditor/document.h>
|
|
#include <ktexteditor/editor.h>
|
|
#include <ktexteditor/configinterface.h>
|
|
#include "plugincontroller.h"
|
|
#include <interfaces/isession.h>
|
|
|
|
namespace KDevelop
|
|
{
|
|
|
|
const QString SourceFormatterController::kateModeLineConfigKey = "ModelinesEnabled";
|
|
const QString SourceFormatterController::kateOverrideIndentationConfigKey = "OverrideKateIndentation";
|
|
const QString SourceFormatterController::styleCaptionKey = "Caption";
|
|
const QString SourceFormatterController::styleContentKey = "Content";
|
|
const QString SourceFormatterController::styleMimeTypesKey = "MimeTypes";
|
|
const QString SourceFormatterController::styleSampleKey = "StyleSample";
|
|
|
|
SourceFormatterController::SourceFormatterController(QObject *parent)
|
|
: ISourceFormatterController(parent), m_enabled(true)
|
|
{
|
|
setObjectName("SourceFormatterController");
|
|
setComponentData(KComponentData("kdevsourceformatter"));
|
|
setXMLFile("kdevsourceformatter.rc");
|
|
|
|
if (Core::self()->setupFlags() & Core::NoUi) return;
|
|
|
|
m_formatTextAction = actionCollection()->addAction("edit_reformat_source");
|
|
m_formatTextAction->setText(i18n("&Reformat Source"));
|
|
m_formatTextAction->setToolTip(i18n("Reformat source using AStyle"));
|
|
m_formatTextAction->setWhatsThis(i18n("Source reformatting functionality using <b>astyle</b> library."));
|
|
connect(m_formatTextAction, SIGNAL(triggered()), this, SLOT(beautifySource()));
|
|
|
|
m_formatLine = actionCollection()->addAction("edit_reformat_line");
|
|
m_formatLine->setText(i18n("Reformat Line"));
|
|
m_formatLine->setToolTip(i18n("Reformat current line using AStyle"));
|
|
m_formatLine->setWhatsThis(i18n("Source reformatting of line under cursor using <b>astyle</b> library."));
|
|
connect(m_formatLine, SIGNAL(triggered()), this, SLOT(beautifyLine()));
|
|
|
|
m_formatFilesAction = actionCollection()->addAction("tools_astyle");
|
|
m_formatFilesAction->setText(i18n("Format Files"));
|
|
m_formatFilesAction->setToolTip(i18n("Format file(s) using the current theme"));
|
|
m_formatFilesAction->setWhatsThis(i18n("Formatting functionality using <b>astyle</b> library."));
|
|
connect(m_formatFilesAction, SIGNAL(triggered()), this, SLOT(formatFiles()));
|
|
|
|
m_formatTextAction->setEnabled(false);
|
|
m_formatFilesAction->setEnabled(true);
|
|
|
|
connect(Core::self()->documentController(), SIGNAL(documentActivated(KDevelop::IDocument*)),
|
|
this, SLOT(activeDocumentChanged(KDevelop::IDocument*)));
|
|
// Use a queued connection, because otherwise the view is not yet fully set up
|
|
connect(Core::self()->documentController(), SIGNAL(documentLoaded(KDevelop::IDocument*)),
|
|
this, SLOT(documentLoaded(KDevelop::IDocument*)), Qt::QueuedConnection);
|
|
|
|
activeDocumentChanged(Core::self()->documentController()->activeDocument());
|
|
}
|
|
|
|
void SourceFormatterController::documentLoaded( IDocument* doc )
|
|
{
|
|
// NOTE: explicitly check this here to prevent crashes on shutdown
|
|
// when this slot gets called (note: delayed connection)
|
|
// but the text document was already destroyed
|
|
// there have been unit tests that failed due to that...
|
|
if (!doc->textDocument()) {
|
|
return;
|
|
}
|
|
KMimeType::Ptr mime = KMimeType::findByUrl(doc->url());
|
|
adaptEditorIndentationMode( doc, formatterForMimeType(mime) );
|
|
}
|
|
|
|
void SourceFormatterController::initialize()
|
|
{
|
|
}
|
|
|
|
SourceFormatterController::~SourceFormatterController()
|
|
{
|
|
}
|
|
|
|
ISourceFormatter* SourceFormatterController::formatterForUrl(const KUrl &url)
|
|
{
|
|
KMimeType::Ptr mime = KMimeType::findByUrl(url);
|
|
return formatterForMimeType(mime);
|
|
}
|
|
KConfigGroup SourceFormatterController::configuration() const
|
|
{
|
|
return Core::self()->activeSession()->config()->group( "SourceFormatter" );
|
|
}
|
|
|
|
ISourceFormatter* SourceFormatterController::findFirstFormatterForMimeType( const KMimeType::Ptr& mime ) const
|
|
{
|
|
static QHash<QString, ISourceFormatter*> knownFormatters;
|
|
if (knownFormatters.contains(mime->name()))
|
|
return knownFormatters[mime->name()];
|
|
|
|
foreach( IPlugin* p, Core::self()->pluginController()->allPluginsForExtension( "org.kdevelop.ISourceFormatter" ) ) {
|
|
KPluginInfo info = Core::self()->pluginController()->pluginInfo( p );
|
|
ISourceFormatter *iformatter = p->extension<ISourceFormatter>();
|
|
QSharedPointer<SourceFormatter> formatter(createFormatterForPlugin(iformatter));
|
|
if( formatter->supportedMimeTypes().contains(mime->name()) ) {
|
|
knownFormatters[mime->name()] = iformatter;
|
|
return iformatter;
|
|
}
|
|
}
|
|
knownFormatters[mime->name()] = 0;
|
|
return 0;
|
|
}
|
|
|
|
static void populateStyleFromConfigGroup(SourceFormatterStyle* s, const KConfigGroup& stylegrp)
|
|
{
|
|
s->setCaption( stylegrp.readEntry( SourceFormatterController::styleCaptionKey, QString() ) );
|
|
s->setContent( stylegrp.readEntry( SourceFormatterController::styleContentKey, QString() ) );
|
|
s->setMimeTypes( stylegrp.readEntry<QStringList>( SourceFormatterController::styleMimeTypesKey, QStringList() ) );
|
|
s->setOverrideSample( stylegrp.readEntry( SourceFormatterController::styleSampleKey, QString() ) );
|
|
}
|
|
|
|
SourceFormatter* SourceFormatterController::createFormatterForPlugin(ISourceFormatter *ifmt) const
|
|
{
|
|
SourceFormatter* formatter = new SourceFormatter();
|
|
formatter->formatter = ifmt;
|
|
|
|
// Inserted a new formatter. Now fill it with styles
|
|
foreach( const KDevelop::SourceFormatterStyle& style, ifmt->predefinedStyles() ) {
|
|
formatter->styles[ style.name() ] = new SourceFormatterStyle(style);
|
|
}
|
|
KConfigGroup grp = configuration();
|
|
if( grp.hasGroup( ifmt->name() ) ) {
|
|
KConfigGroup fmtgrp = grp.group( ifmt->name() );
|
|
foreach( const QString& subgroup, fmtgrp.groupList() ) {
|
|
SourceFormatterStyle* s = new SourceFormatterStyle( subgroup );
|
|
KConfigGroup stylegrp = fmtgrp.group( subgroup );
|
|
populateStyleFromConfigGroup(s, stylegrp);
|
|
formatter->styles[ s->name() ] = s;
|
|
}
|
|
}
|
|
return formatter;
|
|
}
|
|
|
|
ISourceFormatter* SourceFormatterController::formatterForMimeType(const KMimeType::Ptr &mime)
|
|
{
|
|
if( !m_enabled || !isMimeTypeSupported( mime ) ) {
|
|
return 0;
|
|
}
|
|
QString formatter = configuration().readEntry( mime->name(), "" );
|
|
|
|
if( formatter.isEmpty() )
|
|
{
|
|
return findFirstFormatterForMimeType( mime );
|
|
}
|
|
|
|
QStringList formatterinfo = formatter.split( "||", QString::SkipEmptyParts );
|
|
|
|
if( formatterinfo.size() != 2 ) {
|
|
kDebug() << "Broken formatting entry for mime:" << mime << "current value:" << formatter;
|
|
return 0;
|
|
}
|
|
|
|
return Core::self()->pluginControllerInternal()->extensionForPlugin<ISourceFormatter>( "org.kdevelop.ISourceFormatter", formatterinfo.at(0) );
|
|
}
|
|
|
|
bool SourceFormatterController::isMimeTypeSupported(const KMimeType::Ptr &mime)
|
|
{
|
|
if( findFirstFormatterForMimeType( mime ) ) {
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
QString SourceFormatterController::indentationMode(const KMimeType::Ptr &mime)
|
|
{
|
|
if (mime->is("text/x-c++src") || mime->is("text/x-chdr") ||
|
|
mime->is("text/x-c++hdr") || mime->is("text/x-csrc") ||
|
|
mime->is("text/x-java") || mime->is("text/x-csharp"))
|
|
return "cstyle";
|
|
return "none";
|
|
}
|
|
|
|
QString SourceFormatterController::addModelineForCurrentLang(QString input, const KUrl& url, const KMimeType::Ptr& mime)
|
|
{
|
|
if( !isMimeTypeSupported(mime) )
|
|
return input;
|
|
|
|
QRegExp kateModelineWithNewline("\\s*\\n//\\s*kate:(.*)$");
|
|
|
|
// If there already is a modeline in the document, adapt it while formatting, even
|
|
// if "add modeline" is disabled.
|
|
if( !configuration().readEntry( SourceFormatterController::kateModeLineConfigKey, false ) &&
|
|
kateModelineWithNewline.indexIn( input ) == -1 )
|
|
return input;
|
|
|
|
ISourceFormatter* fmt = formatterForMimeType( mime );
|
|
ISourceFormatter::Indentation indentation = fmt->indentation(url);
|
|
|
|
if( !indentation.isValid() )
|
|
return input;
|
|
|
|
QString output;
|
|
QTextStream os(&output, QIODevice::WriteOnly);
|
|
QTextStream is(&input, QIODevice::ReadOnly);
|
|
|
|
Q_ASSERT(fmt);
|
|
|
|
|
|
QString modeline("// kate: ");
|
|
QString indentLength = QString::number(indentation.indentWidth);
|
|
QString tabLength = QString::number(indentation.indentationTabWidth);
|
|
// add indentation style
|
|
modeline.append("indent-mode ").append(indentationMode(mime).append("; "));
|
|
|
|
if(indentation.indentWidth) // We know something about indentation-width
|
|
modeline.append(QString("indent-width %1; ").arg(indentation.indentWidth));
|
|
|
|
if(indentation.indentationTabWidth != 0) // We know something about tab-usage
|
|
{
|
|
modeline.append(QString("replace-tabs %1; ").arg((indentation.indentationTabWidth == -1) ? "on" : "off"));
|
|
if(indentation.indentationTabWidth > 0)
|
|
modeline.append(QString("tab-width %1; ").arg(indentation.indentationTabWidth));
|
|
}
|
|
|
|
kDebug() << "created modeline: " << modeline << endl;
|
|
|
|
QRegExp kateModeline("^\\s*//\\s*kate:(.*)$");
|
|
|
|
bool modelinefound = false;
|
|
QRegExp knownOptions("\\s*(indent-width|space-indent|tab-width|indent-mode|replace-tabs)");
|
|
while (!is.atEnd()) {
|
|
QString line = is.readLine();
|
|
// replace only the options we care about
|
|
if (kateModeline.indexIn(line) >= 0) { // match
|
|
kDebug() << "Found a kate modeline: " << line << endl;
|
|
modelinefound = true;
|
|
QString options = kateModeline.cap(1);
|
|
QStringList optionList = options.split(';', QString::SkipEmptyParts);
|
|
|
|
os << modeline;
|
|
foreach(QString s, optionList) {
|
|
if (knownOptions.indexIn(s) < 0) { // unknown option, add it
|
|
if(s.startsWith(' '))
|
|
s=s.mid(1);
|
|
os << s << ";";
|
|
kDebug() << "Found unknown option: " << s << endl;
|
|
}
|
|
}
|
|
os << endl;
|
|
} else
|
|
os << line << endl;
|
|
}
|
|
|
|
if (!modelinefound)
|
|
os << modeline << endl;
|
|
return output;
|
|
}
|
|
|
|
void SourceFormatterController::cleanup()
|
|
{
|
|
}
|
|
|
|
|
|
void SourceFormatterController::activeDocumentChanged(IDocument* doc)
|
|
{
|
|
bool enabled = false;
|
|
|
|
if (doc) {
|
|
KMimeType::Ptr mime = KMimeType::findByUrl(doc->url());
|
|
if (isMimeTypeSupported(mime))
|
|
enabled = true;
|
|
}
|
|
|
|
m_formatTextAction->setEnabled(enabled);
|
|
}
|
|
|
|
void SourceFormatterController::beautifySource()
|
|
{
|
|
KDevelop::IDocumentController *docController = KDevelop::ICore::self()->documentController();
|
|
KDevelop::IDocument *doc = docController->activeDocument();
|
|
if (!doc)
|
|
return;
|
|
// load the appropriate formatter
|
|
KMimeType::Ptr mime = KMimeType::findByUrl(doc->url());
|
|
ISourceFormatter *formatter = formatterForMimeType(mime);
|
|
if( !formatter ) {
|
|
kDebug() << "no formatter available for" << mime;
|
|
return;
|
|
}
|
|
|
|
// Ignore the modeline, as the modeline will be changed anyway
|
|
adaptEditorIndentationMode( doc, formatter, true );
|
|
|
|
bool has_selection = false;
|
|
KTextEditor::View *view = doc->textDocument()->activeView();
|
|
if (view && view->selection())
|
|
has_selection = true;
|
|
|
|
if (has_selection) {
|
|
QString original = view->selectionText();
|
|
|
|
QString output = formatter->formatSource(view->selectionText(), doc->url(), mime,
|
|
view->document()->text(KTextEditor::Range(KTextEditor::Cursor(0,0),view->selectionRange().start())),
|
|
view->document()->text(KTextEditor::Range(view->selectionRange().end(), view->document()->documentRange().end())));
|
|
|
|
//remove the final newline character, unless it should be there
|
|
if (!original.endsWith('\n') && output.endsWith('\n'))
|
|
output.resize(output.length() - 1);
|
|
//there was a selection, so only change the part of the text related to it
|
|
|
|
// We don't use KTextEditor::Document directly, because CodeRepresentation transparently works
|
|
// around a possible tab-replacement incompatibility between kate and kdevelop
|
|
DynamicCodeRepresentation::Ptr code = DynamicCodeRepresentation::Ptr::dynamicCast( KDevelop::createCodeRepresentation( IndexedString( doc->url() ) ) );
|
|
Q_ASSERT( code );
|
|
code->replace( view->selectionRange(), original, output );
|
|
} else {
|
|
formatDocument(doc, formatter, mime);
|
|
}
|
|
}
|
|
|
|
void SourceFormatterController::beautifyLine()
|
|
{
|
|
KDevelop::IDocumentController *docController = KDevelop::ICore::self()->documentController();
|
|
KDevelop::IDocument *doc = docController->activeDocument();
|
|
if (!doc || !doc->isTextDocument())
|
|
return;
|
|
KTextEditor::Document *tDoc = doc->textDocument();
|
|
if (!tDoc->activeView())
|
|
return;
|
|
// load the appropriate formatter
|
|
KMimeType::Ptr mime = KMimeType::findByUrl(doc->url());
|
|
ISourceFormatter *formatter = formatterForMimeType(mime);
|
|
if( !formatter ) {
|
|
kDebug() << "no formatter available for" << mime;
|
|
return;
|
|
}
|
|
|
|
const KTextEditor::Cursor cursor = tDoc->activeView()->cursorPosition();
|
|
const QString line = tDoc->line(cursor.line());
|
|
const QString prev = tDoc->text(KTextEditor::Range(0, 0, cursor.line(), 0));
|
|
const QString post = '\n' + tDoc->text(KTextEditor::Range(KTextEditor::Cursor(cursor.line() + 1, 0), tDoc->documentEnd()));
|
|
|
|
const QString formatted = formatter->formatSource(line, doc->url(), mime, prev, post);
|
|
|
|
// We don't use KTextEditor::Document directly, because CodeRepresentation transparently works
|
|
// around a possible tab-replacement incompatibility between kate and kdevelop
|
|
DynamicCodeRepresentation::Ptr code = DynamicCodeRepresentation::Ptr::dynamicCast( KDevelop::createCodeRepresentation( IndexedString( doc->url() ) ) );
|
|
Q_ASSERT( code );
|
|
code->replace( KTextEditor::Range(cursor.line(), 0, cursor.line(), line.length()), line, formatted );
|
|
|
|
// advance cursor one line
|
|
tDoc->activeView()->setCursorPosition(KTextEditor::Cursor(cursor.line() + 1, 0));
|
|
}
|
|
|
|
void SourceFormatterController::formatDocument(KDevelop::IDocument *doc, ISourceFormatter *formatter, const KMimeType::Ptr &mime)
|
|
{
|
|
// We don't use KTextEditor::Document directly, because CodeRepresentation transparently works
|
|
// around a possible tab-replacement incompatibility between kate and kdevelop
|
|
CodeRepresentation::Ptr code = KDevelop::createCodeRepresentation( IndexedString( doc->url() ) );
|
|
|
|
KTextEditor::Cursor cursor = doc->cursorPosition();
|
|
QString text = formatter->formatSource(code->text(), doc->url(), mime);
|
|
text = addModelineForCurrentLang(text, doc->url(), mime);
|
|
code->setText(text);
|
|
|
|
doc->setCursorPosition(cursor);
|
|
}
|
|
|
|
void SourceFormatterController::settingsChanged()
|
|
{
|
|
if( configuration().readEntry( SourceFormatterController::kateOverrideIndentationConfigKey, false ) )
|
|
foreach( KDevelop::IDocument* doc, ICore::self()->documentController()->openDocuments() )
|
|
adaptEditorIndentationMode( doc, formatterForUrl(doc->url()) );
|
|
}
|
|
|
|
/**
|
|
* Kate commands:
|
|
* Use spaces for indentation:
|
|
* "set-replace-tabs 1"
|
|
* Use tabs for indentation (eventually mixed):
|
|
* "set-replace-tabs 0"
|
|
* Indent width:
|
|
* "set-indent-width X"
|
|
* Tab width:
|
|
* "set-tab-width X"
|
|
* */
|
|
|
|
void SourceFormatterController::adaptEditorIndentationMode(KDevelop::IDocument *doc, ISourceFormatter *formatter, bool ignoreModeline )
|
|
{
|
|
if( !formatter || !configuration().readEntry( SourceFormatterController::kateOverrideIndentationConfigKey, false ) || !doc->isTextDocument() )
|
|
return;
|
|
|
|
KTextEditor::Document *textDoc = doc->textDocument();
|
|
kDebug() << "adapting mode for" << doc->url();
|
|
Q_ASSERT(textDoc);
|
|
|
|
QRegExp kateModelineWithNewline("\\s*\\n//\\s*kate:(.*)$");
|
|
|
|
// modelines should always take precedence
|
|
if( !ignoreModeline && kateModelineWithNewline.indexIn( textDoc->text() ) != -1 )
|
|
{
|
|
kDebug() << "ignoring because a kate modeline was found";
|
|
return;
|
|
}
|
|
|
|
ISourceFormatter::Indentation indentation = formatter->indentation(doc->url());
|
|
if(indentation.isValid())
|
|
{
|
|
struct CommandCaller {
|
|
CommandCaller(KTextEditor::Document* _doc) : doc(_doc), ci(qobject_cast<KTextEditor::CommandInterface*>(doc->editor())) {
|
|
Q_ASSERT(ci);
|
|
}
|
|
void operator()(QString cmd) {
|
|
KTextEditor::Command* command = ci->queryCommand( cmd );
|
|
Q_ASSERT(command);
|
|
QString msg;
|
|
kDebug() << "calling" << cmd;
|
|
if( !command->exec( doc->activeView(), cmd, msg ) )
|
|
kWarning() << "setting indentation width failed: " << msg;
|
|
}
|
|
|
|
KTextEditor::Document* doc;
|
|
KTextEditor::CommandInterface* ci;
|
|
} call(textDoc);
|
|
|
|
if( indentation.indentWidth ) // We know something about indentation-width
|
|
call( QString("set-indent-width %1").arg(indentation.indentWidth ) );
|
|
|
|
if( indentation.indentationTabWidth != 0 ) // We know something about tab-usage
|
|
{
|
|
call( QString("set-replace-tabs %1").arg( (indentation.indentationTabWidth == -1) ? 1 : 0 ) );
|
|
if( indentation.indentationTabWidth > 0 )
|
|
call( QString("set-tab-width %1").arg(indentation.indentationTabWidth ) );
|
|
}
|
|
}else{
|
|
kDebug() << "found no valid indentation";
|
|
}
|
|
}
|
|
|
|
void SourceFormatterController::formatFiles()
|
|
{
|
|
if (m_prjItems.isEmpty())
|
|
return;
|
|
|
|
//get a list of all files in this folder recursively
|
|
QList<KDevelop::ProjectFolderItem*> folders;
|
|
foreach(KDevelop::ProjectBaseItem *item, m_prjItems) {
|
|
if (!item)
|
|
continue;
|
|
if (item->folder())
|
|
folders.append(item->folder());
|
|
else if (item->file())
|
|
m_urls.append(item->file()->path().toUrl());
|
|
else if (item->target()) {
|
|
foreach(KDevelop::ProjectFileItem *f, item->fileList())
|
|
m_urls.append(f->path().toUrl());
|
|
}
|
|
}
|
|
|
|
while (!folders.isEmpty()) {
|
|
KDevelop::ProjectFolderItem *item = folders.takeFirst();
|
|
foreach(KDevelop::ProjectFolderItem *f, item->folderList())
|
|
folders.append(f);
|
|
foreach(KDevelop::ProjectTargetItem *f, item->targetList()) {
|
|
foreach(KDevelop::ProjectFileItem *child, f->fileList())
|
|
m_urls.append(child->path().toUrl());
|
|
}
|
|
foreach(KDevelop::ProjectFileItem *f, item->fileList())
|
|
m_urls.append(f->path().toUrl());
|
|
}
|
|
|
|
formatFiles(m_urls);
|
|
}
|
|
|
|
void SourceFormatterController::formatFiles(KUrl::List &list)
|
|
{
|
|
//! \todo IStatus
|
|
for (int fileCount = 0; fileCount < list.size(); fileCount++) {
|
|
// check mimetype
|
|
KMimeType::Ptr mime = KMimeType::findByUrl(list[fileCount]);
|
|
kDebug() << "Checking file " << list[fileCount].pathOrUrl() << " of mime type " << mime->name() << endl;
|
|
ISourceFormatter *formatter = formatterForMimeType(mime);
|
|
if (!formatter) // unsupported mime type
|
|
continue;
|
|
|
|
// if the file is opened in the editor, format the text in the editor without saving it
|
|
KDevelop::IDocumentController *docController = KDevelop::ICore::self()->documentController();
|
|
KDevelop::IDocument *doc = docController->documentForUrl(list[fileCount]);
|
|
if (doc) {
|
|
kDebug() << "Processing file " << list[fileCount].pathOrUrl() << "opened in editor" << endl;
|
|
formatDocument(doc, formatter, mime);
|
|
continue;
|
|
}
|
|
|
|
kDebug() << "Processing file " << list[fileCount].pathOrUrl() << endl;
|
|
QString tmpFile, output;
|
|
if (KIO::NetAccess::download(list[fileCount], tmpFile, 0)) {
|
|
QFile file(tmpFile);
|
|
// read file
|
|
if (file.open(QFile::ReadOnly)) {
|
|
QTextStream is(&file);
|
|
output = formatter->formatSource(is.readAll(), list[fileCount], mime);
|
|
file.close();
|
|
} else
|
|
KMessageBox::error(0, i18n("Unable to read %1", list[fileCount].prettyUrl()));
|
|
|
|
//write new content
|
|
if (file.open(QFile::WriteOnly | QIODevice::Truncate)) {
|
|
QTextStream os(&file);
|
|
os << addModelineForCurrentLang(output, list[fileCount], mime);
|
|
file.close();
|
|
} else
|
|
KMessageBox::error(0, i18n("Unable to write to %1", list[fileCount].prettyUrl()));
|
|
|
|
if (!KIO::NetAccess::upload(tmpFile, list[fileCount], 0))
|
|
KMessageBox::error(0, KIO::NetAccess::lastErrorString());
|
|
|
|
KIO::NetAccess::removeTempFile(tmpFile);
|
|
} else
|
|
KMessageBox::error(0, KIO::NetAccess::lastErrorString());
|
|
}
|
|
}
|
|
|
|
KDevelop::ContextMenuExtension SourceFormatterController::contextMenuExtension(KDevelop::Context* context)
|
|
{
|
|
KDevelop::ContextMenuExtension ext;
|
|
m_urls.clear();
|
|
m_prjItems.clear();
|
|
|
|
if (context->hasType(KDevelop::Context::EditorContext))
|
|
{
|
|
if(m_formatTextAction->isEnabled())
|
|
ext.addAction(KDevelop::ContextMenuExtension::EditGroup, m_formatTextAction);
|
|
} else if (context->hasType(KDevelop::Context::FileContext)) {
|
|
KDevelop::FileContext* filectx = dynamic_cast<KDevelop::FileContext*>(context);
|
|
m_urls = filectx->urls();
|
|
ext.addAction(KDevelop::ContextMenuExtension::EditGroup, m_formatFilesAction);
|
|
} else if (context->hasType(KDevelop::Context::CodeContext)) {
|
|
} else if (context->hasType(KDevelop::Context::ProjectItemContext)) {
|
|
KDevelop::ProjectItemContext* prjctx = dynamic_cast<KDevelop::ProjectItemContext*>(context);
|
|
m_prjItems = prjctx->items();
|
|
if ( !m_prjItems.isEmpty() ) {
|
|
ext.addAction(KDevelop::ContextMenuExtension::ExtensionGroup, m_formatFilesAction);
|
|
}
|
|
}
|
|
return ext;
|
|
}
|
|
|
|
SourceFormatterStyle SourceFormatterController::styleForMimeType( const KMimeType::Ptr& mime )
|
|
{
|
|
QStringList formatter = configuration().readEntry( mime->name(), "" ).split( "||", QString::SkipEmptyParts );
|
|
if( formatter.count() == 2 )
|
|
{
|
|
SourceFormatterStyle s( formatter.at( 1 ) );
|
|
KConfigGroup fmtgrp = configuration().group( formatter.at(0) );
|
|
if( fmtgrp.hasGroup( formatter.at(1) ) ) {
|
|
KConfigGroup stylegrp = fmtgrp.group( formatter.at(1) );
|
|
populateStyleFromConfigGroup(&s, stylegrp);
|
|
}
|
|
return s;
|
|
}
|
|
return SourceFormatterStyle();
|
|
}
|
|
|
|
void SourceFormatterController::disableSourceFormatting(bool disable)
|
|
{
|
|
m_enabled = !disable;
|
|
}
|
|
|
|
bool SourceFormatterController::sourceFormattingEnabled()
|
|
{
|
|
return m_enabled;
|
|
}
|
|
|
|
/*
|
|
Code copied from source formatter plugin, unused currently but shouldn't be just thrown away
|
|
QString SourceFormatterPlugin::replaceSpacesWithTab(const QString &input, ISourceFormatter *formatter)
|
|
{
|
|
QString output(input);
|
|
int wsCount = formatter->indentationLength();
|
|
ISourceFormatter::IndentationType type = formatter->indentationType();
|
|
|
|
if (type == ISourceFormatter::IndentWithTabs) {
|
|
// tabs and wsCount spaces to be a tab
|
|
QString replace;
|
|
for (int i = 0; i < wsCount;i++)
|
|
replace += ' ';
|
|
|
|
output = output.replace(replace, QChar('\t'));
|
|
// input = input.remove(' ');
|
|
} else if (type == ISourceFormatter::IndentWithSpacesAndConvertTabs) {
|
|
//convert tabs to spaces
|
|
QString replace;
|
|
for (int i = 0;i < wsCount;i++)
|
|
replace += ' ';
|
|
|
|
output = output.replace(QChar('\t'), replace);
|
|
}
|
|
return output;
|
|
}
|
|
|
|
QString SourceFormatterPlugin::addIndentation(QString input, const QString indentWith)
|
|
{
|
|
QString output;
|
|
QTextStream os(&output, QIODevice::WriteOnly);
|
|
QTextStream is(&input, QIODevice::ReadOnly);
|
|
|
|
while (!is.atEnd())
|
|
os << indentWith << is.readLine() << endl;
|
|
return output;
|
|
}
|
|
*/
|
|
|
|
}
|
|
|
|
#include "moc_sourceformattercontroller.cpp"
|
|
|
|
// kate: indent-mode cstyle; space-indent off; tab-width 4;
|
|
|