瀏覽代碼

Added cancel support when running modules.

Sascha Zelzer 13 年之前
父節點
當前提交
048555a14d

+ 8 - 8
Applications/ctkCommandLineModuleExplorer/ctkCLModuleExplorerMainWindow.cpp

@@ -91,14 +91,14 @@ void ctkCLModuleExplorerMainWindow::on_actionRun_triggered()
   ctkCmdLineModuleFuture future = module->run();
   ctkCmdLineModuleFuture future = module->run();
   watcher->setFuture(future);
   watcher->setFuture(future);
 
 
-  try
-  {
-    future.waitForFinished();
-  }
-  catch (const ctkException& e)
-  {
-    qDebug() << e.printStackTrace();
-  }
+//  try
+//  {
+//    future.waitForFinished();
+//  }
+//  catch (const ctkException& e)
+//  {
+//    qDebug() << e.printStackTrace();
+//  }
 }
 }
 
 
 void ctkCLModuleExplorerMainWindow::moduleStarted()
 void ctkCLModuleExplorerMainWindow::moduleStarted()

+ 90 - 15
Libs/CommandLineModules/Core/Testing/Cpp/ctkCmdLineModuleFutureTest.cpp

@@ -86,10 +86,19 @@ bool futureTestStartFinish(ctkCmdLineModule* module)
   QObject::connect(&watcher, SIGNAL(started()), &signalTester, SLOT(moduleStarted()));
   QObject::connect(&watcher, SIGNAL(started()), &signalTester, SLOT(moduleStarted()));
   QObject::connect(&watcher, SIGNAL(finished()), &signalTester, SLOT(moduleFinished()));
   QObject::connect(&watcher, SIGNAL(finished()), &signalTester, SLOT(moduleFinished()));
 
 
+  qDebug() << module->commandLineArguments();
   ctkCmdLineModuleFuture future = module->run();
   ctkCmdLineModuleFuture future = module->run();
   watcher.setFuture(future);
   watcher.setFuture(future);
 
 
-  future.waitForFinished();
+  try
+  {
+    future.waitForFinished();
+  }
+  catch (const ctkCmdLineModuleRunException& e)
+  {
+    qDebug() << e;
+    return false;
+  }
 
 
   // process pending events
   // process pending events
   QCoreApplication::processEvents();
   QCoreApplication::processEvents();
@@ -128,11 +137,19 @@ bool futureTestProgress(ctkCmdLineModule* module)
   QObject::connect(&watcher, SIGNAL(progressTextChanged(QString)), &signalTester, SLOT(moduleProgressTextChanged(QString)));
   QObject::connect(&watcher, SIGNAL(progressTextChanged(QString)), &signalTester, SLOT(moduleProgressTextChanged(QString)));
   QObject::connect(&watcher, SIGNAL(finished()), &signalTester, SLOT(moduleFinished()));
   QObject::connect(&watcher, SIGNAL(finished()), &signalTester, SLOT(moduleFinished()));
 
 
-  module->setValue("fileVar", "output1");
+  module->setValue("numOutputsVar", 1);
   ctkCmdLineModuleFuture future = module->run();
   ctkCmdLineModuleFuture future = module->run();
   watcher.setFuture(future);
   watcher.setFuture(future);
 
 
-  future.waitForFinished();
+  try
+  {
+    future.waitForFinished();
+  }
+  catch (const ctkCmdLineModuleRunException& e)
+  {
+    qDebug() << e;
+    return false;
+  }
 
 
   // process pending events
   // process pending events
   QCoreApplication::processEvents();
   QCoreApplication::processEvents();
@@ -140,6 +157,54 @@ bool futureTestProgress(ctkCmdLineModule* module)
   return signalTester.checkSignals(expectedSignals);
   return signalTester.checkSignals(expectedSignals);
 }
 }
 
 
+bool futureTestPauseAndCancel(ctkCmdLineModule* module)
+{
+  qDebug() << "Testing ctkCmdLineModuleFuture pause and cancel capabilities";
+
+  QList<QString> expectedSignals;
+  expectedSignals.push_back("module.started");
+  expectedSignals.push_back("module.finished");
+
+  ctkCmdLineModuleSignalTester signalTester;
+
+  QFutureWatcher<ctkCmdLineModuleResult> watcher;
+  QObject::connect(&watcher, SIGNAL(started()), &signalTester, SLOT(moduleStarted()));
+  QObject::connect(&watcher, SIGNAL(progressValueChanged(int)), &signalTester, SLOT(moduleProgressValueChanged(int)));
+  QObject::connect(&watcher, SIGNAL(progressTextChanged(QString)), &signalTester, SLOT(moduleProgressTextChanged(QString)));
+  QObject::connect(&watcher, SIGNAL(finished()), &signalTester, SLOT(moduleFinished()));
+
+  module->setValue("runtimeVar", 60);
+  ctkCmdLineModuleFuture future = module->run();
+  watcher.setFuture(future);
+
+
+  try
+  {
+    future.cancel();
+    future.waitForFinished();
+  }
+  catch (const ctkCmdLineModuleRunException& e)
+  {
+    qDebug() << e;
+    return false;
+  }
+
+  // process pending events
+  QCoreApplication::processEvents();
+
+  if (!signalTester.checkSignals(expectedSignals))
+  {
+    return false;
+  }
+
+  if (!(future.isCanceled() && future.isFinished()))
+  {
+    qDebug() << "Cancel state wrong";
+    return false;
+  }
+  return true;
+}
+
 bool futureTestError(ctkCmdLineModule* module)
 bool futureTestError(ctkCmdLineModule* module)
 {
 {
   qDebug() << "Testing ctkCmdLineModuleFuture error reporting.";
   qDebug() << "Testing ctkCmdLineModuleFuture error reporting.";
@@ -183,27 +248,37 @@ int ctkCmdLineModuleFutureTest(int argc, char* argv[])
     qCritical() << "Module at" << moduleFilename << "could not be registered";
     qCritical() << "Module at" << moduleFilename << "could not be registered";
   }
   }
 
 
-  QScopedPointer<ctkCmdLineModule> module(manager.createModule(moduleRef));
-
-  if (!futureTestStartFinish(module.data()))
   {
   {
-    return EXIT_FAILURE;
+    QScopedPointer<ctkCmdLineModule> module(manager.createModule(moduleRef));
+    if (!futureTestStartFinish(module.data()))
+    {
+      return EXIT_FAILURE;
+    }
   }
   }
 
 
-  if (!futureTestProgress(module.data()))
   {
   {
-    return EXIT_FAILURE;
+    QScopedPointer<ctkCmdLineModule> module(manager.createModule(moduleRef));
+    if (!futureTestProgress(module.data()))
+    {
+      return EXIT_FAILURE;
+    }
   }
   }
 
 
-  if (!futureTestError(module.data()))
   {
   {
-    return EXIT_FAILURE;
+    QScopedPointer<ctkCmdLineModule> module(manager.createModule(moduleRef));
+    if (!futureTestError(module.data()))
+    {
+      return EXIT_FAILURE;
+    }
   }
   }
 
 
-//  if (!futureTestPauseAndCancel(module.data()))
-//  {
-//    return EXIT_FAILURE;
-//  }
+  {
+    QScopedPointer<ctkCmdLineModule> module(manager.createModule(moduleRef));
+    if (!futureTestPauseAndCancel(module.data()))
+    {
+      return EXIT_FAILURE;
+    }
+  }
 
 
   //  if (!futureTestResultReady(module.data()))
   //  if (!futureTestResultReady(module.data()))
   //  {
   //  {

+ 7 - 5
Libs/CommandLineModules/Core/Testing/Modules/TestBed/ctkCmdLineModuleTestBed.cpp

@@ -45,6 +45,7 @@ int main(int argc, char* argv[])
   parser.addArgument("help", "h", QVariant::Bool, "Show this help text");
   parser.addArgument("help", "h", QVariant::Bool, "Show this help text");
   parser.addArgument("xml", "", QVariant::Bool, "Print a XML description of this modules command line interface");
   parser.addArgument("xml", "", QVariant::Bool, "Print a XML description of this modules command line interface");
   parser.addArgument("runtime", "", QVariant::Int, "Runtime in seconds", 1);
   parser.addArgument("runtime", "", QVariant::Int, "Runtime in seconds", 1);
+  parser.addArgument("numOutputs", "", QVariant::Int, "Number of outpusts", 0);
   parser.addArgument("exitCode", "", QVariant::Int, "Exit code", 0);
   parser.addArgument("exitCode", "", QVariant::Int, "Exit code", 0);
   parser.addArgument("exitCrash", "", QVariant::Bool, "Force crash", false);
   parser.addArgument("exitCrash", "", QVariant::Bool, "Force crash", false);
   parser.addArgument("exitTime", "", QVariant::Int, "Exit time", 0);
   parser.addArgument("exitTime", "", QVariant::Int, "Exit time", 0);
@@ -65,10 +66,6 @@ int main(int argc, char* argv[])
   if (parsedArgs.contains("help") || parsedArgs.contains("h"))
   if (parsedArgs.contains("help") || parsedArgs.contains("h"))
   {
   {
     out << parser.helpText();
     out << parser.helpText();
-    out.setFieldWidth(parser.fieldWidth());
-    out.setFieldAlignment(QTextStream::AlignLeft);
-    out << "  <output>...";
-    out << "One or more output strings\n";
     return EXIT_SUCCESS;
     return EXIT_SUCCESS;
   }
   }
 
 
@@ -83,13 +80,18 @@ int main(int argc, char* argv[])
   // Do something
   // Do something
 
 
   float runtime = parsedArgs["runtime"].toFloat();
   float runtime = parsedArgs["runtime"].toFloat();
+  int numOutputs = parsedArgs["numOutputs"].toInt();
   float exitTime = parsedArgs["exitTime"].toFloat();
   float exitTime = parsedArgs["exitTime"].toFloat();
   int exitTimeMillis = static_cast<long>(exitTime/2.0 * 1000.0);
   int exitTimeMillis = static_cast<long>(exitTime/2.0 * 1000.0);
   int exitCode = parsedArgs["exitCode"].toInt();
   int exitCode = parsedArgs["exitCode"].toInt();
   bool exitCrash = parsedArgs["exitCrash"].toBool();
   bool exitCrash = parsedArgs["exitCrash"].toBool();
   QString errorText = parsedArgs["errorText"].toString();
   QString errorText = parsedArgs["errorText"].toString();
 
 
-  QStringList outputs = parser.unparsedArguments();
+  QStringList outputs;
+  for (int i = 0; i < numOutputs; ++i)
+  {
+    outputs << "Output " + QString::number(i+1);
+  }
 
 
   if (outputs.empty())
   if (outputs.empty())
   {
   {

+ 7 - 7
Libs/CommandLineModules/Core/Testing/Modules/TestBed/ctkCmdLineModuleTestBed.xml

@@ -25,13 +25,13 @@ Configurable behaviour for testing purposes.
         <step>1</step>
         <step>1</step>
       </constraints>
       </constraints>
     </integer>
     </integer>
-    <file multiple="true">
-      <name>fileVar</name>
-      <index>0</index>
-      <description>Output files which will be reported as the progress text via a QFutureWatcher.</description>
-      <label>Output</label>
-      <channel>output</channel>
-    </file>
+    <integer>
+      <name>numOutputsVar</name>
+      <longflag>numOutputs</longflag>
+      <description>Number of outputs which will be reported as the progress text via a QFutureWatcher.</description>
+      <label>Output Number</label>
+      <default>0</default>
+    </integer>
     <integer>
     <integer>
       <name>exitTimeVar</name>
       <name>exitTimeVar</name>
       <longflag>exitTime</longflag>
       <longflag>exitTime</longflag>

+ 26 - 12
Libs/CommandLineModules/Core/ctkCmdLineModuleProcessTask.cpp

@@ -81,7 +81,7 @@ int ctkCmdLineModuleProcessProgressWatcher::incrementProgress()
 }
 }
 
 
 ctkCmdLineModuleProcessTask::ctkCmdLineModuleProcessTask(const QString& location, const QStringList& args)
 ctkCmdLineModuleProcessTask::ctkCmdLineModuleProcessTask(const QString& location, const QStringList& args)
-  : location(location), args(args)
+  : process(NULL), location(location), args(args)
 {
 {
   this->setCanCancel(true);
   this->setCanCancel(true);
 }
 }
@@ -107,32 +107,46 @@ void ctkCmdLineModuleProcessTask::run()
     return;
     return;
   }
   }
 
 
-  QProcess process;
-  process.setReadChannel(QProcess::StandardOutput);
+  process = new QProcess();
+  process->setReadChannel(QProcess::StandardOutput);
 
 
   QEventLoop localLoop;
   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()));
 
 
-  process.start(location, args);
+  QTimer pollCancelTimer;
+  pollCancelTimer.setInterval(500);
+  this->connect(&pollCancelTimer, SIGNAL(timeout()), SLOT(pollCancelState()));
 
 
-  ctkCmdLineModuleProcessProgressWatcher progressWatcher(process, location, *this);
+  process->start(location, args);
+
+  ctkCmdLineModuleProcessProgressWatcher progressWatcher(*process, location, *this);
   Q_UNUSED(progressWatcher)
   Q_UNUSED(progressWatcher)
 
 
   localLoop.exec();
   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->reportResult(result);
   this->reportFinished();
   this->reportFinished();
 
 
+  delete process;
+
+}
+
+void ctkCmdLineModuleProcessTask::pollCancelState()
+{
+  if (this->isCanceled() && process->state() == QProcess::Running)
+  {
+    process->terminate();
+  }
 }
 }

+ 7 - 1
Libs/CommandLineModules/Core/ctkCmdLineModuleProcessTask.h

@@ -32,8 +32,9 @@
 
 
 class QProcess;
 class QProcess;
 
 
-class ctkCmdLineModuleProcessTask : public ctkCmdLineModuleFutureInterface, public QRunnable
+class ctkCmdLineModuleProcessTask : public QObject, public ctkCmdLineModuleFutureInterface, public QRunnable
 {
 {
+  Q_OBJECT
 
 
 public:
 public:
 
 
@@ -44,8 +45,13 @@ public:
 
 
   void run();
   void run();
 
 
+protected Q_SLOTS:
+
+  void pollCancelState();
+
 private:
 private:
 
 
+  QProcess* process;
   const QString location;
   const QString location;
   const QStringList args;
   const QStringList args;