|
@@ -29,10 +29,14 @@
|
|
|
#include <QThreadPool>
|
|
|
#include <QProcess>
|
|
|
|
|
|
-ctkCmdLineModuleProcessProgressWatcher::ctkCmdLineModuleProcessProgressWatcher(QProcess& process, const QString& location,
|
|
|
- ctkCmdLineModuleFutureInterface &futureInterface)
|
|
|
+#ifdef Q_OS_UNIX
|
|
|
+#include <signal.h>
|
|
|
+#endif
|
|
|
+
|
|
|
+ctkCmdLineModuleProcessWatcher::ctkCmdLineModuleProcessWatcher(QProcess& process, const QString& location,
|
|
|
+ ctkCmdLineModuleFutureInterface &futureInterface)
|
|
|
: process(process), location(location), futureInterface(futureInterface), processXmlWatcher(&process),
|
|
|
- progressValue(0)
|
|
|
+ processPaused(false), progressValue(0)
|
|
|
{
|
|
|
futureInterface.setProgressRange(0, 1000);
|
|
|
|
|
@@ -40,30 +44,81 @@ ctkCmdLineModuleProcessProgressWatcher::ctkCmdLineModuleProcessProgressWatcher(Q
|
|
|
connect(&processXmlWatcher, SIGNAL(filterProgress(float)), SLOT(filterProgress(float)));
|
|
|
connect(&processXmlWatcher, SIGNAL(filterFinished(QString)), SLOT(filterFinished(QString)));
|
|
|
connect(&processXmlWatcher, SIGNAL(filterXmlError(QString)), SLOT(filterXmlError(QString)));
|
|
|
+
|
|
|
+ connect(&futureWatcher, SIGNAL(canceled()), SLOT(cancelProcess()));
|
|
|
+#ifdef Q_OS_UNIX
|
|
|
+ connect(&futureWatcher, SIGNAL(resumed()), SLOT(resumeProcess()));
|
|
|
+ // Due to Qt bug 12152, we cannot listen to the "paused" signal because it is
|
|
|
+ // not emitted directly when the QFuture is paused. Instead, it is emitted after
|
|
|
+ // resuming the future, after the "resume" signal has been emitted...
|
|
|
+ //connect(&futureWatcher, SIGNAL(paused()), SLOT(pauseProcess()));
|
|
|
+ connect(&pollPauseTimer, SIGNAL(timeout()), this, SLOT(pauseProcess()));
|
|
|
+ pollPauseTimer.start(500);
|
|
|
+#endif
|
|
|
+ futureWatcher.setFuture(futureInterface.future());
|
|
|
}
|
|
|
|
|
|
-void ctkCmdLineModuleProcessProgressWatcher::filterStarted(const QString& name, const QString& comment)
|
|
|
+void ctkCmdLineModuleProcessWatcher::filterStarted(const QString& name, const QString& comment)
|
|
|
{
|
|
|
Q_UNUSED(comment)
|
|
|
futureInterface.setProgressValueAndText(incrementProgress(), name);
|
|
|
}
|
|
|
|
|
|
-void ctkCmdLineModuleProcessProgressWatcher::filterProgress(float progress)
|
|
|
+void ctkCmdLineModuleProcessWatcher::filterProgress(float progress)
|
|
|
{
|
|
|
futureInterface.setProgressValue(updateProgress(progress));
|
|
|
}
|
|
|
|
|
|
-void ctkCmdLineModuleProcessProgressWatcher::filterFinished(const QString& name)
|
|
|
+void ctkCmdLineModuleProcessWatcher::filterFinished(const QString& name)
|
|
|
{
|
|
|
futureInterface.setProgressValueAndText(incrementProgress(), "Finished: " + name);
|
|
|
}
|
|
|
|
|
|
-void ctkCmdLineModuleProcessProgressWatcher::filterXmlError(const QString &error)
|
|
|
+void ctkCmdLineModuleProcessWatcher::filterXmlError(const QString &error)
|
|
|
{
|
|
|
qDebug().nospace() << "[Module " << location << "]: " << error;
|
|
|
}
|
|
|
|
|
|
-int ctkCmdLineModuleProcessProgressWatcher::updateProgress(float progress)
|
|
|
+void ctkCmdLineModuleProcessWatcher::pauseProcess()
|
|
|
+{
|
|
|
+ if (processPaused || !futureInterface.isPaused()) return;
|
|
|
+
|
|
|
+#ifdef Q_OS_UNIX
|
|
|
+ if (::kill(process.pid(), SIGSTOP))
|
|
|
+ {
|
|
|
+ // error
|
|
|
+ futureInterface.setPaused(false);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ processPaused = true;
|
|
|
+ }
|
|
|
+#endif
|
|
|
+}
|
|
|
+
|
|
|
+void ctkCmdLineModuleProcessWatcher::resumeProcess()
|
|
|
+{
|
|
|
+ if (!processPaused) return;
|
|
|
+
|
|
|
+#ifdef Q_OS_UNIX
|
|
|
+ if(::kill(process.pid(), SIGCONT))
|
|
|
+ {
|
|
|
+ // error
|
|
|
+ futureInterface.setPaused(true);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ processPaused = false;
|
|
|
+ }
|
|
|
+#endif
|
|
|
+}
|
|
|
+
|
|
|
+void ctkCmdLineModuleProcessWatcher::cancelProcess()
|
|
|
+{
|
|
|
+ process.terminate();
|
|
|
+}
|
|
|
+
|
|
|
+int ctkCmdLineModuleProcessWatcher::updateProgress(float progress)
|
|
|
{
|
|
|
progressValue = static_cast<int>(progress * 1000.0f);
|
|
|
// normalize the value to lie between 0 and 1000.
|
|
@@ -74,16 +129,19 @@ int ctkCmdLineModuleProcessProgressWatcher::updateProgress(float progress)
|
|
|
return progressValue;
|
|
|
}
|
|
|
|
|
|
-int ctkCmdLineModuleProcessProgressWatcher::incrementProgress()
|
|
|
+int ctkCmdLineModuleProcessWatcher::incrementProgress()
|
|
|
{
|
|
|
if (++progressValue > 999) progressValue = 999;
|
|
|
return progressValue;
|
|
|
}
|
|
|
|
|
|
ctkCmdLineModuleProcessTask::ctkCmdLineModuleProcessTask(const QString& location, const QStringList& args)
|
|
|
- : process(NULL), location(location), args(args)
|
|
|
+ : location(location), args(args)
|
|
|
{
|
|
|
this->setCanCancel(true);
|
|
|
+#ifdef Q_OS_UNIX
|
|
|
+ this->setCanPause(true);
|
|
|
+#endif
|
|
|
}
|
|
|
|
|
|
ctkCmdLineModuleProcessTask::~ctkCmdLineModuleProcessTask()
|
|
@@ -107,46 +165,32 @@ void ctkCmdLineModuleProcessTask::run()
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
- process = new QProcess();
|
|
|
- process->setReadChannel(QProcess::StandardOutput);
|
|
|
+ QProcess process;
|
|
|
+ process.setReadChannel(QProcess::StandardOutput);
|
|
|
|
|
|
QEventLoop localLoop;
|
|
|
- QObject::connect(process, SIGNAL(finished(int)), &localLoop, SLOT(quit()));
|
|
|
- QObject::connect(process, SIGNAL(error(QProcess::ProcessError)), &localLoop, SLOT(quit()));
|
|
|
+ QObject::connect(&process, SIGNAL(finished(int)), &localLoop, SLOT(quit()));
|
|
|
+ QObject::connect(&process, SIGNAL(error(QProcess::ProcessError)), &localLoop, SLOT(quit()));
|
|
|
|
|
|
- QTimer pollCancelTimer;
|
|
|
- pollCancelTimer.setInterval(500);
|
|
|
- this->connect(&pollCancelTimer, SIGNAL(timeout()), SLOT(pollCancelState()));
|
|
|
+ process.start(location, args);
|
|
|
|
|
|
- process->start(location, args);
|
|
|
-
|
|
|
- ctkCmdLineModuleProcessProgressWatcher progressWatcher(*process, location, *this);
|
|
|
+ ctkCmdLineModuleProcessWatcher progressWatcher(process, location, *this);
|
|
|
Q_UNUSED(progressWatcher)
|
|
|
|
|
|
localLoop.exec();
|
|
|
|
|
|
- if (process->error() != QProcess::UnknownError)
|
|
|
+ if (process.error() != QProcess::UnknownError)
|
|
|
{
|
|
|
- this->reportException(ctkCmdLineModuleRunException(location, process->exitCode(), process->errorString()));
|
|
|
+ this->reportException(ctkCmdLineModuleRunException(location, process.exitCode(), process.errorString()));
|
|
|
}
|
|
|
- else if (process->exitCode() != 0)
|
|
|
+ else if (process.exitCode() != 0)
|
|
|
{
|
|
|
- this->reportException(ctkCmdLineModuleRunException(location, process->exitCode(), process->readAllStandardError()));
|
|
|
+ this->reportException(ctkCmdLineModuleRunException(location, process.exitCode(), process.readAllStandardError()));
|
|
|
}
|
|
|
|
|
|
- this->setProgressValueAndText(1000, process->readAllStandardError());
|
|
|
+ this->setProgressValueAndText(1000, process.readAllStandardError());
|
|
|
|
|
|
//this->reportResult(result);
|
|
|
this->reportFinished();
|
|
|
|
|
|
- delete process;
|
|
|
-
|
|
|
-}
|
|
|
-
|
|
|
-void ctkCmdLineModuleProcessTask::pollCancelState()
|
|
|
-{
|
|
|
- if (this->isCanceled() && process->state() == QProcess::Running)
|
|
|
- {
|
|
|
- process->terminate();
|
|
|
- }
|
|
|
}
|