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 <tobias.hunger@qt.io>
This commit is contained in:
Jarek Kobus
2017-06-30 14:50:28 +02:00
parent 0a2590e7be
commit 4bea049c45
8 changed files with 341 additions and 197 deletions

View File

@@ -43,7 +43,6 @@
#include <coreplugin/idocument.h> #include <coreplugin/idocument.h>
#include <coreplugin/iversioncontrol.h> #include <coreplugin/iversioncontrol.h>
#include <coreplugin/vcsmanager.h> #include <coreplugin/vcsmanager.h>
#include <coreplugin/progressmanager/progressmanager.h>
#include <utils/algorithm.h> #include <utils/algorithm.h>
#include <utils/asconst.h> #include <utils/asconst.h>
@@ -54,9 +53,9 @@
#include <utils/qtcprocess.h> #include <utils/qtcprocess.h>
#include <utils/synchronousprocess.h> #include <utils/synchronousprocess.h>
#include <utils/temporaryfile.h> #include <utils/temporaryfile.h>
#include <utils/runextensions.h>
#include <vcsbase/submitfilemodel.h> #include <vcsbase/submitfilemodel.h>
#include <vcsbase/vcsbasediffeditorcontroller.h>
#include <vcsbase/vcsbaseeditor.h> #include <vcsbase/vcsbaseeditor.h>
#include <vcsbase/vcsbaseeditorconfig.h> #include <vcsbase/vcsbaseeditorconfig.h>
#include <vcsbase/vcsbaseplugin.h> #include <vcsbase/vcsbaseplugin.h>
@@ -112,138 +111,31 @@ const unsigned silentFlags = unsigned(VcsCommand::SuppressCommandLogging
| VcsCommand::SuppressStdErr | VcsCommand::SuppressStdErr
| VcsCommand::SuppressFailMessage); | VcsCommand::SuppressFailMessage);
static void readPatch(QFutureInterface<QList<FileData>> &futureInterface, class GitDiffEditorController : public VcsBaseDiffEditorController
const QString &patch)
{
bool ok;
const QList<FileData> &fileDataList = DiffUtils::readPatch(patch, &ok);
futureInterface.reportResult(fileDataList);
}
/////////////////////////////////////
class BaseController : public DiffEditorController
{ {
Q_OBJECT Q_OBJECT
public: public:
BaseController(IDocument *document, const QString &dir); GitDiffEditorController(IDocument *document, const QString &workingDirectory);
~BaseController();
protected: protected:
void runCommand(const QList<QStringList> &args, QTextCodec *codec = 0); void runCommand(const QList<QStringList> &args, QTextCodec *codec = nullptr);
virtual void processCommandOutput(const QString &output);
QStringList addConfigurationArguments(const QStringList &args) const; QStringList addConfigurationArguments(const QStringList &args) const;
QStringList addHeadWhenCommandInProgress() const; QStringList addHeadWhenCommandInProgress() const;
void setStartupFile(const QString &startupFile) { m_startupFile = startupFile; }
QString startupFile() const { return m_startupFile; }
QString directory() const { return m_directory; }
private:
void processDiff(const QString &patch);
void storeOutput(const QString &output);
void cancelReload();
void commandFinished(bool success);
void processingFinished();
const QString m_directory;
QString m_startupFile;
QString m_output;
QPointer<VcsCommand> m_command;
QFutureWatcher<QList<FileData>> m_processWatcher;
}; };
BaseController::BaseController(IDocument *document, const QString &dir) : GitDiffEditorController::GitDiffEditorController(IDocument *document, const QString &workingDirectory) :
DiffEditorController(document), VcsBaseDiffEditorController(document, GitPlugin::client(), workingDirectory)
m_directory(dir),
m_command(0)
{ {
connect(&m_processWatcher, &QFutureWatcher<QList<FileData>>::finished,
this, &BaseController::processingFinished);
} }
BaseController::~BaseController() void GitDiffEditorController::runCommand(const QList<QStringList> &args, QTextCodec *codec)
{ {
cancelReload(); VcsBaseDiffEditorController::runCommand(args, diffExecutionFlags(), codec);
} }
void BaseController::cancelReload() QStringList GitDiffEditorController::addConfigurationArguments(const QStringList &args) const
{
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 BaseController::commandFinished(bool success)
{
if (m_command)
m_command.clear();
if (!success) {
cancelReload();
reloadFinished(success);
return;
}
processCommandOutput(m_output);
}
void BaseController::runCommand(const QList<QStringList> &args, QTextCodec *codec)
{
cancelReload();
m_command = new VcsCommand(directory(), GitPlugin::client()->processEnvironment());
m_command->setCodec(codec ? codec : EditorManager::defaultTextCodec());
connect(m_command.data(), &VcsCommand::stdOutText, this, &BaseController::storeOutput);
connect(m_command.data(), &VcsCommand::finished, this, &BaseController::commandFinished);
m_command->addFlags(diffExecutionFlags());
for (const QStringList &arg : args) {
QTC_ASSERT(!arg.isEmpty(), continue);
m_command->addJob(GitPlugin::client()->vcsBinary(), arg, GitPlugin::client()->vcsTimeoutS());
}
m_command->execute();
}
void BaseController::storeOutput(const QString &output)
{
m_output = output;
}
void BaseController::processCommandOutput(const QString &output)
{
processDiff(output);
}
void BaseController::processDiff(const QString &patch)
{
m_processWatcher.setFuture(Utils::runAsync(&readPatch, patch));
Core::ProgressManager::addTask(m_processWatcher.future(),
tr("Processing diff"), "DiffEditor");
}
void BaseController::processingFinished()
{
const QList<FileData> fileDataList = m_processWatcher.future().result();
setDiffFiles(fileDataList, directory(), startupFile());
reloadFinished(true);
}
QStringList BaseController::addConfigurationArguments(const QStringList &args) const
{ {
QTC_ASSERT(!args.isEmpty(), return args); QTC_ASSERT(!args.isEmpty(), return args);
@@ -261,23 +153,23 @@ QStringList BaseController::addConfigurationArguments(const QStringList &args) c
return realArgs; return realArgs;
} }
QStringList BaseController::addHeadWhenCommandInProgress() const QStringList GitDiffEditorController::addHeadWhenCommandInProgress() const
{ {
// This is workaround for lack of support for merge commits and resolving conflicts, // This is workaround for lack of support for merge commits and resolving conflicts,
// we compare the current state of working tree to the HEAD of current branch // we compare the current state of working tree to the HEAD of current branch
// instead of showing unsupported combined diff format. // instead of showing unsupported combined diff format.
GitClient::CommandInProgress commandInProgress = GitPlugin::client()->checkCommandInProgress(directory()); GitClient::CommandInProgress commandInProgress = GitPlugin::client()->checkCommandInProgress(workingDirectory());
if (commandInProgress != GitClient::NoCommand) if (commandInProgress != GitClient::NoCommand)
return {HEAD}; return {HEAD};
return QStringList(); return QStringList();
} }
class RepositoryDiffController : public BaseController class RepositoryDiffController : public GitDiffEditorController
{ {
Q_OBJECT Q_OBJECT
public: public:
RepositoryDiffController(IDocument *document, const QString &dir) : RepositoryDiffController(IDocument *document, const QString &dir) :
BaseController(document, dir) GitDiffEditorController(document, dir)
{ } { }
void reload() override; void reload() override;
@@ -290,12 +182,12 @@ void RepositoryDiffController::reload()
runCommand(QList<QStringList>() << addConfigurationArguments(args)); runCommand(QList<QStringList>() << addConfigurationArguments(args));
} }
class FileDiffController : public BaseController class FileDiffController : public GitDiffEditorController
{ {
Q_OBJECT Q_OBJECT
public: public:
FileDiffController(IDocument *document, const QString &dir, const QString &fileName) : FileDiffController(IDocument *document, const QString &dir, const QString &fileName) :
BaseController(document, dir), GitDiffEditorController(document, dir),
m_fileName(fileName) m_fileName(fileName)
{ } { }
@@ -314,13 +206,13 @@ void FileDiffController::reload()
runCommand(QList<QStringList>() << addConfigurationArguments(args)); runCommand(QList<QStringList>() << addConfigurationArguments(args));
} }
class FileListDiffController : public BaseController class FileListDiffController : public GitDiffEditorController
{ {
Q_OBJECT Q_OBJECT
public: public:
FileListDiffController(IDocument *document, const QString &dir, FileListDiffController(IDocument *document, const QString &dir,
const QStringList &stagedFiles, const QStringList &unstagedFiles) : const QStringList &stagedFiles, const QStringList &unstagedFiles) :
BaseController(document, dir), GitDiffEditorController(document, dir),
m_stagedFiles(stagedFiles), m_stagedFiles(stagedFiles),
m_unstagedFiles(unstagedFiles) m_unstagedFiles(unstagedFiles)
{ } { }
@@ -351,13 +243,13 @@ void FileListDiffController::reload()
runCommand(argLists); runCommand(argLists);
} }
class ProjectDiffController : public BaseController class ProjectDiffController : public GitDiffEditorController
{ {
Q_OBJECT Q_OBJECT
public: public:
ProjectDiffController(IDocument *document, const QString &dir, ProjectDiffController(IDocument *document, const QString &dir,
const QStringList &projectPaths) : const QStringList &projectPaths) :
BaseController(document, dir), GitDiffEditorController(document, dir),
m_projectPaths(projectPaths) m_projectPaths(projectPaths)
{ } { }
@@ -374,13 +266,13 @@ void ProjectDiffController::reload()
runCommand(QList<QStringList>() << addConfigurationArguments(args)); runCommand(QList<QStringList>() << addConfigurationArguments(args));
} }
class BranchDiffController : public BaseController class BranchDiffController : public GitDiffEditorController
{ {
Q_OBJECT Q_OBJECT
public: public:
BranchDiffController(IDocument *document, const QString &dir, BranchDiffController(IDocument *document, const QString &dir,
const QString &branch) : const QString &branch) :
BaseController(document, dir), GitDiffEditorController(document, dir),
m_branch(branch) m_branch(branch)
{ } { }
@@ -397,12 +289,12 @@ void BranchDiffController::reload()
runCommand(QList<QStringList>() << addConfigurationArguments(args)); runCommand(QList<QStringList>() << addConfigurationArguments(args));
} }
class ShowController : public BaseController class ShowController : public GitDiffEditorController
{ {
Q_OBJECT Q_OBJECT
public: public:
ShowController(IDocument *document, const QString &dir, const QString &id) : ShowController(IDocument *document, const QString &dir, const QString &id) :
BaseController(document, dir), GitDiffEditorController(document, dir),
m_id(id), m_id(id),
m_state(Idle) m_state(Idle)
{ } { }
@@ -421,7 +313,7 @@ void ShowController::reload()
// stage 1 // stage 1
m_state = GettingDescription; m_state = GettingDescription;
const QStringList args = {"show", "-s", noColorOption, showFormatC, m_id}; const QStringList args = {"show", "-s", noColorOption, showFormatC, m_id};
runCommand(QList<QStringList>() << args, GitPlugin::client()->encoding(directory(), "i18n.commitEncoding")); runCommand(QList<QStringList>() << args, GitPlugin::client()->encoding(workingDirectory(), "i18n.commitEncoding"));
setStartupFile(VcsBasePlugin::source(document())); setStartupFile(VcsBasePlugin::source(document()));
} }
@@ -429,7 +321,7 @@ void ShowController::processCommandOutput(const QString &output)
{ {
QTC_ASSERT(m_state != Idle, return); QTC_ASSERT(m_state != Idle, return);
if (m_state == GettingDescription) { if (m_state == GettingDescription) {
setDescription(GitPlugin::client()->extendedShowDescription(directory(), output)); setDescription(GitPlugin::client()->extendedShowDescription(workingDirectory(), output));
// stage 2 // stage 2
m_state = GettingDiff; m_state = GettingDiff;
const QStringList args = {"show", "--format=format:", // omit header, already generated const QStringList args = {"show", "--format=format:", // omit header, already generated
@@ -437,7 +329,7 @@ void ShowController::processCommandOutput(const QString &output)
runCommand(QList<QStringList>() << addConfigurationArguments(args)); runCommand(QList<QStringList>() << addConfigurationArguments(args));
} else if (m_state == GettingDiff) { } else if (m_state == GettingDiff) {
m_state = Idle; m_state = Idle;
BaseController::processCommandOutput(output); GitDiffEditorController::processCommandOutput(output);
} }
} }

View File

@@ -30,6 +30,7 @@
#include <vcsbase/vcscommand.h> #include <vcsbase/vcscommand.h>
#include <vcsbase/vcsbaseconstants.h> #include <vcsbase/vcsbaseconstants.h>
#include <vcsbase/vcsbasediffeditorcontroller.h>
#include <vcsbase/vcsbaseeditor.h> #include <vcsbase/vcsbaseeditor.h>
#include <vcsbase/vcsbaseeditorconfig.h> #include <vcsbase/vcsbaseeditorconfig.h>
#include <vcsbase/vcsbaseplugin.h> #include <vcsbase/vcsbaseplugin.h>
@@ -167,46 +168,40 @@ QStringList SubversionClient::escapeFiles(const QStringList &files)
return Utils::transform(files, &SubversionClient::escapeFile); return Utils::transform(files, &SubversionClient::escapeFile);
} }
class DiffController : public DiffEditorController class SubversionDiffEditorController : public VcsBaseDiffEditorController
{ {
Q_OBJECT Q_OBJECT
public: public:
DiffController(IDocument *document, const SubversionClient *client, const QString &directory); SubversionDiffEditorController(IDocument *document,
const QString &workingDirectory);
void setFilesList(const QStringList &filesList); void setFilesList(const QStringList &filesList);
void setChangeNumber(int changeNumber); void setChangeNumber(int changeNumber);
protected: protected:
void reload() override; void reload() override;
void processCommandOutput(const QString &output) override;
private slots:
void slotTextualDiffOutputReceived(const QString &contents);
private: private:
QString getDescription() const; void requestDescription();
void postCollectTextualDiffOutput(); void requestDiff();
QProcessEnvironment processEnvironment() const;
const SubversionClient *m_client; enum State { Idle, GettingDescription, GettingDiff };
QString m_workingDirectory; State m_state;
QStringList m_filesList; QStringList m_filesList;
int m_changeNumber = 0; int m_changeNumber = 0;
}; };
DiffController::DiffController(IDocument *document, const SubversionClient *client, const QString &directory) : SubversionDiffEditorController::SubversionDiffEditorController(
DiffEditorController(document), IDocument *document,
m_client(client), const QString &workingDirectory)
m_workingDirectory(directory) : VcsBaseDiffEditorController(document, SubversionPlugin::instance()->client(), workingDirectory)
, m_state(Idle)
{ {
forceContextLineCount(3); // SVN can not change that when using internal diff forceContextLineCount(3); // SVN can not change that when using internal diff
} }
QProcessEnvironment DiffController::processEnvironment() const void SubversionDiffEditorController::setFilesList(const QStringList &filesList)
{
return m_client->processEnvironment();
}
void DiffController::setFilesList(const QStringList &filesList)
{ {
if (isReloading()) if (isReloading())
return; return;
@@ -214,7 +209,7 @@ void DiffController::setFilesList(const QStringList &filesList)
m_filesList = SubversionClient::escapeFiles(filesList); m_filesList = SubversionClient::escapeFiles(filesList);
} }
void DiffController::setChangeNumber(int changeNumber) void SubversionDiffEditorController::setChangeNumber(int changeNumber)
{ {
if (isReloading()) if (isReloading())
return; return;
@@ -222,33 +217,24 @@ void DiffController::setChangeNumber(int changeNumber)
m_changeNumber = qMax(changeNumber, 0); m_changeNumber = qMax(changeNumber, 0);
} }
QString DiffController::getDescription() const void SubversionDiffEditorController::requestDescription()
{ {
m_state = GettingDescription;
QStringList args(QLatin1String("log")); QStringList args(QLatin1String("log"));
args << SubversionClient::addAuthenticationOptions(m_client->settings()); args << SubversionClient::addAuthenticationOptions(client()->settings());
args << QLatin1String("-r"); args << QLatin1String("-r");
args << QString::number(m_changeNumber); args << QString::number(m_changeNumber);
const SubversionResponse logResponse = runCommand(QList<QStringList>() << args, VcsCommand::SshPasswordPrompt);
SubversionPlugin::instance()->runSvn(m_workingDirectory, args,
m_client->vcsTimeoutS(),
VcsCommand::SshPasswordPrompt);
if (logResponse.error)
return QString();
return logResponse.stdOut;
} }
void DiffController::postCollectTextualDiffOutput() void SubversionDiffEditorController::requestDiff()
{ {
auto command = new VcsCommand(m_workingDirectory, processEnvironment()); m_state = GettingDiff;
command->setCodec(EditorManager::defaultTextCodec());
connect(command, &VcsCommand::stdOutText, this, &DiffController::slotTextualDiffOutputReceived);
// command->addFlags(diffExecutionFlags());
QStringList args; QStringList args;
args << QLatin1String("diff"); args << QLatin1String("diff");
args << m_client->addAuthenticationOptions(m_client->settings()); args << SubversionClient::addAuthenticationOptions(client()->settings());
args << QLatin1String("--internal-diff"); args << QLatin1String("--internal-diff");
if (ignoreWhitespace()) if (ignoreWhitespace())
args << QLatin1String("-x") << QLatin1String("-uw"); args << QLatin1String("-x") << QLatin1String("-uw");
@@ -258,40 +244,43 @@ void DiffController::postCollectTextualDiffOutput()
} else { } else {
args << m_filesList; args << m_filesList;
} }
runCommand(QList<QStringList>() << args, 0);
command->addJob(m_client->vcsBinary(), args, m_client->vcsTimeoutS());
command->execute();
} }
void DiffController::slotTextualDiffOutputReceived(const QString &contents) void SubversionDiffEditorController::reload()
{ {
bool ok; if (m_changeNumber) {
QList<FileData> fileDataList requestDescription();
= DiffUtils::readPatch(contents, &ok); } else {
setDiffFiles(fileDataList, m_workingDirectory); requestDiff();
}
reloadFinished(true);
} }
void DiffController::reload() void SubversionDiffEditorController::processCommandOutput(const QString &output)
{ {
const QString description = m_changeNumber QTC_ASSERT(m_state != Idle, return);
? getDescription() : QString(); if (m_state == GettingDescription) {
postCollectTextualDiffOutput(); setDescription(output);
setDescription(description);
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 &source,
const QString &title, const QString &title,
const QString &workingDirectory) const const QString &workingDirectory) const
{ {
IDocument *document = DiffEditorController::findOrCreateDocument(documentId, title); IDocument *document = DiffEditorController::findOrCreateDocument(documentId, title);
DiffController *controller = qobject_cast<DiffController *>( SubversionDiffEditorController *controller = qobject_cast<SubversionDiffEditorController *>(
DiffEditorController::controller(document)); DiffEditorController::controller(document));
if (!controller) if (!controller)
controller = new DiffController(document, this, workingDirectory); controller = new SubversionDiffEditorController(document, workingDirectory);
VcsBasePlugin::setSource(document, source); VcsBasePlugin::setSource(document, source);
EditorManager::activateEditorForDocument(document);
return controller; return controller;
} }
@@ -304,7 +293,7 @@ void SubversionClient::diff(const QString &workingDirectory, const QStringList &
+ QLatin1String(".Diff.") + VcsBaseEditor::getTitleId(workingDirectory, files); + QLatin1String(".Diff.") + VcsBaseEditor::getTitleId(workingDirectory, files);
const QString title = vcsEditorTitle(vcsCmdString, documentId); const QString title = vcsEditorTitle(vcsCmdString, documentId);
DiffController *controller = findOrCreateDiffEditor(documentId, workingDirectory, title, SubversionDiffEditorController *controller = findOrCreateDiffEditor(documentId, workingDirectory, title,
workingDirectory); workingDirectory);
controller->setFilesList(files); controller->setFilesList(files);
controller->requestReload(); controller->requestReload();
@@ -335,7 +324,7 @@ void SubversionClient::describe(const QString &workingDirectory, int changeNumbe
QStringList(), QStringList(),
QString::number(changeNumber)); QString::number(changeNumber));
DiffController *controller = findOrCreateDiffEditor(documentId, workingDirectory, title, workingDirectory); SubversionDiffEditorController *controller = findOrCreateDiffEditor(documentId, workingDirectory, title, workingDirectory);
controller->setChangeNumber(changeNumber); controller->setChangeNumber(changeNumber);
controller->requestReload(); controller->requestReload();
} }

View File

@@ -35,7 +35,7 @@ namespace Subversion {
namespace Internal { namespace Internal {
class SubversionSettings; class SubversionSettings;
class DiffController; class SubversionDiffEditorController;
class SubversionClient : public VcsBase::VcsBaseClient class SubversionClient : public VcsBase::VcsBaseClient
{ {
@@ -78,7 +78,7 @@ protected:
Core::Id vcsEditorKind(VcsCommandTag cmd) const override; Core::Id vcsEditorKind(VcsCommandTag cmd) const override;
private: private:
DiffController *findOrCreateDiffEditor(const QString &documentId, const QString &source, SubversionDiffEditorController *findOrCreateDiffEditor(const QString &documentId, const QString &source,
const QString &title, const QString &workingDirectory) const; const QString &title, const QString &workingDirectory) const;
mutable Utils::FileName m_svnVersionBinary; mutable Utils::FileName m_svnVersionBinary;

View File

@@ -27,7 +27,8 @@ HEADERS += vcsbase_global.h \
vcsbaseclientsettings.h \ vcsbaseclientsettings.h \
vcsbaseeditorconfig.h \ vcsbaseeditorconfig.h \
submitfieldwidget.h \ submitfieldwidget.h \
submiteditorwidget.h submiteditorwidget.h \
vcsbasediffeditorcontroller.h
SOURCES += vcsplugin.cpp \ SOURCES += vcsplugin.cpp \
vcsbaseplugin.cpp \ vcsbaseplugin.cpp \
@@ -54,7 +55,8 @@ SOURCES += vcsplugin.cpp \
vcsbaseclientsettings.cpp \ vcsbaseclientsettings.cpp \
vcsbaseeditorconfig.cpp \ vcsbaseeditorconfig.cpp \
submitfieldwidget.cpp \ submitfieldwidget.cpp \
submiteditorwidget.cpp submiteditorwidget.cpp \
vcsbasediffeditorcontroller.cpp
RESOURCES += vcsbase.qrc RESOURCES += vcsbase.qrc

View File

@@ -12,6 +12,7 @@ QtcPlugin {
Depends { name: "TextEditor" } Depends { name: "TextEditor" }
Depends { name: "ProjectExplorer" } Depends { name: "ProjectExplorer" }
Depends { name: "CppTools" } Depends { name: "CppTools" }
Depends { name: "DiffEditor" }
pluginRecommends: [ pluginRecommends: [
"CodePaster" "CodePaster"
@@ -53,6 +54,8 @@ QtcPlugin {
"vcsbaseclientsettings.cpp", "vcsbaseclientsettings.cpp",
"vcsbaseclientsettings.h", "vcsbaseclientsettings.h",
"vcsbaseconstants.h", "vcsbaseconstants.h",
"vcsbasediffeditorcontroller.cpp",
"vcsbasediffeditorcontroller.h",
"vcsbaseeditor.cpp", "vcsbaseeditor.cpp",
"vcsbaseeditor.h", "vcsbaseeditor.h",
"vcsbaseeditorconfig.cpp", "vcsbaseeditorconfig.cpp",

View File

@@ -8,6 +8,7 @@ QTC_PLUGIN_DEPENDS += \
coreplugin \ coreplugin \
texteditor \ texteditor \
projectexplorer \ projectexplorer \
cpptools cpptools \
diffeditor
QTC_PLUGIN_RECOMMENDS += \ QTC_PLUGIN_RECOMMENDS += \
cpaster cpaster

View File

@@ -0,0 +1,195 @@
/****************************************************************************
**
** 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

View File

@@ -0,0 +1,62 @@
/****************************************************************************
**
** 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