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;
|
d->m_maxHangTimerCount = INT_MAX / 1000;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int QtcProcess::timeoutS() const
|
||||||
|
{
|
||||||
|
return d->m_maxHangTimerCount;
|
||||||
|
}
|
||||||
|
|
||||||
void QtcProcess::setCodec(QTextCodec *c)
|
void QtcProcess::setCodec(QTextCodec *c)
|
||||||
{
|
{
|
||||||
QTC_ASSERT(c, return);
|
QTC_ASSERT(c, return);
|
||||||
|
@@ -142,6 +142,7 @@ public:
|
|||||||
/* Timeout for hanging processes (triggers after no more output
|
/* Timeout for hanging processes (triggers after no more output
|
||||||
* occurs on stderr/stdout). */
|
* occurs on stderr/stdout). */
|
||||||
void setTimeoutS(int timeoutS);
|
void setTimeoutS(int timeoutS);
|
||||||
|
int timeoutS() const;
|
||||||
|
|
||||||
// TODO: We should specify the purpose of the codec, e.g. setCodecForStandardChannel()
|
// TODO: We should specify the purpose of the codec, e.g. setCodecForStandardChannel()
|
||||||
void setCodec(QTextCodec *c);
|
void setCodec(QTextCodec *c);
|
||||||
|
@@ -140,6 +140,7 @@ add_qtc_plugin(Core
|
|||||||
plugindialog.cpp plugindialog.h
|
plugindialog.cpp plugindialog.h
|
||||||
plugininstallwizard.cpp plugininstallwizard.h
|
plugininstallwizard.cpp plugininstallwizard.h
|
||||||
progressmanager/futureprogress.cpp progressmanager/futureprogress.h
|
progressmanager/futureprogress.cpp progressmanager/futureprogress.h
|
||||||
|
progressmanager/processprogress.cpp progressmanager/processprogress.h
|
||||||
progressmanager/progressbar.cpp progressmanager/progressbar.h
|
progressmanager/progressbar.cpp progressmanager/progressbar.h
|
||||||
progressmanager/progressmanager.cpp progressmanager/progressmanager.h progressmanager/progressmanager_p.h
|
progressmanager/progressmanager.cpp progressmanager/progressmanager.h progressmanager/progressmanager_p.h
|
||||||
progressmanager/progressview.cpp progressmanager/progressview.h
|
progressmanager/progressview.cpp progressmanager/progressview.h
|
||||||
|
@@ -239,6 +239,7 @@ Project {
|
|||||||
prefix: "progressmanager/"
|
prefix: "progressmanager/"
|
||||||
files: [
|
files: [
|
||||||
"futureprogress.cpp", "futureprogress.h",
|
"futureprogress.cpp", "futureprogress.h",
|
||||||
|
"processprogress.cpp", "processprogress.h",
|
||||||
"progressbar.cpp", "progressbar.h",
|
"progressbar.cpp", "progressbar.h",
|
||||||
"progressmanager.cpp", "progressmanager.h", "progressmanager_p.h",
|
"progressmanager.cpp", "progressmanager.h", "progressmanager_p.h",
|
||||||
"progressview.cpp", "progressview.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