diff --git a/shell/CMakeLists.txt b/shell/CMakeLists.txt --- a/shell/CMakeLists.txt +++ b/shell/CMakeLists.txt @@ -36,6 +36,7 @@ sessionchooserdialog.cpp savedialog.cpp sourceformattercontroller.cpp + sourceformatterjob.cpp completionsettings.cpp openprojectpage.cpp openprojectdialog.cpp diff --git a/shell/sourceformattercontroller.h b/shell/sourceformattercontroller.h --- a/shell/sourceformattercontroller.h +++ b/shell/sourceformattercontroller.h @@ -80,6 +80,9 @@ class KDEVPLATFORMSHELL_EXPORT SourceFormatterController : public ISourceFormatterController, public KXMLGUIClient { Q_OBJECT + + friend class SourceFormatterJob; + public: static QString kateModeLineConfigKey(); static QString kateOverrideIndentationConfigKey(); @@ -149,7 +152,6 @@ void formatDocument(KDevelop::IDocument* doc, ISourceFormatter* formatter, const QMimeType& mime); // Adapts the mode of the editor regarding indentation-style void adaptEditorIndentationMode(KTextEditor::Document* doc, KDevelop::ISourceFormatter* formatter, bool ignoreModeline = false); - void formatFiles(QList &list); // GUI actions QAction* m_formatTextAction; QAction* m_formatFilesAction; diff --git a/shell/sourceformattercontroller.cpp b/shell/sourceformattercontroller.cpp --- a/shell/sourceformattercontroller.cpp +++ b/shell/sourceformattercontroller.cpp @@ -43,6 +43,7 @@ #include #include #include +#include #include #include #include @@ -54,6 +55,7 @@ #include "core.h" #include "debug.h" #include "plugincontroller.h" +#include "sourceformatterjob.h" namespace { @@ -565,41 +567,9 @@ msgBox.exec(); if (msgBox.clickedButton() == okButton) { - formatFiles(m_urls); - } -} - -void SourceFormatterController::formatFiles(QList &list) -{ - //! \todo IStatus - for (int fileCount = 0; fileCount < list.size(); fileCount++) { - // check mimetype - QMimeType mime = QMimeDatabase().mimeTypeForUrl(list[fileCount]); - qCDebug(SHELL) << "Checking file " << list[fileCount] << " 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) { - qCDebug(SHELL) << "Processing file " << list[fileCount] << "opened in editor" << endl; - formatDocument(doc, formatter, mime); - continue; - } - - qCDebug(SHELL) << "Processing file " << list[fileCount] << endl; - KIO::StoredTransferJob *job = KIO::storedGet(list[fileCount]); - if (job->exec()) { - QString text = QString::fromLocal8Bit(job->data()); - text = formatter->formatSource(text, list[fileCount], mime); - text = addModelineForCurrentLang(text, list[fileCount], mime).toUtf8(); - job = KIO::storedPut(text.toLocal8Bit(), list[fileCount], -1, KIO::Overwrite); - if (!job->exec()) - KMessageBox::error(nullptr, job->errorString()); - } else - KMessageBox::error(nullptr, job->errorString()); + auto formatterJob = new SourceFormatterJob(this); + formatterJob->setFiles(m_urls); + ICore::self()->runController()->registerJob(formatterJob); } } diff --git a/shell/sourceformatterjob.h b/shell/sourceformatterjob.h new file mode 100644 --- /dev/null +++ b/shell/sourceformatterjob.h @@ -0,0 +1,85 @@ +/* + * This file is part of KDevelop + * + * Copyright 2017 Friedrich W. H. Kossebau + * + * 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. + */ + +#ifndef KDEVPLATFORM_SOURCEFORMATTERJOB_H +#define KDEVPLATFORM_SOURCEFORMATTERJOB_H + +#include +#include + +#include + +#include + + +namespace KDevelop +{ +class SourceFormatterController; + + +class SourceFormatterJob : public KJob, public IStatus +{ + Q_OBJECT + Q_INTERFACES( KDevelop::IStatus ) + +public: + explicit SourceFormatterJob(SourceFormatterController* sourceFormatterController); + +public: // KJob API + void start() override; + +public: // KDevelop::IStatus API + QString statusName() const override; + +public: + void setFiles(const QList& fileList); + +protected: // KJob API + bool doKill() override; + +Q_SIGNALS: // KDevelop::IStatus API + void clearMessage(KDevelop::IStatus* status) override; + void showMessage(KDevelop::IStatus* status, const QString& message, int timeout = 0) override; + void showErrorMessage(const QString& message, int timeout = 0) override; + void hideProgress(KDevelop::IStatus* status) override; + void showProgress(KDevelop::IStatus* status, int minimum, int maximum, int value) override; + +private: + Q_INVOKABLE void doWork(); + + void formatFile(const QUrl& url); + +private: + SourceFormatterController* m_sourceFormatterController; + + enum { + WorkIdle, + WorkFormat, + WorkCancelled + } m_workState; + + QList m_fileList; + int m_fileIndex; +}; + +} + +#endif diff --git a/shell/sourceformatterjob.cpp b/shell/sourceformatterjob.cpp new file mode 100644 --- /dev/null +++ b/shell/sourceformatterjob.cpp @@ -0,0 +1,153 @@ +/* + * This file is part of KDevelop + * + * Copyright (C) 2008 Cédric Pasteur + * Copyright 2009 Andreas Pakulat + * Copyright 2017 Friedrich W. H. Kossebau + * + * 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 "sourceformatterjob.h" + +#include "sourceformattercontroller.h" + +#include + +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + +using namespace KDevelop; + + +SourceFormatterJob::SourceFormatterJob(SourceFormatterController* sourceFormatterController) + : KJob(sourceFormatterController) + , m_sourceFormatterController(sourceFormatterController) + , m_workState(WorkIdle) + , m_fileIndex(0) +{ + setCapabilities(Killable); + // set name for job listing + setObjectName(i18n("Reformatting")); + + KDevelop::ICore::self()->uiController()->registerStatus(this); + + connect(this, &SourceFormatterJob::finished, this, [this]() { + emit hideProgress(this); + }); +} + +QString SourceFormatterJob::statusName() const +{ + return i18n("Reformat Files"); +} + +void SourceFormatterJob::doWork() +{ + // TODO: consider to use ExecuteCompositeJob, with every file a separate subjob + switch (m_workState) { + case WorkIdle: + m_workState = WorkFormat; + m_fileIndex = 0; + emit showProgress(this, 0, 0, 0); + emit showMessage(this, i18np("Reformatting one file", + "Reformatting %1 files", + m_fileList.length())); + + QMetaObject::invokeMethod(this, "doWork", Qt::QueuedConnection); + break; + case WorkFormat: + if (m_fileIndex < m_fileList.length()) { + emit showProgress(this, 0, m_fileList.length(), m_fileIndex); + formatFile(m_fileList[m_fileIndex]); + + // trigger formatting of next file + ++m_fileIndex; + QMetaObject::invokeMethod(this, "doWork", Qt::QueuedConnection); + } else { + m_workState = WorkIdle; + emitResult(); + } + break; + case WorkCancelled: + break; + } +} + +void SourceFormatterJob::start() +{ + if (m_workState != WorkIdle) + return; + + m_workState = WorkIdle; + + QMetaObject::invokeMethod(this, "doWork", Qt::QueuedConnection); +} + +bool SourceFormatterJob::doKill() +{ + m_workState = WorkCancelled; + return true; +} + +void SourceFormatterJob::setFiles(const QList& fileList) +{ + m_fileList = fileList; +} + +void SourceFormatterJob::formatFile(const QUrl& url) +{ + // check mimetype + QMimeType mime = QMimeDatabase().mimeTypeForUrl(url); + qCDebug(SHELL) << "Checking file " << url << " of mime type " << mime.name() << endl; + auto formatter = m_sourceFormatterController->formatterForMimeType(mime); + if (!formatter) // unsupported mime type + return; + + // if the file is opened in the editor, format the text in the editor without saving it + auto doc = ICore::self()->documentController()->documentForUrl(url); + if (doc) { + qCDebug(SHELL) << "Processing file " << url << "opened in editor" << endl; + m_sourceFormatterController->formatDocument(doc, formatter, mime); + return; + } + + qCDebug(SHELL) << "Processing file " << url << endl; + auto getJob = KIO::storedGet(url); + // TODO: make also async and use start() and integrate using setError and setErrorString. + if (getJob->exec()) { + // TODO: really fromLocal8Bit/toLocal8Bit? no encoding detection? added in b8062f736a2bf2eec098af531a7fda6ebcdc7cde + QString text = QString::fromLocal8Bit(getJob->data()); + text = formatter->formatSource(text, url, mime); + text = m_sourceFormatterController->addModelineForCurrentLang(text, url, mime).toUtf8(); + + auto putJob = KIO::storedPut(text.toLocal8Bit(), url, -1, KIO::Overwrite); + // see getJob + if (!putJob->exec()) + // TODO: integrate with job error reporting, use showErrorMessage? + KMessageBox::error(nullptr, putJob->errorString()); + } else + KMessageBox::error(nullptr, getJob->errorString()); +}