forked from qt-creator/qt-creator
Introduce ProcessProgress
This is extracted separate object out of VcsCommand. It's responsible for showing progress of the running process. It's able to cancel the running process automatically after pressing a small 'x' indicator on progress panel. In this case the QtcProcess::stop() method is being called. Change-Id: I9fa94fd047638f76909356ae4023852349be3a06 Reviewed-by: Eike Ziller <eike.ziller@qt.io>
This commit is contained in:
@@ -1750,6 +1750,11 @@ void QtcProcess::setTimeoutS(int timeoutS)
|
||||
d->m_maxHangTimerCount = INT_MAX / 1000;
|
||||
}
|
||||
|
||||
int QtcProcess::timeoutS() const
|
||||
{
|
||||
return d->m_maxHangTimerCount;
|
||||
}
|
||||
|
||||
void QtcProcess::setCodec(QTextCodec *c)
|
||||
{
|
||||
QTC_ASSERT(c, return);
|
||||
|
@@ -142,6 +142,7 @@ public:
|
||||
/* Timeout for hanging processes (triggers after no more output
|
||||
* occurs on stderr/stdout). */
|
||||
void setTimeoutS(int timeoutS);
|
||||
int timeoutS() const;
|
||||
|
||||
// TODO: We should specify the purpose of the codec, e.g. setCodecForStandardChannel()
|
||||
void setCodec(QTextCodec *c);
|
||||
|
@@ -140,6 +140,7 @@ add_qtc_plugin(Core
|
||||
plugindialog.cpp plugindialog.h
|
||||
plugininstallwizard.cpp plugininstallwizard.h
|
||||
progressmanager/futureprogress.cpp progressmanager/futureprogress.h
|
||||
progressmanager/processprogress.cpp progressmanager/processprogress.h
|
||||
progressmanager/progressbar.cpp progressmanager/progressbar.h
|
||||
progressmanager/progressmanager.cpp progressmanager/progressmanager.h progressmanager/progressmanager_p.h
|
||||
progressmanager/progressview.cpp progressmanager/progressview.h
|
||||
|
@@ -239,6 +239,7 @@ Project {
|
||||
prefix: "progressmanager/"
|
||||
files: [
|
||||
"futureprogress.cpp", "futureprogress.h",
|
||||
"processprogress.cpp", "processprogress.h",
|
||||
"progressbar.cpp", "progressbar.h",
|
||||
"progressmanager.cpp", "progressmanager.h", "progressmanager_p.h",
|
||||
"progressview.cpp", "progressview.h",
|
||||
|
134
src/plugins/coreplugin/progressmanager/processprogress.cpp
Normal file
134
src/plugins/coreplugin/progressmanager/processprogress.cpp
Normal file
@@ -0,0 +1,134 @@
|
||||
// Copyright (C) 2022 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0
|
||||
|
||||
#include "processprogress.h"
|
||||
|
||||
#include "coreplugintr.h"
|
||||
#include "progressmanager.h"
|
||||
|
||||
#include <utils/qtcassert.h>
|
||||
#include <utils/qtcprocess.h>
|
||||
|
||||
#include <QFutureWatcher>
|
||||
|
||||
using namespace Utils;
|
||||
|
||||
namespace Core {
|
||||
|
||||
class ProcessProgressPrivate : public QObject
|
||||
{
|
||||
public:
|
||||
explicit ProcessProgressPrivate(ProcessProgress *progress, QtcProcess *process);
|
||||
~ProcessProgressPrivate();
|
||||
|
||||
QString displayName() const;
|
||||
void parseProgress(const QString &inputText);
|
||||
|
||||
QtcProcess *m_process = nullptr;
|
||||
ProgressParser m_parser = {};
|
||||
QFutureWatcher<void> m_watcher;
|
||||
QFutureInterface<void> m_futureInterface;
|
||||
QString m_displayName;
|
||||
};
|
||||
|
||||
ProcessProgressPrivate::ProcessProgressPrivate(ProcessProgress *progress, QtcProcess *process)
|
||||
: QObject(progress)
|
||||
, m_process(process)
|
||||
{
|
||||
}
|
||||
|
||||
ProcessProgressPrivate::~ProcessProgressPrivate()
|
||||
{
|
||||
if (m_futureInterface.isRunning()) {
|
||||
m_futureInterface.reportCanceled();
|
||||
m_futureInterface.reportFinished();
|
||||
// TODO: should we stop the process? Or just mark the process canceled?
|
||||
// What happens to task in progress manager?
|
||||
}
|
||||
}
|
||||
|
||||
QString ProcessProgressPrivate::displayName() const
|
||||
{
|
||||
if (!m_displayName.isEmpty())
|
||||
return m_displayName;
|
||||
const CommandLine commandLine = m_process->commandLine();
|
||||
QString result = commandLine.executable().baseName();
|
||||
QTC_ASSERT(!result.isEmpty(), result = Tr::tr("Unknown"));
|
||||
result[0] = result[0].toTitleCase();
|
||||
if (!commandLine.arguments().isEmpty())
|
||||
result += ' ' + commandLine.splitArguments().at(0);
|
||||
return result;
|
||||
}
|
||||
|
||||
void ProcessProgressPrivate::parseProgress(const QString &inputText)
|
||||
{
|
||||
QTC_ASSERT(m_parser, return);
|
||||
m_parser(m_futureInterface, inputText);
|
||||
}
|
||||
|
||||
/*!
|
||||
\class Core::ProcessProgress
|
||||
|
||||
\brief The ProcessProgress class is responsible for showing progress of the running process.
|
||||
|
||||
It's able to cancel the running process automatically after pressing a small 'x' indicator on
|
||||
progress panel. In this case the QtcProcess::stop() method is being called.
|
||||
*/
|
||||
|
||||
ProcessProgress::ProcessProgress(QtcProcess *process)
|
||||
: QObject(process)
|
||||
, d(new ProcessProgressPrivate(this, process))
|
||||
{
|
||||
connect(&d->m_watcher, &QFutureWatcher<void>::canceled, this, [this] {
|
||||
d->m_process->stop(); // TODO: should we have different cancel policies?
|
||||
});
|
||||
connect(d->m_process, &QtcProcess::starting, this, [this] {
|
||||
d->m_futureInterface = QFutureInterface<void>();
|
||||
d->m_futureInterface.setProgressRange(0, 1);
|
||||
d->m_watcher.setFuture(d->m_futureInterface.future());
|
||||
d->m_futureInterface.reportStarted();
|
||||
|
||||
const QString name = d->displayName();
|
||||
const auto id = Id::fromString(name + ".action");
|
||||
if (d->m_parser) {
|
||||
ProgressManager::addTask(d->m_futureInterface.future(), name, id);
|
||||
} else {
|
||||
ProgressManager::addTimedTask(d->m_futureInterface, name, id,
|
||||
qMax(2, d->m_process->timeoutS() / 5));
|
||||
}
|
||||
});
|
||||
connect(d->m_process, &QtcProcess::done, this, [this] {
|
||||
if (d->m_process->result() != ProcessResult::FinishedWithSuccess)
|
||||
d->m_futureInterface.reportCanceled();
|
||||
d->m_futureInterface.reportFinished();
|
||||
});
|
||||
}
|
||||
|
||||
void ProcessProgress::setDisplayName(const QString &name)
|
||||
{
|
||||
d->m_displayName = name;
|
||||
}
|
||||
|
||||
void ProcessProgress::setProgressParser(const ProgressParser &parser)
|
||||
{
|
||||
if (d->m_parser) {
|
||||
disconnect(d->m_process, &QtcProcess::textOnStandardOutput,
|
||||
d, &ProcessProgressPrivate::parseProgress);
|
||||
disconnect(d->m_process, &QtcProcess::textOnStandardError,
|
||||
d, &ProcessProgressPrivate::parseProgress);
|
||||
}
|
||||
d->m_parser = parser;
|
||||
if (!d->m_parser)
|
||||
return;
|
||||
|
||||
QTC_ASSERT(d->m_process->textChannelMode(Channel::Output) != TextChannelMode::Off,
|
||||
qWarning() << "Setting progress parser on a process without changing process' "
|
||||
"text channel mode is no-op.");
|
||||
|
||||
connect(d->m_process, &QtcProcess::textOnStandardOutput,
|
||||
d, &ProcessProgressPrivate::parseProgress);
|
||||
connect(d->m_process, &QtcProcess::textOnStandardError,
|
||||
d, &ProcessProgressPrivate::parseProgress);
|
||||
}
|
||||
|
||||
} // namespace Core
|
35
src/plugins/coreplugin/progressmanager/processprogress.h
Normal file
35
src/plugins/coreplugin/progressmanager/processprogress.h
Normal file
@@ -0,0 +1,35 @@
|
||||
// Copyright (C) 2022 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <coreplugin/core_global.h>
|
||||
|
||||
#include <QObject>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
template <typename T>
|
||||
class QFutureInterface;
|
||||
QT_END_NAMESPACE
|
||||
|
||||
namespace Utils { class QtcProcess; }
|
||||
|
||||
namespace Core {
|
||||
|
||||
using ProgressParser = std::function<void(QFutureInterface<void> &, const QString &)>;
|
||||
|
||||
class ProcessProgressPrivate;
|
||||
|
||||
class CORE_EXPORT ProcessProgress : public QObject
|
||||
{
|
||||
public:
|
||||
ProcessProgress(Utils::QtcProcess *process); // Makes ProcessProgress a child of process
|
||||
|
||||
void setDisplayName(const QString &name);
|
||||
void setProgressParser(const ProgressParser &parser);
|
||||
|
||||
private:
|
||||
ProcessProgressPrivate *d;
|
||||
};
|
||||
|
||||
} // namespace Core
|
Reference in New Issue
Block a user