Browse Source

Trap exceptions from concurrent registrations of CLI and report error messages and references

Matt Clarkson 11 years ago
parent
commit
4397a1dfe7

+ 13 - 9
Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerMainWindow.cpp

@@ -28,7 +28,7 @@
 #include "ctkCmdLineModuleExplorerTabList.h"
 #include "ctkCmdLineModuleExplorerProgressWidget.h"
 #include "ctkCmdLineModuleExplorerConstants.h"
-#include "ctkCmdLineModuleExplorerUtils.h"
+#include "ctkCmdLineModuleUtils.h"
 
 #include <ctkCmdLineModuleManager.h>
 #include <ctkCmdLineModuleConcurrentHelpers.h>
@@ -38,6 +38,7 @@
 #include <ctkCmdLineModuleBackendLocalProcess.h>
 #include <ctkCmdLineModuleBackendFunctionPointer.h>
 #include <ctkCmdLineModuleBackendXMLChecker.h>
+#include <ctkCmdLineModuleReferenceResult.h>
 #include <ctkException.h>
 #include <ctkCmdLineModuleXmlException.h>
 
@@ -143,8 +144,12 @@ ctkCLModuleExplorerMainWindow::ctkCLModuleExplorerMainWindow(QWidget *parent) :
   }
 
   // Register persistent modules
-  QFuture<ctkCmdLineModuleReference> future = QtConcurrent::mapped(settings.value(ctkCmdLineModuleExplorerConstants::KEY_REGISTERED_MODULES).toStringList(),
-                                                                   ctkCmdLineModuleConcurrentRegister(&moduleManager, true));
+  QFuture<ctkCmdLineModuleReferenceResult> future = QtConcurrent::mapped(settings.value(ctkCmdLineModuleExplorerConstants::KEY_REGISTERED_MODULES).toStringList(),
+                                                                         ctkCmdLineModuleConcurrentRegister(&moduleManager, true));
+  future.waitForFinished();
+
+  ctkCmdLineModuleUtils::messageBoxModuleRegistration(future,
+                                                      moduleManager.validationMode());
 
   // Start watching directories
   directoryWatcher.setDebug(true);
@@ -153,9 +158,6 @@ ctkCLModuleExplorerMainWindow::ctkCLModuleExplorerMainWindow(QWidget *parent) :
   moduleTabActivated(NULL);
 
   pollPauseTimer.start();
-
-  ctkCmdLineModuleExplorerUtils::messageBoxModuleRegistration(future,
-                                                              moduleManager.validationMode());
 }
 
 
@@ -286,12 +288,14 @@ void ctkCLModuleExplorerMainWindow::on_actionLoad_triggered()
   QStringList fileNames = QFileDialog::getOpenFileNames(this, tr("Load modules..."));
 
   this->setCursor(Qt::BusyCursor);
-  QFuture<ctkCmdLineModuleReference> future = QtConcurrent::mapped(fileNames, ctkCmdLineModuleConcurrentRegister(&this->moduleManager));
+
+  QFuture<ctkCmdLineModuleReferenceResult> future = QtConcurrent::mapped(fileNames, ctkCmdLineModuleConcurrentRegister(&this->moduleManager));
   future.waitForFinished();
+
   this->unsetCursor();
 
-  ctkCmdLineModuleExplorerUtils::messageBoxModuleRegistration(future,
-                                                              this->moduleManager.validationMode());
+  ctkCmdLineModuleUtils::messageBoxModuleRegistration(future,
+                                                      this->moduleManager.validationMode());
 }
 
 

+ 5 - 4
Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerModulesSettings.cpp

@@ -23,7 +23,7 @@
 #include "ctkCmdLineModuleExplorerConstants.h"
 #include "ctkCmdLineModuleExplorerUtils.h"
 #include "ctkCmdLineModuleExplorerShowXmlAction.h"
-#include "ctkCmdLineModuleExplorerUtils.h"
+#include "ctkCmdLineModuleUtils.h"
 
 #include "ui_ctkCmdLineModuleExplorerModulesSettings.h"
 
@@ -83,7 +83,7 @@ void ctkCmdLineModuleExplorerModulesSettings::applySettings()
   this->setCursor(Qt::BusyCursor);
 
   QFuture<void> future1 = QtConcurrent::mapped(removedModules, ctkCmdLineModuleConcurrentUnRegister(this->ModuleManager));
-  QFuture<ctkCmdLineModuleReference> future2 = QtConcurrent::mapped(addedModules, ctkCmdLineModuleConcurrentRegister(this->ModuleManager, true));
+  QFuture<ctkCmdLineModuleReferenceResult> future2 = QtConcurrent::mapped(addedModules, ctkCmdLineModuleConcurrentRegister(this->ModuleManager, true));
 
   ctkSettingsPanel::applySettings();
 
@@ -102,8 +102,9 @@ void ctkCmdLineModuleExplorerModulesSettings::applySettings()
 
   this->unsetCursor();
 
-  ctkCmdLineModuleExplorerUtils::messageBoxModuleRegistration(future2,
-                                                              this->ModuleManager->validationMode());
+  future2.waitForFinished();
+  ctkCmdLineModuleUtils::messageBoxModuleRegistration(future2,
+                                                      this->ModuleManager->validationMode());
 
 }
 

+ 0 - 44
Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerUtils.cpp

@@ -20,13 +20,8 @@
 =============================================================================*/
 
 #include "ctkCmdLineModuleExplorerUtils.h"
-#include "ctkCmdLineModuleRunException.h"
 
 #include <QPainter>
-#include <QObject>
-#include <QWidget>
-#include <QApplication>
-#include <QMessageBox>
 
 QPixmap ctkCmdLineModuleExplorerUtils::createIconOverlay(const QPixmap &base, const QPixmap &overlay)
 {
@@ -39,42 +34,3 @@ QPixmap ctkCmdLineModuleExplorerUtils::createIconOverlay(const QPixmap &base, co
                      overlay.scaled(base.width()/2, base.height()/2, Qt::KeepAspectRatio));
   return result;
 }
-
-void ctkCmdLineModuleExplorerUtils::messageBoxModuleRegistration(const QFuture<ctkCmdLineModuleReference>& moduleRefsFuture,
-                                                                  ctkCmdLineModuleManager::ValidationMode validationMode)
-{
-  QString errorMsg;
-  QFutureIterator<ctkCmdLineModuleReference> futureIter(moduleRefsFuture);
-  while(futureIter.hasNext())
-  {
-    try
-    {
-      const ctkCmdLineModuleReference& moduleRef = futureIter.next();
-      if (!moduleRef)
-      {
-        errorMsg += QObject::tr("Failed to register ") + moduleRef.location().toString() + "\n\n";
-      }
-      else if (!moduleRef.xmlValidationErrorString().isEmpty() &&
-             validationMode == ctkCmdLineModuleManager::STRICT_VALIDATION)
-      {
-        errorMsg += QObject::tr("Failed to register ") + moduleRef.location().toString() + ":\n" + moduleRef.xmlValidationErrorString() + "\n\n";
-      }
-    }
-    catch (const ctkCmdLineModuleRunException& e)
-    {
-      errorMsg += QObject::tr("Failed to register module ") + e.location().toString() + ":\n" + e.message() + "\n\\n";
-    }
-
-    catch (const std::exception& e)
-    {
-      errorMsg += QObject::tr("Failed to register module:\n") + e.what() + "\n\n";
-    }
-  }
-
-  if (!errorMsg.isEmpty())
-  {
-    QWidget* widget = QApplication::activeModalWidget();
-    if (widget == NULL) widget = QApplication::activeWindow();
-    QMessageBox::critical(widget, QObject::tr("Failed to register modules"), errorMsg);
-  }
-}

+ 0 - 8
Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerUtils.h

@@ -22,19 +22,11 @@
 #ifndef CTKCOMMANDLINEMODULEEXPLORERUTILS_H
 #define CTKCOMMANDLINEMODULEEXPLORERUTILS_H
 
-#include "ctkCmdLineModuleManager.h"
-
 #include <QPixmap>
-#include <QFuture>
 
 struct ctkCmdLineModuleExplorerUtils
 {
-
   static QPixmap createIconOverlay(const QPixmap& base, const QPixmap& overlay);
-
-  static void messageBoxModuleRegistration(const QFuture<ctkCmdLineModuleReference>& moduleRefsFuture,
-                                           ctkCmdLineModuleManager::ValidationMode validationMode);
-
 };
 
 #endif // CTKCOMMANDLINEMODULEEXPLORERUTILS_H

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

@@ -43,6 +43,7 @@ set(KIT_SRCS
   ctkCmdLineModuleReference.cpp
   ctkCmdLineModuleRunException.cpp
   ctkCmdLineModuleTimeoutException.cpp
+  ctkCmdLineModuleUtils.cpp
   ctkCmdLineModuleXmlException.cpp
   ctkCmdLineModuleXmlMsgHandler_p.h
   ctkCmdLineModuleXmlMsgHandler.cpp

+ 14 - 12
Libs/CommandLineModules/Core/ctkCmdLineModuleConcurrentHelpers.cpp

@@ -35,43 +35,45 @@ ctkCmdLineModuleConcurrentRegister::ctkCmdLineModuleConcurrentRegister(ctkCmdLin
 {}
 
 //----------------------------------------------------------------------------
-ctkCmdLineModuleReference ctkCmdLineModuleConcurrentRegister::operator()(const QString& moduleLocation)
+ctkCmdLineModuleReferenceResult ctkCmdLineModuleConcurrentRegister::operator()(const QString& moduleLocation)
 {
   return this->operator ()(QUrl::fromLocalFile(moduleLocation));
 }
 
 //----------------------------------------------------------------------------
-ctkCmdLineModuleReference ctkCmdLineModuleConcurrentRegister::operator()(const QUrl& moduleUrl)
+ctkCmdLineModuleReferenceResult ctkCmdLineModuleConcurrentRegister::operator()(const QUrl& moduleUrl)
 {
   try
   {
-    return this->ModuleManager->registerModule(moduleUrl);
+    ctkCmdLineModuleReference reference = this->ModuleManager->registerModule(moduleUrl);
+    return ctkCmdLineModuleReferenceResult(reference);
   }
-  catch (const QtConcurrent::Exception& e)
+  catch (const ctkException& e)
   {
     if (this->Debug)
     {
-      qDebug() << e.what();
+      qDebug() << e.message();
     }
-    throw e;
+    return ctkCmdLineModuleReferenceResult(moduleUrl, e.message());
   }
-  catch (const ctkException& e)
+  catch (const QtConcurrent::Exception& e)
   {
     if (this->Debug)
     {
-      qDebug() << e;
+      qDebug() << e.what();
     }
-    throw ctkCmdLineModuleRunException(moduleUrl, 0, e.what());
+    return ctkCmdLineModuleReferenceResult(moduleUrl, e.what());
   }
   catch (...)
   {
+    QString errorMessage = QObject::tr("Module %1 failed with an unknown exception.").arg(moduleUrl.toString());
     if (this->Debug)
     {
-      qDebug() << "Registering module" << moduleUrl << "failed with an unknown exception.";
+      qDebug() << errorMessage;
     }
-    throw ctkCmdLineModuleRunException(moduleUrl, 0, "Unknown exception");
+    return ctkCmdLineModuleReferenceResult(moduleUrl, errorMessage);
   }
-  return ctkCmdLineModuleReference();
+  return ctkCmdLineModuleReferenceResult(moduleUrl);
 }
 
 //----------------------------------------------------------------------------

+ 4 - 4
Libs/CommandLineModules/Core/ctkCmdLineModuleConcurrentHelpers.h

@@ -24,7 +24,7 @@
 
 #include "ctkCommandLineModulesCoreExport.h"
 
-#include "ctkCmdLineModuleReference.h"
+#include "ctkCmdLineModuleReferenceResult.h"
 
 class ctkCmdLineModuleManager;
 
@@ -38,11 +38,11 @@ class CTK_CMDLINEMODULECORE_EXPORT ctkCmdLineModuleConcurrentRegister
 
 public:
 
-  typedef ctkCmdLineModuleReference result_type;
+  typedef ctkCmdLineModuleReferenceResult result_type;
 
   ctkCmdLineModuleConcurrentRegister(ctkCmdLineModuleManager* manager, bool debug = false);
-  ctkCmdLineModuleReference operator()(const QString& moduleLocation);
-  ctkCmdLineModuleReference operator()(const QUrl& moduleUrl);
+  result_type operator()(const QString& moduleLocation);
+  result_type operator()(const QUrl& moduleUrl);
 
 private:
 

+ 17 - 17
Libs/CommandLineModules/Core/ctkCmdLineModuleDirectoryWatcher.cpp

@@ -132,7 +132,7 @@ void ctkCmdLineModuleDirectoryWatcherPrivate::setDirectories(const QStringList&
 {
   QStringList validDirectories = this->filterInvalidDirectories(directories);
   this->setModules(validDirectories);
-  this->updateWatchedPaths(validDirectories, this->MapFileNameToReference.keys());
+  this->updateWatchedPaths(validDirectories, this->MapFileNameToReferenceResult.keys());
 }
 
 
@@ -169,20 +169,20 @@ void ctkCmdLineModuleDirectoryWatcherPrivate::setAdditionalModules(const QString
   QStringList filteredAdditionalModules = this->filterFilesNotInCurrentDirectories(this->AdditionalModules);
 
   this->unloadModules(filteredAdditionalModules);
-  QList<ctkCmdLineModuleReference> refs = this->loadModules(filteredFileNames);
+  QList<ctkCmdLineModuleReferenceResult> refs = this->loadModules(filteredFileNames);
 
   QStringList validFileNames;
 
   for (int i = 0; i < refs.size(); ++i)
   {
-    if (refs[i])
+    if (refs[i].m_Reference)
     {
-      validFileNames << refs[i].location().toLocalFile();
+      validFileNames << refs[i].m_Reference.location().toLocalFile();
     }
   }
 
   this->AdditionalModules = validFileNames;
-  this->updateWatchedPaths(this->directories(), this->MapFileNameToReference.keys());
+  this->updateWatchedPaths(this->directories(), this->MapFileNameToReferenceResult.keys());
 
   if (this->Debug) qDebug() << "ctkCmdLineModuleDirectoryWatcherPrivate::setAdditionalModules watching:" << this->AdditionalModules;
 }
@@ -296,7 +296,7 @@ QStringList ctkCmdLineModuleDirectoryWatcherPrivate::extractCurrentlyWatchedFile
   QDir dir(path);
   if (dir.exists())
   {
-    QList<QString> keys = this->MapFileNameToReference.keys();
+    QList<QString> keys = this->MapFileNameToReferenceResult.keys();
 
     QString fileName;
     foreach(fileName, keys)
@@ -397,24 +397,24 @@ void ctkCmdLineModuleDirectoryWatcherPrivate::updateModules(const QString &direc
     currentlyWatchedDirectories << directory;
   }
   this->setModules(currentlyWatchedDirectories);
-  this->updateWatchedPaths(currentlyWatchedDirectories, this->MapFileNameToReference.keys());
+  this->updateWatchedPaths(currentlyWatchedDirectories, this->MapFileNameToReferenceResult.keys());
 }
 
 
 //-----------------------------------------------------------------------------
-QList<ctkCmdLineModuleReference> ctkCmdLineModuleDirectoryWatcherPrivate::loadModules(const QStringList& executables)
+QList<ctkCmdLineModuleReferenceResult> ctkCmdLineModuleDirectoryWatcherPrivate::loadModules(const QStringList& executables)
 {
-  QList<ctkCmdLineModuleReference> refs = QtConcurrent::blockingMapped(executables,
-                                                                       ctkCmdLineModuleConcurrentRegister(this->ModuleManager, this->Debug));
+  QList<ctkCmdLineModuleReferenceResult> refResults = QtConcurrent::blockingMapped(executables,
+                                                                                   ctkCmdLineModuleConcurrentRegister(this->ModuleManager, this->Debug));
 
   for (int i = 0; i < executables.size(); ++i)
   {
-    if (refs[i])
+    if (refResults[i].m_Reference)
     {
-      this->MapFileNameToReference[executables[i]] = refs[i];
+      this->MapFileNameToReferenceResult[executables[i]] = refResults[i];
     }
   }
-  return refs;
+  return refResults;
 }
 
 
@@ -424,7 +424,7 @@ void ctkCmdLineModuleDirectoryWatcherPrivate::unloadModules(const QStringList& e
   QtConcurrent::blockingMapped(executables, ctkCmdLineModuleConcurrentUnRegister(this->ModuleManager));
   foreach(QString executable, executables)
   {
-    this->MapFileNameToReference.remove(executable);
+    this->MapFileNameToReferenceResult.remove(executable);
   }
 }
 
@@ -432,14 +432,14 @@ void ctkCmdLineModuleDirectoryWatcherPrivate::unloadModules(const QStringList& e
 //-----------------------------------------------------------------------------
 void ctkCmdLineModuleDirectoryWatcherPrivate::onFileChanged(const QString& path)
 {
-  ctkCmdLineModuleReference ref = this->loadModules(QStringList() << path).front();
-  if (ref)
+  ctkCmdLineModuleReferenceResult refResult = this->loadModules(QStringList() << path).front();
+  if (refResult.m_Reference)
   {
     if (this->Debug) qDebug() << "Reloaded " << path;
   }
   else
   {
-    if (this->Debug) qDebug() << "ctkCmdLineModuleDirectoryWatcherPrivate::onFileChanged(" << path << "): failed to load module";
+    if (this->Debug) qDebug() << "ctkCmdLineModuleDirectoryWatcherPrivate::onFileChanged(" << path << "): failed to load module due to " << refResult.m_RuntimeError;
   }
 }
 

+ 0 - 2
Libs/CommandLineModules/Core/ctkCmdLineModuleDirectoryWatcher.h

@@ -23,8 +23,6 @@
 
 #include <ctkCommandLineModulesCoreExport.h>
 
-#include "ctkCmdLineModuleReference.h"
-
 #include <QObject>
 #include <QScopedPointer>
 

+ 3 - 3
Libs/CommandLineModules/Core/ctkCmdLineModuleDirectoryWatcher_p.h

@@ -26,7 +26,7 @@
 #include <QStringList>
 #include <QFileInfoList>
 
-#include "ctkCmdLineModuleReference.h"
+#include "ctkCmdLineModuleReferenceResult.h"
 #include "ctkCmdLineModuleDirectoryWatcher.h"
 
 class QFileSystemWatcher;
@@ -156,7 +156,7 @@ private:
    *
    * \param executables A list of paths to executable files, denoted by an absolute path.
    */
-  QList<ctkCmdLineModuleReference> loadModules(const QStringList& executables);
+  QList<ctkCmdLineModuleReferenceResult> loadModules(const QStringList& executables);
 
   /**
    * \brief Removes the executables from both the ctkCmdLineModuleManager and this->MapFileNameToReference.
@@ -165,7 +165,7 @@ private:
    */
   void unloadModules(const QStringList& executables);
 
-  QHash<QString, ctkCmdLineModuleReference> MapFileNameToReference;
+  QHash<QString, ctkCmdLineModuleReferenceResult> MapFileNameToReferenceResult;
   ctkCmdLineModuleManager* ModuleManager;
   QFileSystemWatcher* FileSystemWatcher;
   QStringList AdditionalModules;

+ 43 - 0
Libs/CommandLineModules/Core/ctkCmdLineModuleReferenceResult.h

@@ -0,0 +1,43 @@
+/*=============================================================================
+  
+  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 CTKCMDLINEMODULEREFERENCERESULT_H
+#define CTKCMDLINEMODULEREFERENCERESULT_H
+
+#include "ctkCommandLineModulesCoreExport.h"
+#include <ctkCmdLineModuleReference.h>
+
+#include <QString>
+#include <QUrl>
+
+struct CTK_CMDLINEMODULECORE_EXPORT ctkCmdLineModuleReferenceResult
+{
+  ctkCmdLineModuleReferenceResult() {}
+  ctkCmdLineModuleReferenceResult(const QUrl& moduleUrl) { m_Url = moduleUrl;}
+  ctkCmdLineModuleReferenceResult(const QUrl& moduleUrl, const QString& errorMessage) { m_Url = moduleUrl; m_RuntimeError = errorMessage; }
+  ctkCmdLineModuleReferenceResult(ctkCmdLineModuleReference& ref) { m_Reference = ref; m_Url = ref.location(); }
+
+  QUrl m_Url;
+  ctkCmdLineModuleReference m_Reference;
+  QString m_RuntimeError;
+};
+
+#endif // CTKCMDLINEMODULEREFERENCERESULT_H

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

@@ -0,0 +1,67 @@
+/*=============================================================================
+
+  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 "ctkCmdLineModuleUtils.h"
+#include "ctkCmdLineModuleRunException.h"
+
+#include <QApplication>
+#include <QMessageBox>
+#include <QUrl>
+#include <QString>
+
+void ctkCmdLineModuleUtils::messageBoxModuleRegistration(const QFuture<ctkCmdLineModuleReferenceResult> &moduleRefsFuture,
+                                                                  ctkCmdLineModuleManager::ValidationMode validationMode)
+{
+  QString errorMsg;
+  QFutureIterator<ctkCmdLineModuleReferenceResult> futureIter(moduleRefsFuture);
+  while(futureIter.hasNext())
+  {
+    try
+    {
+      const ctkCmdLineModuleReferenceResult& moduleRefResult = futureIter.next();
+      if (!moduleRefResult.m_Reference)
+      {
+        errorMsg += (QObject::tr("Failed to register module:\n%1\n\ndue to:\n%2\n\n").arg(moduleRefResult.m_Url.toString()).arg(moduleRefResult.m_RuntimeError));
+      }
+      else if (!moduleRefResult.m_Reference.xmlValidationErrorString().isEmpty() &&
+             validationMode == ctkCmdLineModuleManager::STRICT_VALIDATION)
+      {
+        errorMsg += (QObject::tr("Failed to register module:\n%1\n\ndue to xml validation error:\n%2\n\n").arg(moduleRefResult.m_Url.toString()).arg(moduleRefResult.m_Reference.xmlValidationErrorString()));
+      }
+    }
+    // These exceptions should never happen, as at this point we are iterating over a fixed list of results, and not processing exceptions.
+    catch (const ctkCmdLineModuleRunException& e)
+    {
+      errorMsg += QObject::tr("Failed to register module:\n") + e.location().toString() + "\n\ndue to:\n" + e.message() + "\n\n";
+    }
+    catch (const std::exception& e)
+    {
+      errorMsg += QObject::tr("Failed to register module:\n\n\ndue to:\n") + e.what() + "\n\n";
+    }
+  }
+
+  if (!errorMsg.isEmpty())
+  {
+    QWidget* widget = QApplication::activeModalWidget();
+    if (widget == NULL) widget = QApplication::activeWindow();
+    QMessageBox::critical(widget, QObject::tr("Failed to register modules"), errorMsg);
+  }
+}

+ 38 - 0
Libs/CommandLineModules/Core/ctkCmdLineModuleUtils.h

@@ -0,0 +1,38 @@
+/*=============================================================================
+
+  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 CTKCOMMANDLINEMODULEUTILS_H
+#define CTKCOMMANDLINEMODULEUTILS_H
+
+#include "ctkCommandLineModulesCoreExport.h"
+
+#include "ctkCmdLineModuleManager.h"
+#include "ctkCmdLineModuleReferenceResult.h"
+
+#include <QFuture>
+
+struct CTK_CMDLINEMODULECORE_EXPORT ctkCmdLineModuleUtils
+{
+  static void messageBoxModuleRegistration(const QFuture<ctkCmdLineModuleReferenceResult>& moduleRefsFuture,
+                                           ctkCmdLineModuleManager::ValidationMode validationMode);
+};
+
+#endif // CTKCOMMANDLINEMODULEUTILS_H

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

@@ -92,6 +92,8 @@ int main(int argc, char* argv[])
 
   if (parsedArgs.contains("xml"))
   {
+    sleep_ms(2000);
+
     QFile xmlDescription(":/ctkCmdLineModuleTestBed.xml");
     xmlDescription.open(QIODevice::ReadOnly);
     out << xmlDescription.readAll();