Browse Source

Support for running cmd line modules. Partial support for QFuture.

Sascha Zelzer 12 years ago
parent
commit
ba055de2ef
22 changed files with 709 additions and 397 deletions
  1. 11 10
      Applications/ctkCommandLineModuleExplorer/ctkCLModuleExplorerMainWindow.cpp
  2. 3 5
      Libs/CommandLineModules/Core/CMakeLists.txt
  3. 1 1
      Libs/CommandLineModules/Core/Testing/CMakeLists.txt
  4. 14 5
      Libs/CommandLineModules/Core/Testing/Cpp/CMakeLists.txt
  5. 113 0
      Libs/CommandLineModules/Core/Testing/Cpp/ctkCmdLineModuleFutureTest.cpp
  6. 89 0
      Libs/CommandLineModules/Core/Testing/Cpp/ctkCmdLineModuleSignalTester.cpp
  7. 52 0
      Libs/CommandLineModules/Core/Testing/Cpp/ctkCmdLineModuleSignalTester.h
  8. 0 92
      Libs/CommandLineModules/Core/Testing/Cpp/ctkModuleDescriptionTest.cpp
  9. 1 0
      Libs/CommandLineModules/Core/Testing/Modules/CMakeLists.txt
  10. 2 0
      Libs/CommandLineModules/Core/Testing/Modules/TestBed/CMakeLists.txt
  11. 131 0
      Libs/CommandLineModules/Core/Testing/Modules/TestBed/ctkCmdLineModuleTestBed.cpp
  12. 5 0
      Libs/CommandLineModules/Core/Testing/Modules/TestBed/ctkCmdLineModuleTestBed.qrc
  13. 58 0
      Libs/CommandLineModules/Core/Testing/Modules/TestBed/ctkCmdLineModuleTestBed.xml
  14. 0 97
      Libs/CommandLineModules/Core/ctkCmdLineModuleFuture.cpp
  15. 0 93
      Libs/CommandLineModules/Core/ctkCmdLineModuleFuture.h
  16. 9 9
      Libs/CommandLineModules/Core/ctkCmdLineModuleInstance.cpp
  17. 2 4
      Libs/CommandLineModules/Core/ctkCmdLineModuleInstance.h
  18. 0 67
      Libs/CommandLineModules/Core/ctkCmdLineModuleProcess.cpp
  19. 94 0
      Libs/CommandLineModules/Core/ctkCmdLineModuleProcessTask.cpp
  20. 17 14
      Libs/CommandLineModules/Core/ctkCmdLineModuleProcess_p.h
  21. 61 0
      Libs/CommandLineModules/Core/ctkCmdLineModuleRunException.cpp
  22. 46 0
      Libs/CommandLineModules/Core/ctkCmdLineModuleRunException.h

+ 11 - 10
Applications/ctkCommandLineModuleExplorer/ctkCLModuleExplorerMainWindow.cpp

@@ -26,8 +26,9 @@
 #include <ctkCmdLineModuleManager.h>
 #include <ctkCmdLineModuleInstance.h>
 #include <ctkCmdLineModuleInstanceFactoryQtGui.h>
-//#include <ctkCmdLineModuleFuture.h>
+#include <ctkException.h>
 
+#include <QFuture>
 #include <QDebug>
 
 ctkCLModuleExplorerMainWindow::ctkCLModuleExplorerMainWindow(QWidget *parent) :
@@ -66,8 +67,6 @@ void ctkCLModuleExplorerMainWindow::addModule(const QString &location)
 
 void ctkCLModuleExplorerMainWindow::on_actionRun_triggered()
 {
-  qDebug() << "Creating module command line...";
-
   ctkCmdLineModuleInstance* moduleInstance = mapTabToModuleRef[ui->mainTabWidget->currentIndex()];
   if (!moduleInstance)
   {
@@ -78,14 +77,16 @@ void ctkCLModuleExplorerMainWindow::on_actionRun_triggered()
   QStringList cmdLineArgs = moduleInstance->commandLineArguments();
   qDebug() << cmdLineArgs;
 
+  QFuture<QString> future = moduleInstance->run();
+  try
+  {
+    future.waitForFinished();
+  }
+  catch (const ctkException& e)
+  {
+    qDebug() << e.printStackTrace();
+  }
 
-  //ctkCmdLineModuleProcessFuture future = moduleInstance->run();
-  //future.waitForFinished();
-  //qDebug() << future.standardOutput();
-
-//  connect(&futureWatcher, SIGNAL(finished()), this, SLOT(futureFinished()));
-//  ctkCmdLineModuleProcessFuture future = moduleManager.run(moduleRef);
-//  futureWatcher.setFuture(future);
 }
 
 void ctkCLModuleExplorerMainWindow::futureFinished()

+ 3 - 5
Libs/CommandLineModules/Core/CMakeLists.txt

@@ -16,8 +16,6 @@ set(KIT_export_directive "CTK_CMDLINEMODULECORE_EXPORT")
 set(KIT_SRCS
   ctkCmdLineModuleDescription.cpp
   ctkCmdLineModuleDescriptionPrivate.h
-  ctkCmdLineModuleFuture.h
-  #ctkCmdLineModuleFuture.cpp
   ctkCmdLineModuleInstance.cpp
   ctkCmdLineModuleInstanceFactory.cpp
   ctkCmdLineModuleManager.cpp
@@ -26,10 +24,10 @@ set(KIT_SRCS
   ctkCmdLineModuleParameterGroup.cpp
   ctkCmdLineModuleParameterGroupPrivate.h
   ctkCmdLineModuleParameterParsers_p.h
-  #ctkCmdLineModuleProcess.cpp
-  ctkCmdLineModuleProcess_p.h
+  ctkCmdLineModuleProcessTask.cpp
   ctkCmdLineModuleReference.cpp
   ctkCmdLineModuleReferencePrivate.cpp
+  ctkCmdLineModuleRunException.cpp
   ctkCmdLineModuleXmlException.cpp
   ctkCmdLineModuleXmlMsgHandler_p.h
   ctkCmdLineModuleXmlMsgHandler.cpp
@@ -42,7 +40,7 @@ set(KIT_SRCS
 # Headers that should run through moc
 set(KIT_MOC_SRCS
   ctkCmdLineModuleInstance.h
-  #ctkCmdLineModuleProcess_p.h
+  ctkCmdLineModuleProcessTask.h
 )
 
 # UI files

+ 1 - 1
Libs/CommandLineModules/Core/Testing/CMakeLists.txt

@@ -1,2 +1,2 @@
 add_subdirectory(Modules)
-#add_subdirectory(Cpp)
+add_subdirectory(Cpp)

+ 14 - 5
Libs/CommandLineModules/Core/Testing/Cpp/CMakeLists.txt

@@ -1,20 +1,29 @@
 set(KIT ${PROJECT_NAME})
 
 create_test_sourcelist(Tests ${KIT}CppTests.cpp
-  ctkModuleDescriptionTest.cpp
+  ctkCmdLineModuleFutureTest.cpp
   )
 
-SET (TestsToRun ${Tests})
-REMOVE (TestsToRun ${KIT}CppTests.cpp)
+set(TestsToRun ${Tests})
+remove(TestsToRun ${KIT}CppTests.cpp)
+
+set(SRC_FILES ${Tests}
+  ctkCmdLineModuleSignalTester.cpp
+)
+
+qt4_wrap_cpp(SRC_FILES ctkCmdLineModuleSignalTester.h)
 
 set(LIBRARY_NAME ${PROJECT_NAME})
 
-add_executable(${KIT}CppTests ${Tests})
+add_executable(${KIT}CppTests ${SRC_FILES})
 target_link_libraries(${KIT}CppTests ${LIBRARY_NAME} ${CTK_BASE_LIBRARIES})
+add_dependencies(${KIT}CppTests ctkCmdLineTestModules)
 
 #
 # Add Tests
 #
 
-SIMPLE_TEST( ctkModuleDescriptionTest.cpp )
+foreach(_test ${TestsToRun})
+  SIMPLE_TEST(${_test})
+endforeach()
 

+ 113 - 0
Libs/CommandLineModules/Core/Testing/Cpp/ctkCmdLineModuleFutureTest.cpp

@@ -0,0 +1,113 @@
+/*=============================================================================
+  
+  Library: CTK
+  
+  Copyright (c) German Cancer Research Center,
+    Division of Medical and Biological Informatics
+    
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+  
+    http://www.apache.org/licenses/LICENSE-2.0
+    
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  
+=============================================================================*/
+
+#include <ctkCmdLineModuleManager.h>
+#include <ctkCmdLineModuleInstanceFactory.h>
+#include <ctkCmdLineModuleInstance.h>
+#include <ctkCmdLineModuleReference.h>
+#include <ctkCmdLineModuleDescription.h>
+#include <ctkCmdLineModuleParameter.h>
+
+#include <ctkCmdLineModuleXmlProgressWatcher.h>
+#include <QBuffer>
+
+#include "ctkCmdLineModuleSignalTester.h"
+
+#include <QVariant>
+#include <QCoreApplication>
+#include <QDebug>
+#include <QFuture>
+#include <QFutureWatcher>
+
+#include <cstdlib>
+
+
+class ctkCmdLineModuleTestInstanceFactory : public ctkCmdLineModuleInstanceFactory
+{
+public:
+
+  virtual ctkCmdLineModuleInstance* create(const ctkCmdLineModuleReference& moduleRef)
+  {
+    struct ModuleTestInstance : public ctkCmdLineModuleInstance
+    {
+      ModuleTestInstance(const ctkCmdLineModuleReference& moduleRef) : ctkCmdLineModuleInstance(moduleRef) {}
+
+      virtual QObject* guiHandle() const { return NULL; }
+
+      virtual QVariant value(const QString& parameter) const
+      {
+        return this->moduleReference().description().parameter(parameter).defaultValue();
+      }
+
+      virtual void setValue(const QString& /*parameter*/, const QVariant& /*value*/)
+      {
+        // do nothing
+      }
+    };
+
+    return new ModuleTestInstance(moduleRef);
+  }
+};
+
+
+int ctkCmdLineModuleFutureTest(int argc, char* argv[])
+{
+  QCoreApplication app(argc, argv);
+
+  ctkCmdLineModuleTestInstanceFactory factory;
+  ctkCmdLineModuleManager manager(&factory);
+
+  QString moduleFilename = app.applicationDirPath() + "/ctkCmdLineModuleTestBed";
+  ctkCmdLineModuleReference moduleRef = manager.registerModule(moduleFilename);
+  if (!moduleRef)
+  {
+    qCritical() << "Module at" << moduleFilename << "could not be registered";
+  }
+
+  ctkCmdLineModuleInstance* moduleInstance = manager.createModuleInstance(moduleRef);
+
+  QList<QString> expectedSignals;
+  expectedSignals.push_back("module.started");
+  expectedSignals.push_back("module.finished");
+
+  ctkCmdLineModuleSignalTester signalTester;
+
+  QFutureWatcher<QString> watcher;
+  QObject::connect(&watcher, SIGNAL(started()), &signalTester, SLOT(moduleStarted()));
+  QObject::connect(&watcher, SIGNAL(finished()), &signalTester, SLOT(moduleFinished()));
+
+  QFuture<QString> future = moduleInstance->run();
+  watcher.setFuture(future);
+
+  future.waitForFinished();
+
+  // process pending events
+  QCoreApplication::processEvents();
+
+  delete moduleInstance;
+
+  if (!signalTester.checkSignals(expectedSignals))
+  {
+    return EXIT_FAILURE;
+  }
+
+  return EXIT_SUCCESS;
+}

+ 89 - 0
Libs/CommandLineModules/Core/Testing/Cpp/ctkCmdLineModuleSignalTester.cpp

@@ -0,0 +1,89 @@
+/*=============================================================================
+  
+  Library: CTK
+  
+  Copyright (c) German Cancer Research Center,
+    Division of Medical and Biological Informatics
+    
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+  
+    http://www.apache.org/licenses/LICENSE-2.0
+    
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  
+=============================================================================*/
+
+#include "ctkCmdLineModuleSignalTester.h"
+
+#include <QDebug>
+
+void ctkCmdLineModuleSignalTester::moduleStarted()
+{
+  events.push_back("module.started");
+}
+
+void ctkCmdLineModuleSignalTester::moduleFinished()
+{
+  events.push_back("module.finished");
+}
+
+void ctkCmdLineModuleSignalTester::filterStarted(const QString &name, const QString &comment)
+{
+  qDebug() << "Filter started:" << name << "(" << comment << ")";
+  events.push_back("filter.started");
+}
+
+void ctkCmdLineModuleSignalTester::filterProgress(float progress)
+{
+  qDebug() << "progress:" << progress;
+  events.push_back("filter.progress");
+}
+
+void ctkCmdLineModuleSignalTester::filterFinished(const QString &name)
+{
+  qDebug() << "Filter finished:" << name;
+  events.push_back("filter.finished");
+}
+
+bool ctkCmdLineModuleSignalTester::checkSignals(const QList<QString>& expectedSignals)
+{
+  if (events.size() != expectedSignals.size())
+  {
+    dumpSignals(expectedSignals);
+    return false;
+  }
+
+  for (int i=0; i < expectedSignals.size(); ++i)
+  {
+    if (expectedSignals[i] != events[i])
+    {
+      dumpSignals(expectedSignals);
+      return false;
+    }
+  }
+  return true;
+}
+
+void ctkCmdLineModuleSignalTester::dumpSignals(const QList<QString>& expectedSignals)
+{
+  int max = events.size() > expectedSignals.size() ? events.size() : expectedSignals.size();
+  qDebug() << "Expected signal --  Actual signal";
+  for (int i = 0; i < max; ++i)
+  {
+    QString sig = i < events.size() ? events[i] : QString();
+    if (i < expectedSignals.size())
+    {
+      qDebug() << " " << expectedSignals[i] << "--" << sig;
+    }
+    else
+    {
+      qDebug() << " " << "- NONE - " << "--" << sig;
+    }
+  }
+}

+ 52 - 0
Libs/CommandLineModules/Core/Testing/Cpp/ctkCmdLineModuleSignalTester.h

@@ -0,0 +1,52 @@
+/*=============================================================================
+  
+  Library: CTK
+  
+  Copyright (c) German Cancer Research Center,
+    Division of Medical and Biological Informatics
+    
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+  
+    http://www.apache.org/licenses/LICENSE-2.0
+    
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  
+=============================================================================*/
+
+#ifndef CTKCMDLINEMODULESIGNALTESTER_H
+#define CTKCMDLINEMODULESIGNALTESTER_H
+
+#include <QObject>
+#include <QList>
+
+class ctkCmdLineModuleSignalTester : public QObject
+{
+  Q_OBJECT
+
+public:
+
+  bool checkSignals(const QList<QString>& expectedSignals);
+  void dumpSignals(const QList<QString>& expectedSignals);
+
+
+public Q_SLOTS:
+
+  void moduleStarted();
+  void moduleFinished();
+
+  void filterStarted(const QString& name, const QString& comment);
+  void filterProgress(float progress);
+  void filterFinished(const QString& name);
+
+private:
+
+  QList<QString> events;
+};
+
+#endif // CTKCMDLINEMODULESIGNALTESTER_H

+ 0 - 92
Libs/CommandLineModules/Core/Testing/Cpp/ctkModuleDescriptionTest.cpp

@@ -1,92 +0,0 @@
-/*=========================================================================
-
-  Library:   CTK
- 
-  Copyright (c) 2010  Kitware Inc.
-
-  Licensed under the Apache License, Version 2.0 (the "License");
-  you may not use this file except in compliance with the License.
-  You may obtain a copy of the License at
-
-      http://www.apache.org/licenses/LICENSE-2.0.txt
-
-  Unless required by applicable law or agreed to in writing, software
-  distributed under the License is distributed on an "AS IS" BASIS,
-  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  See the License for the specific language governing permissions and
-  limitations under the License.
- 
-=========================================================================*/
-
-// Qt includes
-#include <QTextStream>
-
-// CTK includes
-#include "ctkModuleDescription.h"
-#include <iostream>
-
-//-----------------------------------------------------------------------------
-int ctkModuleDescriptionTest(int argc, char * argv [] )
-{
-  Q_UNUSED(argc);
-  Q_UNUSED(argv);  
-
-
-  ctkModuleParameter param;
-  param[ "Tag" ] = "MyTag";
-  param[ "Name" ] = "MyName";
-  param[ "Description" ] = "MyDescription";
-  param[ "Label" ] = "MyLabel";
-  param[ "CPPType" ] = "MyCPPType";
-  param[ "Type" ] = "MyType";
-  param[ "Reference" ] = "MyReference";
-  param[ "Hidden" ] = "false";
-  param[ "ArgType" ] = "MyArgType";
-  param[ "StringToType" ] = "MyStringToType";
-  param[ "Default" ] = "MyDefault";
-  param[ "Flag" ] = "MyFlag";
-  param[ "LongFlag" ] = "MyLongFlag";
-  param[ "Constraints" ] = "MyConstraints";
-  param[ "Minimum" ] = "MyMinimum";
-  param[ "Maximum" ] = "MyMaximum";
-  param[ "Channel" ] = "MyChannel";
-  param[ "Index" ] = "MyIndex";
-  param[ "Multiple" ] = "false";
-  param[ "Aggregate" ] = "false";
-  param[ "FileExtensions" ] = ".vtk,.jpg";
-  param[ "FlagAliases" ] = "MyFlagAliases";
-  param[ "DeprecatedFlagAliases" ] = "MyDeprecatedFlagAliases";
-  param[ "LongFlagAliases" ] = "MyLongFlagAliases";
-  param[ "DeprecatedLongFlagAliases" ] = "MyDeprecatedLongFlagAliases";
-  param[ "CoordinateSystem" ] = "MyCoordinateSystem";
-
-
-  ctkModuleParameterGroup group;
-  group[ "Label" ] = "MyLabel";
-  group[ "Description" ] = "MyDescription";
-  group[ "Advanced" ] = "MyAdvanced";
-
-
-  ctkModuleDescription module;
-  module[ "Category" ] = "MyCategory";
-  module[ "Index" ] = "MyIndex";
-  module[ "Title" ] = "MyTitle";
-  module[ "Description" ] = "MyDescription";
-  module[ "DocumentationURL" ] = "MyDocumentationURL";
-  module[ "License" ] = "MyLicense";
-  module[ "Acknowledgements" ] = "MyAcknowledgements";
-  module[ "Contributor" ] = "MyContributor";
-  module[ "Type" ] = "MyType";
-  module[ "AlternativeType" ] = "MyAlternativeType";
-  module[ "Target" ] = "MyTarget";
-  module[ "AlternativeTarget" ] = "MyAlternativeTarget";
-  module[ "Location" ] = "MyLocation";
-
-  group.addParameter( new ctkModuleParameter(param) );
-  module.addParameterGroup( new ctkModuleParameterGroup(group) );
-
-  QTextStream stream(stdout);
-  stream<< module;
-
-  return EXIT_SUCCESS;
-}

+ 1 - 0
Libs/CommandLineModules/Core/Testing/Modules/CMakeLists.txt

@@ -14,6 +14,7 @@ endfunction()
 
 set(_cmdline_modules
   Blur2dImage
+  TestBed
   Tour
 )
 

+ 2 - 0
Libs/CommandLineModules/Core/Testing/Modules/TestBed/CMakeLists.txt

@@ -0,0 +1,2 @@
+
+ctkFunctionCreateCmdLineModule(TestBed)

+ 131 - 0
Libs/CommandLineModules/Core/Testing/Modules/TestBed/ctkCmdLineModuleTestBed.cpp

@@ -0,0 +1,131 @@
+/*=============================================================================
+
+  Library: CTK
+
+  Copyright (c) German Cancer Research Center,
+    Division of Medical and Biological Informatics
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+=============================================================================*/
+
+#include <ctkCommandLineParser.h>
+
+#include <QCoreApplication>
+#include <QTextStream>
+#include <QFile>
+#include <QDebug>
+#include <QTime>
+
+#include <cstdlib>
+#include <time.h>
+
+int main(int argc, char* argv[])
+{
+  QCoreApplication app(argc, argv);
+  // This is used by QSettings
+  QCoreApplication::setOrganizationName("CommonTK");
+  QCoreApplication::setApplicationName("CmdLineModuleTestBed");
+
+  ctkCommandLineParser parser;
+  // Use Unix-style argument names
+  parser.setArgumentPrefix("--", "-");
+
+  // Add command line argument names
+  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("runtime", "", QVariant::Int, "Runtime in seconds", 1);
+  parser.addArgument("exitCode", "", QVariant::Int, "Exit code", 0);
+  parser.addArgument("exitTime", "", QVariant::Int, "Exit time", 0);
+  parser.addArgument("errorText", "", QVariant::String, "Error text (will not be printed on exit code 0)");
+  QTextStream out(stdout, QIODevice::WriteOnly);
+  QTextStream err(stderr, QIODevice::WriteOnly);
+
+  // Parse the command line arguments
+  bool ok = false;
+  QHash<QString, QVariant> parsedArgs = parser.parseArguments(QCoreApplication::arguments(), &ok);
+  if (!ok)
+  {
+    err << "Error parsing arguments: " << parser.errorString() << "\n";
+    return EXIT_FAILURE;
+  }
+
+  // Show a help message
+  if (parsedArgs.contains("help") || parsedArgs.contains("h"))
+  {
+    out << parser.helpText();
+    out.setFieldWidth(parser.fieldWidth());
+    out.setFieldAlignment(QTextStream::AlignLeft);
+    out << "  <output>...";
+    out << "One or more output strings\n";
+    return EXIT_SUCCESS;
+  }
+
+  if (parsedArgs.contains("xml"))
+  {
+    QFile xmlDescription(":/ctkCmdLineModuleTestBed.xml");
+    xmlDescription.open(QIODevice::ReadOnly);
+    out << xmlDescription.readAll();
+    return EXIT_SUCCESS;
+  }
+
+  // Do something
+
+  float runtime = parsedArgs["runtime"].toFloat();
+  float exitTime = parsedArgs["exitTime"].toFloat();
+  int exitTimeMillis = static_cast<long>(exitTime/2.0 * 1000.0);
+  int exitCode = parsedArgs["exitCode"].toInt();
+  QString errorText = parsedArgs["errorText"].toString();
+
+  QStringList outputs = parser.unparsedArguments();
+
+  if (outputs.empty())
+  {
+    // no outputs given, just return
+    if (exitCode != 0)
+    {
+      err << errorText;
+    }
+    return exitCode;
+  }
+
+  float stepTime = runtime / static_cast<float>(outputs.size());
+
+  QTime time;
+  time.start();
+
+  struct timespec nanostep;
+
+  foreach(QString output, outputs)
+  {
+    if (exitTimeMillis != 0 && exitTimeMillis < time.elapsed())
+    {
+      if (exitCode != 0)
+      {
+        err << errorText;
+      }
+      return exitCode;
+    }
+
+    // simulate some work
+    nanostep.tv_sec = static_cast<time_t>(stepTime);
+    double millisecs = (stepTime - static_cast<time_t>(stepTime)) * 1000.0;
+    nanostep.tv_nsec = static_cast<long>(millisecs * 1000.0 * 1000.0);
+    nanosleep(&nanostep, NULL);
+
+    // print the first output
+    out << output; endl(out);
+  }
+
+  return EXIT_SUCCESS;
+}

+ 5 - 0
Libs/CommandLineModules/Core/Testing/Modules/TestBed/ctkCmdLineModuleTestBed.qrc

@@ -0,0 +1,5 @@
+<RCC>
+    <qresource prefix="/">
+        <file>ctkCmdLineModuleTestBed.xml</file>
+    </qresource>
+</RCC>

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

@@ -0,0 +1,58 @@
+<?xml version="1.0" encoding="utf-8"?>
+<executable>
+  <category>Testing</category>
+  <title>Test Bed</title>
+  <description>
+Configurable behaviour for testing purposes.
+  </description>
+  <version>1.0</version>
+  <documentation-url></documentation-url>
+  <license></license>
+  <contributor>Sascha Zelzer</contributor>
+
+  <parameters>
+    <label>Runtime behaviour</label>
+    <description>Configures the runtime behaviour of this module.</description>
+    <integer>
+      <name>runtimeVar</name>
+      <longflag>runtime</longflag>
+      <description>An integer without constraints</description>
+      <label>Runtime (seconds)</label>
+      <default>1</default>
+      <constraints>
+        <minimum>0</minimum>
+        <maximum>60</maximum>
+        <step>1</step>
+      </constraints>
+    </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>exitTimeVar</name>
+      <longflag>exitTime</longflag>
+      <description>The exit time of the module (premature finish).</description>
+      <label>Exit time</label>
+      <default>0</default>
+    </integer>
+    <integer>
+      <name>exitCodeVar</name>
+      <longflag>exitCode</longflag>
+      <description>The exit code of the module.</description>
+      <label>Exit code</label>
+      <default>0</default>
+    </integer>
+    <string>
+      <name>errorTextVar</name>
+      <longflag>errorText</longflag>
+      <description>Final error message (not displayed if the exit code is 0).</description>
+      <label>Error text</label>
+    </string>
+  </parameters>
+
+</executable>
+

+ 0 - 97
Libs/CommandLineModules/Core/ctkCmdLineModuleFuture.cpp

@@ -1,97 +0,0 @@
-/*=============================================================================
-  
-  Library: CTK
-  
-  Copyright (c) German Cancer Research Center,
-    Division of Medical and Biological Informatics
-    
-  Licensed under the Apache License, Version 2.0 (the "License");
-  you may not use this file except in compliance with the License.
-  You may obtain a copy of the License at
-  
-    http://www.apache.org/licenses/LICENSE-2.0
-    
-  Unless required by applicable law or agreed to in writing, software
-  distributed under the License is distributed on an "AS IS" BASIS,
-  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  See the License for the specific language governing permissions and
-  limitations under the License.
-  
-=============================================================================*/
-
-#include "ctkCmdLineModuleFuture.h"
-
-struct ctkCmdLineModuleFutureInterfacePrivate
-{
-  ctkCmdLineModuleFutureInterfacePrivate()
-    : refCount(1), _exitCode(0), _exitStatus(QProcess::NormalExit),
-      _processError(QProcess::UnknownError)
-  {}
-
-  QAtomicInt refCount;
-
-  int _exitCode;
-  QProcess::ExitStatus _exitStatus;
-  QProcess::ProcessError _processError;
-  QString _errorString;
-  QString _stdOut;
-  QString _stdErr;
-};
-
-ctkCmdLineModuleFutureInterface::QFutureInterface(State initialState)
-  : QFutureInterfaceBase(initialState), d(new ctkCmdLineModuleFutureInterfacePrivate)
-{ }
-
-ctkCmdLineModuleFutureInterface::QFutureInterface(const ctkCmdLineModuleFutureInterface& other)
-  : QFutureInterfaceBase(other), d(other.d)
-{
-  d->refCount.ref();
-}
-
-ctkCmdLineModuleFutureInterface ctkCmdLineModuleFutureInterface::canceledResult()
-{ return ctkCmdLineModuleFutureInterface(State(Started | Finished | Canceled)); }
-
-ctkCmdLineModuleFutureInterface& ctkCmdLineModuleFutureInterface::operator=(const ctkCmdLineModuleFutureInterface& other)
-{
-  QFutureInterfaceBase::operator=(other);
-  other.d->refCount.ref();
-  if(!d->refCount.deref()) delete d;
-  d = other.d;
-  return *this;
-}
-
-int ctkCmdLineModuleFutureInterface::exitCode() const
-{ QMutexLocker lock(this->mutex()); return d->_exitCode; }
-
-void ctkCmdLineModuleFutureInterface::reportExitCode(int code)
-{ QMutexLocker lock(this->mutex()); d->_exitCode = code; }
-
-QProcess::ExitStatus ctkCmdLineModuleFutureInterface::exitStatus() const
-{ QMutexLocker lock(this->mutex()); return d->_exitStatus; }
-
-void ctkCmdLineModuleFutureInterface::reportExitStatus(QProcess::ExitStatus status)
-{ QMutexLocker lock(this->mutex()); d->_exitStatus = status; }
-
-QProcess::ProcessError ctkCmdLineModuleFutureInterface::error() const
-{ QMutexLocker lock(this->mutex()); return d->_processError; }
-
-void ctkCmdLineModuleFutureInterface::reportProcessError(QProcess::ProcessError procErr)
-{ QMutexLocker lock(this->mutex()); d->_processError = procErr; }
-
-QString ctkCmdLineModuleFutureInterface::errorString() const
-{ QMutexLocker lock(this->mutex()); return d->_errorString; }
-
-void ctkCmdLineModuleFutureInterface::reportErrorString(const QString& errorStr)
-{ QMutexLocker lock(this->mutex()); d->_errorString = errorStr; }
-
-QString ctkCmdLineModuleFutureInterface::standardOutput() const
-{ QMutexLocker lock(this->mutex()); return d->_stdOut; }
-
-void ctkCmdLineModuleFutureInterface::reportStandardOutput(const QString& stdOut)
-{ QMutexLocker lock(this->mutex()); d->_stdOut = stdOut; }
-
-QString ctkCmdLineModuleFutureInterface::standardError() const
-{ QMutexLocker lock(this->mutex()); return d->_stdErr; }
-
-void ctkCmdLineModuleFutureInterface::reportStandardError(const QString& stdErr)
-{ QMutexLocker lock(this->mutex()); d->_stdErr = stdErr; }

+ 0 - 93
Libs/CommandLineModules/Core/ctkCmdLineModuleFuture.h

@@ -1,93 +0,0 @@
-/*=============================================================================
-  
-  Library: CTK
-  
-  Copyright (c) German Cancer Research Center,
-    Division of Medical and Biological Informatics
-    
-  Licensed under the Apache License, Version 2.0 (the "License");
-  you may not use this file except in compliance with the License.
-  You may obtain a copy of the License at
-  
-    http://www.apache.org/licenses/LICENSE-2.0
-    
-  Unless required by applicable law or agreed to in writing, software
-  distributed under the License is distributed on an "AS IS" BASIS,
-  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  See the License for the specific language governing permissions and
-  limitations under the License.
-  
-=============================================================================*/
-
-#ifndef CTKCMDLINEMODULEFUTURE_H
-#define CTKCMDLINEMODULEFUTURE_H
-
-#include <ctkCommandLineModulesCoreExport.h>
-
-//#include <QFutureInterface>
-//#include <QFutureWatcher>
-#include <QProcess>
-
-/**
- * \ingroup CommandLineModulesCore
- */
-class ctkCmdLineModuleFuture
-{
-
-public:
-
-  ctkCmdLineModuleFuture()
-    : d(ctkCmdLineModuleFutureInterface::canceledResult())
-  { }
-
-  explicit ctkCmdLineModuleFuture(const ctkCmdLineModuleProcess& p) // internal
-    : d(*p)
-  { }
-
-  ctkCmdLineModuleFuture(const ctkCmdLineModuleFuture &other)
-    : d(other.d)
-  { }
-
-  ~ctkCmdLineModuleFuture()
-  { }
-
-  ctkCmdLineModuleFuture& operator=(const ctkCmdLineModuleFuture& other);
-  bool operator==(const ctkCmdLineModuleFuture& other) const { return (d == other.d); }
-  bool operator!=(const ctkCmdLineModuleFuture& other) const { return (d != other.d); }
-
-  void cancel() { d.cancel(); }
-  bool isCanceled() const { return d.isCanceled(); }
-
-  bool isStarted() const { return d.isStarted(); }
-  bool isFinished() const { return d.isFinished(); }
-  bool isRunning() const { return d.isRunning(); }
-
-  int exitCode() const { return d.exitCode(); }
-  int exitStatus() const { return d.exitStatus(); }
-  QProcess::ProcessError error() const { return d.error(); }
-  QString errorString() const { return d.errorString(); }
-
-  QString standardOutput() const { return d.standardOutput(); }
-  QString standardError() const { return d.standardError(); }
-
-  int progressValue() const { return d.progressValue(); }
-  int progressMinimum() const { return d.progressMinimum(); }
-  int progressMaximum() const { return d.progressMaximum(); }
-  QString progressText() const { return d.progressText(); }
-  void waitForFinished() { d.waitForFinished(); }
-
-private:
-
-  friend class ctkCmdLineModuleFutureWatcher;
-
-  mutable ctkCmdLineModuleProcess d;
-};
-
-
-inline ctkCmdLineModuleFuture& ctkCmdLineModuleFuture::operator=(const ctkCmdLineModuleFuture& other)
-{
-  d = other.d;
-  return *this;
-}
-
-#endif // CTKCMDLINEMODULEFUTURE_H

+ 9 - 9
Libs/CommandLineModules/Core/ctkCmdLineModuleInstance.cpp

@@ -24,12 +24,13 @@
 #include "ctkCmdLineModuleParameter.h"
 #include "ctkCmdLineModuleParameterGroup.h"
 #include "ctkCmdLineModuleReference.h"
-#include "ctkCmdLineModuleProcess_p.h"
+#include "ctkCmdLineModuleProcessTask.h"
 
 #include "ctkException.h"
 
 #include <QStringList>
 #include <QDebug>
+#include <QFuture>
 
 
 struct ctkCmdLineModuleInstancePrivate
@@ -146,16 +147,15 @@ QStringList ctkCmdLineModuleInstance::commandLineArguments() const
   return cmdLineArgs;
 }
 
-struct ctkCmdLineModuleFuture {};
-
-ctkCmdLineModuleFuture ctkCmdLineModuleInstance::run() const
+QFuture<QString> ctkCmdLineModuleInstance::run() const
 {
-//  // TODO: manage memory
   QStringList args = commandLineArguments();
-  qDebug() << args;
-//  ctkCmdLineModuleProcessRunner* moduleProcess =
-//      new ctkCmdLineModuleProcessRunner(d->ModuleReference.location(), args);
-//  return moduleProcess->start();
+
+  // Instances of ctkCmdLineModuleProcessTask are auto-deleted by the
+  // thread pool.
+  ctkCmdLineModuleProcessTask* moduleProcess =
+      new ctkCmdLineModuleProcessTask(d->ModuleReference.location(), args);
+  return moduleProcess->start();
 }
 
 

+ 2 - 4
Libs/CommandLineModules/Core/ctkCmdLineModuleInstance.h

@@ -27,8 +27,8 @@
 #include <QObject>
 
 template<class K, class V> class QHash;
+template<class T> class QFuture;
 
-class ctkCmdLineModuleFuture;
 class ctkCmdLineModuleReference;
 class ctkCmdLineModuleInstancePrivate;
 
@@ -59,7 +59,7 @@ public:
 
   QStringList commandLineArguments() const;
 
-  ctkCmdLineModuleFuture run() const;
+  QFuture<QString> run() const;
 
   Q_SIGNAL void valueChanged(const QString& parameter, const QVariant& value);
 
@@ -67,8 +67,6 @@ protected:
 
   ctkCmdLineModuleInstance(const ctkCmdLineModuleReference& moduleRef);
 
-  //virtual QObject* parameterValueModel() const;
-
 private:
 
   friend class ctkCmdLineModuleInstancePrivate;

+ 0 - 67
Libs/CommandLineModules/Core/ctkCmdLineModuleProcess.cpp

@@ -1,67 +0,0 @@
-/*=============================================================================
-  
-  Library: CTK
-  
-  Copyright (c) German Cancer Research Center,
-    Division of Medical and Biological Informatics
-    
-  Licensed under the Apache License, Version 2.0 (the "License");
-  you may not use this file except in compliance with the License.
-  You may obtain a copy of the License at
-  
-    http://www.apache.org/licenses/LICENSE-2.0
-    
-  Unless required by applicable law or agreed to in writing, software
-  distributed under the License is distributed on an "AS IS" BASIS,
-  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  See the License for the specific language governing permissions and
-  limitations under the License.
-  
-=============================================================================*/
-
-#include "ctkCmdLineModuleProcess_p.h"
-
-
-ctkCmdLineModuleProcess::ctkCmdLineModuleProcess(const QString& location, const QStringList& args)
-  : process(), location(location), args(args)
-{
-}
-
-ctkCmdLineModuleFuture ctkCmdLineModuleProcess::start()
-{
-  this->reportStarted();
-  ctkCmdLineModuleFuture future(this);
-  connect(&process, SIGNAL(started()), this, SLOT(processStarted()));
-  connect(&process, SIGNAL(error(QProcess::ProcessError)), this, SLOT(processError(QProcess::ProcessError)));
-  connect(&process, SIGNAL(finished(int,QProcess::ExitStatus)), this, SLOT(processFinished(int,QProcess::ExitStatus)));
-
-  process.start(location, args);
-  return future;
-}
-
-void ctkCmdLineModuleProcess::processStarted()
-{
-  qDebug() << "Reporting process started";
-  this->reportStarted();
-}
-
-void ctkCmdLineModuleProcess::processFinished(int exitCode, QProcess::ExitStatus status)
-{
-  Q_UNUSED(exitCode)
-  Q_UNUSED(status)
-  qDebug() << "Reporting process finished";
-  this->reportExitCode(exitCode);
-  this->reportExitStatus(status);
-  this->reportProcessError(process.error());
-  this->reportErrorString(process.errorString());
-  this->reportStandardOutput(process.readAllStandardOutput());
-  this->reportStandardError(process.readAllStandardError());
-  this->reportFinished();
-}
-
-void ctkCmdLineModuleProcess::processError(QProcess::ProcessError)
-{
-  //qDebug() << "Reporting process error";
-  //this->reportException(ctkCmdLineModuleProcessException(process.errorString(), process.exitCode(),
-  //                                                process.exitStatus()));
-}

+ 94 - 0
Libs/CommandLineModules/Core/ctkCmdLineModuleProcessTask.cpp

@@ -0,0 +1,94 @@
+/*=============================================================================
+  
+  Library: CTK
+  
+  Copyright (c) German Cancer Research Center,
+    Division of Medical and Biological Informatics
+    
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+  
+    http://www.apache.org/licenses/LICENSE-2.0
+    
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  
+=============================================================================*/
+
+#include "ctkCmdLineModuleProcessTask.h"
+#include "ctkCmdLineModuleRunException.h"
+
+#include <QDebug>
+#include <QEventLoop>
+#include <QThreadPool>
+#include <QProcess>
+#include <QFuture>
+
+
+ctkCmdLineModuleProcessTask::ctkCmdLineModuleProcessTask(const QString& location, const QStringList& args)
+  : location(location), args(args)
+{
+}
+
+ctkCmdLineModuleProcessTask::~ctkCmdLineModuleProcessTask()
+{
+}
+
+QFuture<QString> ctkCmdLineModuleProcessTask::start()
+{
+  this->setRunnable(this);
+  this->reportStarted();
+  QFuture<QString> future = this->future();
+  QThreadPool::globalInstance()->start(this, /*m_priority*/ 0);
+  return future;
+}
+
+void ctkCmdLineModuleProcessTask::run()
+{
+  if (this->isCanceled())
+  {
+    this->reportFinished();
+    return;
+  }
+
+  QProcess process;
+  QEventLoop localLoop;
+  connect(&process, SIGNAL(finished(int)), &localLoop, SLOT(quit()));
+  connect(&process, SIGNAL(error(QProcess::ProcessError)), SLOT(error(QProcess::ProcessError)));
+  connect(&process, SIGNAL(readyReadStandardError()), SLOT(readyReadStandardError()));
+  connect(&process, SIGNAL(readyReadStandardOutput()), SLOT(readyReadStandardOutput()));
+
+  process.start(location, args);
+
+  localLoop.exec();
+
+  if (process.exitCode() != 0 || process.exitStatus() == QProcess::CrashExit)
+  {
+    QString msg = "The process running \"%1\" ";
+    msg += process.exitStatus() == QProcess::CrashExit ? QString("crashed: ")
+                                                     : QString("exited with code %1: ").arg(process.exitCode());
+    msg += process.readAllStandardError();
+    this->reportException(ctkCmdLineModuleRunException(msg));
+  }
+
+  this->setProgressValueAndText(100, process.readAllStandardOutput());
+
+  //this->reportResult(result);
+  this->reportFinished();
+}
+
+void ctkCmdLineModuleProcessTask::error(QProcess::ProcessError error)
+{
+}
+
+void ctkCmdLineModuleProcessTask::readyReadStandardError()
+{
+}
+
+void ctkCmdLineModuleProcessTask::readyReadStandardOutput()
+{
+}

+ 17 - 14
Libs/CommandLineModules/Core/ctkCmdLineModuleProcess_p.h

@@ -19,37 +19,40 @@
   
 =============================================================================*/
 
-#ifndef CTKCMDLINEMODULEPROCESS_P_H
-#define CTKCMDLINEMODULEPROCESS_P_H
+#ifndef CTKCMDLINEMODULEPROCESSTASK_H
+#define CTKCMDLINEMODULEPROCESSTASK_H
+
+#include <QFutureInterface>
 
 #include <QObject>
+#include <QRunnable>
+#include <QStringList>
 #include <QProcess>
 
-class ctkCmdLineModuleFuture;
-
-class ctkCmdLineModuleProcess : public QObject
+class ctkCmdLineModuleProcessTask : public QObject, public QFutureInterface<QString>, public QRunnable
 {
   Q_OBJECT
 
 public:
 
-  ctkCmdLineModuleProcess(const QString& location, const QStringList& args);
+  ctkCmdLineModuleProcessTask(const QString& location, const QStringList& args);
+  ~ctkCmdLineModuleProcessTask();
 
-  ctkCmdLineModuleFuture start();
+  QFuture<QString> start();
 
-protected Q_SLOTS:
+  void run();
 
-  void processStarted();
-
-  void processFinished(int exitCode, QProcess::ExitStatus status);
+protected Q_SLOTS:
 
-  void processError(QProcess::ProcessError);
+  void error(QProcess::ProcessError error);
+  void readyReadStandardError();
+  void readyReadStandardOutput();
 
 private:
 
-  QProcess process;
   const QString location;
   const QStringList args;
+  QString result;
 };
 
-#endif // CTKCMDLINEMODULEPROCESSRUNNER_P_H
+#endif // CTKCMDLINEMODULEPROCESSTASK_H

+ 61 - 0
Libs/CommandLineModules/Core/ctkCmdLineModuleRunException.cpp

@@ -0,0 +1,61 @@
+/*===================================================================
+  
+BlueBerry Platform
+
+Copyright (c) German Cancer Research Center, 
+Division of Medical and Biological Informatics.
+All rights reserved.
+
+This software is distributed WITHOUT ANY WARRANTY; without 
+even the implied warranty of MERCHANTABILITY or FITNESS FOR 
+A PARTICULAR PURPOSE.
+
+See LICENSE.txt or http://www.mitk.org for details.
+
+===================================================================*/
+
+#include "ctkCmdLineModuleRunException.h"
+
+ctkCmdLineModuleRunException::ctkCmdLineModuleRunException(const QString& msg)
+  : QtConcurrent::Exception(), ctkException(msg)
+{
+}
+
+ctkCmdLineModuleRunException::ctkCmdLineModuleRunException(const QString& msg, const ctkCmdLineModuleRunException& cause)
+  : QtConcurrent::Exception(), ctkException(msg, cause)
+{
+}
+
+ctkCmdLineModuleRunException::ctkCmdLineModuleRunException(const ctkCmdLineModuleRunException& o)
+  : QtConcurrent::Exception(o), ctkException(o)
+{
+}
+
+ctkCmdLineModuleRunException::~ctkCmdLineModuleRunException() throw()
+{
+}
+
+const char* ctkCmdLineModuleRunException::name() const throw()
+{
+  return "CTK CommandLineModule Run Exception";
+}
+
+const char* ctkCmdLineModuleRunException::className() const throw()
+{
+  return "ctkCmdLineModuleRunException";
+}
+
+ctkCmdLineModuleRunException* ctkCmdLineModuleRunException::clone() const
+{
+  return new ctkCmdLineModuleRunException(*this);
+}
+
+void ctkCmdLineModuleRunException::rethrow() const
+{
+  throw *this;
+}
+
+void ctkCmdLineModuleRunException::raise() const
+{
+  throw *this;
+}

+ 46 - 0
Libs/CommandLineModules/Core/ctkCmdLineModuleRunException.h

@@ -0,0 +1,46 @@
+/*===================================================================
+  
+BlueBerry Platform
+
+Copyright (c) German Cancer Research Center, 
+Division of Medical and Biological Informatics.
+All rights reserved.
+
+This software is distributed WITHOUT ANY WARRANTY; without 
+even the implied warranty of MERCHANTABILITY or FITNESS FOR 
+A PARTICULAR PURPOSE.
+
+See LICENSE.txt or http://www.mitk.org for details.
+
+===================================================================*/
+
+#ifndef CTKCMDLINEMODULERUNEXCEPTION_H
+#define CTKCMDLINEMODULERUNEXCEPTION_H
+
+#include <ctkException.h>
+
+#include <QtCore>
+
+class ctkCmdLineModuleRunException : public QtConcurrent::Exception, public ctkException
+{
+public:
+
+  explicit ctkCmdLineModuleRunException(const QString& msg);
+
+  ctkCmdLineModuleRunException(const QString& msg, const ctkCmdLineModuleRunException& cause);
+  ctkCmdLineModuleRunException(const ctkCmdLineModuleRunException& o);
+
+  ctkCmdLineModuleRunException& operator=(const ctkCmdLineModuleRunException& o);
+
+  ~ctkCmdLineModuleRunException() throw();
+
+  virtual const char* name() const throw();
+  virtual const char* className() const throw();
+  virtual ctkCmdLineModuleRunException* clone() const;
+  virtual void rethrow() const;
+
+  virtual void raise() const;
+
+};
+
+#endif // CTKCMDLINEMODULERUNEXCEPTION_H