Sfoglia il codice sorgente

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

Sascha Zelzer 12 anni fa
parent
commit
ba055de2ef
22 ha cambiato i file con 709 aggiunte e 397 eliminazioni
  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