Commit 4bea049c authored by Jarek Kobus's avatar Jarek Kobus

VcsBase: Create common base diff editor controller

Reuse it in subversion and git plugins.
It makes subversion diff more asynchronous than before.
Make VcsBase plugin dependand on DiffEditor plugin.

Change-Id: Iafea2941b890a95a269362e022af2dc03cdea550
Reviewed-by: Tobias Hunger's avatarTobias Hunger <tobias.hunger@qt.io>
parent 0a2590e7
This diff is collapsed.
......@@ -30,6 +30,7 @@
#include <vcsbase/vcscommand.h>
#include <vcsbase/vcsbaseconstants.h>
#include <vcsbase/vcsbasediffeditorcontroller.h>
#include <vcsbase/vcsbaseeditor.h>
#include <vcsbase/vcsbaseeditorconfig.h>
#include <vcsbase/vcsbaseplugin.h>
......@@ -167,46 +168,40 @@ QStringList SubversionClient::escapeFiles(const QStringList &files)
return Utils::transform(files, &SubversionClient::escapeFile);
}
class DiffController : public DiffEditorController
class SubversionDiffEditorController : public VcsBaseDiffEditorController
{
Q_OBJECT
public:
DiffController(IDocument *document, const SubversionClient *client, const QString &directory);
SubversionDiffEditorController(IDocument *document,
const QString &workingDirectory);
void setFilesList(const QStringList &filesList);
void setChangeNumber(int changeNumber);
protected:
void reload() override;
private slots:
void slotTextualDiffOutputReceived(const QString &contents);
void processCommandOutput(const QString &output) override;
private:
QString getDescription() const;
void postCollectTextualDiffOutput();
QProcessEnvironment processEnvironment() const;
void requestDescription();
void requestDiff();
const SubversionClient *m_client;
QString m_workingDirectory;
enum State { Idle, GettingDescription, GettingDiff };
State m_state;
QStringList m_filesList;
int m_changeNumber = 0;
};
DiffController::DiffController(IDocument *document, const SubversionClient *client, const QString &directory) :
DiffEditorController(document),
m_client(client),
m_workingDirectory(directory)
SubversionDiffEditorController::SubversionDiffEditorController(
IDocument *document,
const QString &workingDirectory)
: VcsBaseDiffEditorController(document, SubversionPlugin::instance()->client(), workingDirectory)
, m_state(Idle)
{
forceContextLineCount(3); // SVN can not change that when using internal diff
}
QProcessEnvironment DiffController::processEnvironment() const
{
return m_client->processEnvironment();
}
void DiffController::setFilesList(const QStringList &filesList)
void SubversionDiffEditorController::setFilesList(const QStringList &filesList)
{
if (isReloading())
return;
......@@ -214,7 +209,7 @@ void DiffController::setFilesList(const QStringList &filesList)
m_filesList = SubversionClient::escapeFiles(filesList);
}
void DiffController::setChangeNumber(int changeNumber)
void SubversionDiffEditorController::setChangeNumber(int changeNumber)
{
if (isReloading())
return;
......@@ -222,33 +217,24 @@ void DiffController::setChangeNumber(int changeNumber)
m_changeNumber = qMax(changeNumber, 0);
}
QString DiffController::getDescription() const
void SubversionDiffEditorController::requestDescription()
{
m_state = GettingDescription;
QStringList args(QLatin1String("log"));
args << SubversionClient::addAuthenticationOptions(m_client->settings());
args << SubversionClient::addAuthenticationOptions(client()->settings());
args << QLatin1String("-r");
args << QString::number(m_changeNumber);
const SubversionResponse logResponse =
SubversionPlugin::instance()->runSvn(m_workingDirectory, args,
m_client->vcsTimeoutS(),
VcsCommand::SshPasswordPrompt);
if (logResponse.error)
return QString();
return logResponse.stdOut;
runCommand(QList<QStringList>() << args, VcsCommand::SshPasswordPrompt);
}
void DiffController::postCollectTextualDiffOutput()
void SubversionDiffEditorController::requestDiff()
{
auto command = new VcsCommand(m_workingDirectory, processEnvironment());
command->setCodec(EditorManager::defaultTextCodec());
connect(command, &VcsCommand::stdOutText, this, &DiffController::slotTextualDiffOutputReceived);
// command->addFlags(diffExecutionFlags());
m_state = GettingDiff;
QStringList args;
args << QLatin1String("diff");
args << m_client->addAuthenticationOptions(m_client->settings());
args << SubversionClient::addAuthenticationOptions(client()->settings());
args << QLatin1String("--internal-diff");
if (ignoreWhitespace())
args << QLatin1String("-x") << QLatin1String("-uw");
......@@ -258,40 +244,43 @@ void DiffController::postCollectTextualDiffOutput()
} else {
args << m_filesList;
}
command->addJob(m_client->vcsBinary(), args, m_client->vcsTimeoutS());
command->execute();
runCommand(QList<QStringList>() << args, 0);
}
void DiffController::slotTextualDiffOutputReceived(const QString &contents)
void SubversionDiffEditorController::reload()
{
bool ok;
QList<FileData> fileDataList
= DiffUtils::readPatch(contents, &ok);
setDiffFiles(fileDataList, m_workingDirectory);
reloadFinished(true);
if (m_changeNumber) {
requestDescription();
} else {
requestDiff();
}
}
void DiffController::reload()
void SubversionDiffEditorController::processCommandOutput(const QString &output)
{
const QString description = m_changeNumber
? getDescription() : QString();
postCollectTextualDiffOutput();
setDescription(description);
QTC_ASSERT(m_state != Idle, return);
if (m_state == GettingDescription) {
setDescription(output);
requestDiff();
} else if (m_state == GettingDiff) {
m_state = Idle;
VcsBaseDiffEditorController::processCommandOutput(output);
}
}
DiffController *SubversionClient::findOrCreateDiffEditor(const QString &documentId,
SubversionDiffEditorController *SubversionClient::findOrCreateDiffEditor(const QString &documentId,
const QString &source,
const QString &title,
const QString &workingDirectory) const
{
IDocument *document = DiffEditorController::findOrCreateDocument(documentId, title);
DiffController *controller = qobject_cast<DiffController *>(
SubversionDiffEditorController *controller = qobject_cast<SubversionDiffEditorController *>(
DiffEditorController::controller(document));
if (!controller)
controller = new DiffController(document, this, workingDirectory);
controller = new SubversionDiffEditorController(document, workingDirectory);
VcsBasePlugin::setSource(document, source);
EditorManager::activateEditorForDocument(document);
return controller;
}
......@@ -304,7 +293,7 @@ void SubversionClient::diff(const QString &workingDirectory, const QStringList &
+ QLatin1String(".Diff.") + VcsBaseEditor::getTitleId(workingDirectory, files);
const QString title = vcsEditorTitle(vcsCmdString, documentId);
DiffController *controller = findOrCreateDiffEditor(documentId, workingDirectory, title,
SubversionDiffEditorController *controller = findOrCreateDiffEditor(documentId, workingDirectory, title,
workingDirectory);
controller->setFilesList(files);
controller->requestReload();
......@@ -335,7 +324,7 @@ void SubversionClient::describe(const QString &workingDirectory, int changeNumbe
QStringList(),
QString::number(changeNumber));
DiffController *controller = findOrCreateDiffEditor(documentId, workingDirectory, title, workingDirectory);
SubversionDiffEditorController *controller = findOrCreateDiffEditor(documentId, workingDirectory, title, workingDirectory);
controller->setChangeNumber(changeNumber);
controller->requestReload();
}
......
......@@ -35,7 +35,7 @@ namespace Subversion {
namespace Internal {
class SubversionSettings;
class DiffController;
class SubversionDiffEditorController;
class SubversionClient : public VcsBase::VcsBaseClient
{
......@@ -78,7 +78,7 @@ protected:
Core::Id vcsEditorKind(VcsCommandTag cmd) const override;
private:
DiffController *findOrCreateDiffEditor(const QString &documentId, const QString &source,
SubversionDiffEditorController *findOrCreateDiffEditor(const QString &documentId, const QString &source,
const QString &title, const QString &workingDirectory) const;
mutable Utils::FileName m_svnVersionBinary;
......
......@@ -27,7 +27,8 @@ HEADERS += vcsbase_global.h \
vcsbaseclientsettings.h \
vcsbaseeditorconfig.h \
submitfieldwidget.h \
submiteditorwidget.h
submiteditorwidget.h \
vcsbasediffeditorcontroller.h
SOURCES += vcsplugin.cpp \
vcsbaseplugin.cpp \
......@@ -54,7 +55,8 @@ SOURCES += vcsplugin.cpp \
vcsbaseclientsettings.cpp \
vcsbaseeditorconfig.cpp \
submitfieldwidget.cpp \
submiteditorwidget.cpp
submiteditorwidget.cpp \
vcsbasediffeditorcontroller.cpp
RESOURCES += vcsbase.qrc
......
......@@ -12,6 +12,7 @@ QtcPlugin {
Depends { name: "TextEditor" }
Depends { name: "ProjectExplorer" }
Depends { name: "CppTools" }
Depends { name: "DiffEditor" }
pluginRecommends: [
"CodePaster"
......@@ -53,6 +54,8 @@ QtcPlugin {
"vcsbaseclientsettings.cpp",
"vcsbaseclientsettings.h",
"vcsbaseconstants.h",
"vcsbasediffeditorcontroller.cpp",
"vcsbasediffeditorcontroller.h",
"vcsbaseeditor.cpp",
"vcsbaseeditor.h",
"vcsbaseeditorconfig.cpp",
......
......@@ -8,6 +8,7 @@ QTC_PLUGIN_DEPENDS += \
coreplugin \
texteditor \
projectexplorer \
cpptools
cpptools \
diffeditor
QTC_PLUGIN_RECOMMENDS += \
cpaster
/****************************************************************************
**
** Copyright (C) 2017 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include "vcsbasediffeditorcontroller.h"
#include "vcsbaseclient.h"
#include "vcscommand.h"
#include <coreplugin/editormanager/editormanager.h>
#include <coreplugin/progressmanager/progressmanager.h>
#include <diffeditor/diffutils.h>
#include <utils/qtcassert.h>
#include <utils/runextensions.h>
#include <QPointer>
using namespace DiffEditor;
using namespace Core;
namespace VcsBase {
static void readPatch(QFutureInterface<QList<FileData>> &futureInterface,
const QString &patch)
{
bool ok;
const QList<FileData> &fileDataList = DiffUtils::readPatch(patch, &ok);
futureInterface.reportResult(fileDataList);
}
class VcsBaseDiffEditorControllerPrivate
{
public:
VcsBaseDiffEditorControllerPrivate(VcsBaseDiffEditorController *controller,
VcsBaseClientImpl *client,
const QString &workingDirectory);
~VcsBaseDiffEditorControllerPrivate();
void processingFinished();
void processDiff(const QString &patch);
void cancelReload();
void commandFinished(bool success);
VcsBaseDiffEditorController *q;
VcsBaseClientImpl *m_client;
const QString m_directory;
QString m_startupFile;
QString m_output;
QPointer<VcsCommand> m_command;
QFutureWatcher<QList<FileData>> m_processWatcher;
};
VcsBaseDiffEditorControllerPrivate::VcsBaseDiffEditorControllerPrivate(VcsBaseDiffEditorController *controller,
VcsBaseClientImpl *client,
const QString &workingDirectory)
: q(controller)
, m_client(client)
, m_directory(workingDirectory)
{
QObject::connect(&m_processWatcher, &QFutureWatcher<QList<FileData>>::finished, q,
[this] () { processingFinished(); });
}
VcsBaseDiffEditorControllerPrivate::~VcsBaseDiffEditorControllerPrivate()
{
cancelReload();
}
void VcsBaseDiffEditorControllerPrivate::processingFinished()
{
const QList<FileData> fileDataList = m_processWatcher.future().result();
q->setDiffFiles(fileDataList, q->workingDirectory(), q->startupFile());
q->reloadFinished(true);
}
void VcsBaseDiffEditorControllerPrivate::processDiff(const QString &patch)
{
m_processWatcher.setFuture(Utils::runAsync(&readPatch, patch));
ProgressManager::addTask(m_processWatcher.future(),
q->tr("Processing diff"), "DiffEditor");
}
void VcsBaseDiffEditorControllerPrivate::cancelReload()
{
if (m_command) {
m_command->disconnect();
m_command->cancel();
m_command.clear();
}
if (m_processWatcher.future().isRunning()) {
m_processWatcher.future().cancel();
m_processWatcher.setFuture(QFuture<QList<FileData>>());
}
m_output = QString();
}
void VcsBaseDiffEditorControllerPrivate::commandFinished(bool success)
{
if (m_command)
m_command.clear();
if (!success) {
cancelReload();
q->reloadFinished(success);
return;
}
q->processCommandOutput(m_output);
}
/////////////////////
VcsBaseDiffEditorController::VcsBaseDiffEditorController(IDocument *document,
VcsBaseClientImpl *client,
const QString &workingDirectory)
: DiffEditorController(document)
, d(new VcsBaseDiffEditorControllerPrivate(this, client, workingDirectory))
{
}
VcsBaseDiffEditorController::~VcsBaseDiffEditorController()
{
delete d;
}
void VcsBaseDiffEditorController::runCommand(const QList<QStringList> &args, unsigned flags, QTextCodec *codec)
{
d->cancelReload();
d->m_command = new VcsCommand(workingDirectory(), d->m_client->processEnvironment());
d->m_command->setCodec(codec ? codec : EditorManager::defaultTextCodec());
connect(d->m_command.data(), &VcsCommand::stdOutText, this,
[this] (const QString &output) { d->m_output = output; });
connect(d->m_command.data(), &VcsCommand::finished, this,
[this] (bool success) { d->commandFinished(success); });
d->m_command->addFlags(flags);
for (const QStringList &arg : args) {
QTC_ASSERT(!arg.isEmpty(), continue);
d->m_command->addJob(d->m_client->vcsBinary(), arg, d->m_client->vcsTimeoutS());
}
d->m_command->execute();
}
void VcsBaseDiffEditorController::processCommandOutput(const QString &output)
{
d->processDiff(output);
}
VcsBaseClientImpl *VcsBaseDiffEditorController::client() const
{
return d->m_client;
}
QString VcsBaseDiffEditorController::workingDirectory() const
{
return d->m_directory;
}
void VcsBaseDiffEditorController::setStartupFile(const QString &startupFile)
{
d->m_startupFile = startupFile;
}
QString VcsBaseDiffEditorController::startupFile() const
{
return d->m_startupFile;
}
} // namespace VcsBase
/****************************************************************************
**
** Copyright (C) 2017 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
#include "vcsbase_global.h"
#include <diffeditor/diffeditorcontroller.h>
namespace Core { class IDocument; }
namespace VcsBase {
class VcsBaseClientImpl;
class VcsBaseDiffEditorControllerPrivate;
class VCSBASE_EXPORT VcsBaseDiffEditorController : public DiffEditor::DiffEditorController
{
Q_OBJECT
public:
VcsBaseDiffEditorController(Core::IDocument *document,
VcsBaseClientImpl *client,
const QString &workingDirectory);
~VcsBaseDiffEditorController();
protected:
void runCommand(const QList<QStringList> &args, unsigned flags, QTextCodec *codec = nullptr);
virtual void processCommandOutput(const QString &output);
VcsBaseClientImpl *client() const;
QString workingDirectory() const;
void setStartupFile(const QString &startupFile);
QString startupFile() const;
private:
friend class VcsBaseDiffEditorControllerPrivate;
VcsBaseDiffEditorControllerPrivate *d;
};
} //namespace VcsBase
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment