Forráskód Böngészése

Merge branch '398-cli-validator'

Matt Clarkson 11 éve
szülő
commit
a05024eacc

+ 74 - 2
Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerMainWindow.cpp

@@ -37,6 +37,7 @@
 #include <ctkCmdLineModuleFrontendFactoryQtWebKit.h>
 #include <ctkCmdLineModuleBackendLocalProcess.h>
 #include <ctkCmdLineModuleBackendFunctionPointer.h>
+#include <ctkCmdLineModuleBackendXMLChecker.h>
 #include <ctkException.h>
 #include <ctkCmdLineModuleXmlException.h>
 
@@ -48,8 +49,9 @@
 #include <QFutureSynchronizer>
 #include <QCloseEvent>
 #include <QFileDialog>
+#include <QMessageBox>
 
-
+//-----------------------------------------------------------------------------
 ctkCLModuleExplorerMainWindow::ctkCLModuleExplorerMainWindow(QWidget *parent) :
   QMainWindow(parent),
   ui(new Ui::ctkCmdLineModuleExplorerMainWindow),
@@ -80,9 +82,13 @@ ctkCLModuleExplorerMainWindow::ctkCLModuleExplorerMainWindow(QWidget *parent) :
 
   // Backends
   ctkCmdLineModuleBackendFunctionPointer* backendFunctionPointer = new ctkCmdLineModuleBackendFunctionPointer;
+  moduleBackends.push_back(backendFunctionPointer);
+
+  xmlCheckerBackEnd = new ctkCmdLineModuleBackendXMLChecker;
+  moduleBackends.push_back(xmlCheckerBackEnd);
 
   moduleBackends.push_back(new ctkCmdLineModuleBackendLocalProcess);
-  moduleBackends.push_back(backendFunctionPointer);
+
   for(int i = 0; i < moduleBackends.size(); ++i)
   {
     moduleManager.registerBackend(moduleBackends[i]);
@@ -104,6 +110,7 @@ ctkCLModuleExplorerMainWindow::ctkCLModuleExplorerMainWindow(QWidget *parent) :
   connect(ui->progressListWidget, SIGNAL(progressWidgetClicked(ctkCmdLineModuleFrontend*)), tabList.data(), SLOT(setActiveTab(ctkCmdLineModuleFrontend*)));
 
   connect(ui->ClearButton, SIGNAL(clicked()), ui->progressListWidget, SLOT(clearList()));
+  connect(ui->m_CheckXMLButton, SIGNAL(pressed()), this, SLOT(checkXMLPressed()));
 
   // Listen to future events for the currently active tab
 
@@ -137,6 +144,8 @@ ctkCLModuleExplorerMainWindow::ctkCLModuleExplorerMainWindow(QWidget *parent) :
   future.waitForFinished();
 }
 
+
+//-----------------------------------------------------------------------------
 ctkCLModuleExplorerMainWindow::~ctkCLModuleExplorerMainWindow()
 {
   qDeleteAll(moduleBackends);
@@ -149,11 +158,15 @@ ctkCLModuleExplorerMainWindow::~ctkCLModuleExplorerMainWindow()
   }
 }
 
+
+//-----------------------------------------------------------------------------
 void ctkCLModuleExplorerMainWindow::addModule(const QUrl &location)
 {
   moduleManager.registerModule(location);
 }
 
+
+//-----------------------------------------------------------------------------
 void ctkCLModuleExplorerMainWindow::closeEvent(QCloseEvent *event)
 {
   QList<ctkCmdLineModuleFrontend*> runningFrontends;
@@ -198,6 +211,8 @@ void ctkCLModuleExplorerMainWindow::closeEvent(QCloseEvent *event)
   event->accept();
 }
 
+
+//-----------------------------------------------------------------------------
 void ctkCLModuleExplorerMainWindow::on_actionRun_triggered()
 {
   ctkCmdLineModuleFrontend* moduleFrontend = this->tabList->activeTab();
@@ -218,16 +233,22 @@ void ctkCLModuleExplorerMainWindow::on_actionRun_triggered()
   this->currentFutureWatcher.setFuture(future);
 }
 
+
+//-----------------------------------------------------------------------------
 void ctkCLModuleExplorerMainWindow::on_actionPause_toggled(bool toggled)
 {
   this->currentFutureWatcher.setPaused(toggled);
 }
 
+
+//-----------------------------------------------------------------------------
 void ctkCLModuleExplorerMainWindow::on_actionCancel_triggered()
 {
   this->currentFutureWatcher.cancel();
 }
 
+
+//-----------------------------------------------------------------------------
 void ctkCLModuleExplorerMainWindow::on_actionOptions_triggered()
 {
   if (settingsDialog == NULL)
@@ -244,6 +265,8 @@ void ctkCLModuleExplorerMainWindow::on_actionOptions_triggered()
   settingsDialog->exec();
 }
 
+
+//-----------------------------------------------------------------------------
 void ctkCLModuleExplorerMainWindow::on_actionLoad_triggered()
 {
   QStringList fileNames = QFileDialog::getOpenFileNames(this, tr("Load modules..."));
@@ -257,26 +280,36 @@ void ctkCLModuleExplorerMainWindow::on_actionLoad_triggered()
                                                               this->moduleManager.validationMode());
 }
 
+
+//-----------------------------------------------------------------------------
 void ctkCLModuleExplorerMainWindow::on_actionQuit_triggered()
 {
   this->close();
 }
 
+
+//-----------------------------------------------------------------------------
 void ctkCLModuleExplorerMainWindow::on_actionReset_triggered()
 {
   this->tabList->activeTab()->resetValues();
 }
 
+
+//-----------------------------------------------------------------------------
 void ctkCLModuleExplorerMainWindow::on_actionClear_Cache_triggered()
 {
   moduleManager.clearCache();
 }
 
+
+//-----------------------------------------------------------------------------
 void ctkCLModuleExplorerMainWindow::on_actionReload_Modules_triggered()
 {
   moduleManager.reloadModules();
 }
 
+
+//-----------------------------------------------------------------------------
 void ctkCLModuleExplorerMainWindow::checkModulePaused()
 {
   if (this->currentFutureWatcher.future().isPaused())
@@ -295,11 +328,15 @@ void ctkCLModuleExplorerMainWindow::checkModulePaused()
   }
 }
 
+
+//-----------------------------------------------------------------------------
 void ctkCLModuleExplorerMainWindow::currentModuleResumed()
 {
   ui->actionPause->setChecked(false);
 }
 
+
+//-----------------------------------------------------------------------------
 void ctkCLModuleExplorerMainWindow::currentModuleCanceled()
 {
   ctkCmdLineModuleFrontend* frontend = this->tabList->activeTab();
@@ -316,6 +353,8 @@ void ctkCLModuleExplorerMainWindow::currentModuleCanceled()
   }
 }
 
+
+//-----------------------------------------------------------------------------
 void ctkCLModuleExplorerMainWindow::currentModuleFinished()
 {
   ctkCmdLineModuleFrontend* frontend = this->tabList->activeTab();
@@ -332,6 +371,39 @@ void ctkCLModuleExplorerMainWindow::currentModuleFinished()
   }
 }
 
+
+//-----------------------------------------------------------------------------
+void ctkCLModuleExplorerMainWindow::checkXMLPressed()
+{
+  xmlCheckerBackEnd->setXML(ui->m_XMLToValidate->toPlainText());
+  QUrl url(QString("xmlchecker://should call ctkCmdLineModuleBackendXMLChecker"));
+
+  qDebug() << "ctkCLModuleExplorerMainWindow::checkXMLPressed validating:\n" << ui->m_XMLToValidate->toPlainText();
+
+  ctkCmdLineModuleManager::ValidationMode previousMode = moduleManager.validationMode();
+
+  try
+  {
+    ctkCmdLineModuleReference ref = moduleManager.moduleReference(url);
+    if (ref)
+    {
+      moduleManager.unregisterModule(ref);
+    }
+    moduleManager.setValidationMode(ctkCmdLineModuleManager::STRICT_VALIDATION);
+    moduleManager.registerModule(url);
+    moduleManager.setValidationMode(previousMode);
+
+  } catch (ctkException& except)
+  {
+    moduleManager.setValidationMode(previousMode);
+    QWidget* widget = QApplication::activeModalWidget();
+    if (widget == NULL) widget = QApplication::activeWindow();
+    QMessageBox::critical(widget, QObject::tr("Failed while checking XML:"), except.message());
+  }
+}
+
+
+//-----------------------------------------------------------------------------
 void ctkCLModuleExplorerMainWindow::moduleTabActivated(ctkCmdLineModuleFrontend *module)
 {
   if (module == NULL)

+ 4 - 2
Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerMainWindow.h

@@ -35,6 +35,7 @@ class ctkCmdLineModuleExplorerTabList;
 class ctkCmdLineModuleReference;
 class ctkCmdLineModuleResult;
 class ctkSettingsDialog;
+class ctkCmdLineModuleBackendXMLChecker;
 
 namespace Ui {
 class ctkCmdLineModuleExplorerMainWindow;
@@ -77,7 +78,8 @@ protected Q_SLOTS:
   void currentModuleFinished();
 
   void moduleTabActivated(ctkCmdLineModuleFrontend* module);
-  
+  void checkXMLPressed();
+
 private:
 
   QScopedPointer<Ui::ctkCmdLineModuleExplorerMainWindow> ui;
@@ -97,7 +99,7 @@ private:
 
   ctkSettings settings;
   ctkSettingsDialog* settingsDialog;
-
+  ctkCmdLineModuleBackendXMLChecker* xmlCheckerBackEnd;
 };
 
 #endif // CTKCLIPLUGINEXPLORERMAINWINDOW_H

+ 88 - 2
Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerMainWindow.ui

@@ -17,7 +17,7 @@
    <set>QMainWindow::AllowNestedDocks|QMainWindow::AllowTabbedDocks|QMainWindow::AnimatedDocks</set>
   </property>
   <widget class="QWidget" name="centralwidget">
-   <layout class="QHBoxLayout" name="horizontalLayout">
+   <layout class="QVBoxLayout" name="verticalLayout_6">
     <property name="margin">
      <number>0</number>
     </property>
@@ -90,6 +90,15 @@
    <addaction name="actionReset"/>
   </widget>
   <widget class="QDockWidget" name="dockWidget">
+   <property name="sizePolicy">
+    <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
+     <horstretch>0</horstretch>
+     <verstretch>0</verstretch>
+    </sizepolicy>
+   </property>
+   <property name="floating">
+    <bool>false</bool>
+   </property>
    <property name="features">
     <set>QDockWidget::NoDockWidgetFeatures</set>
    </property>
@@ -203,7 +212,7 @@
              <x>0</x>
              <y>0</y>
              <width>250</width>
-             <height>208</height>
+             <height>144</height>
             </rect>
            </property>
            <layout class="QVBoxLayout" name="verticalLayout_5">
@@ -274,6 +283,83 @@
     </layout>
    </widget>
   </widget>
+  <widget class="QDockWidget" name="dockWidget_4">
+   <property name="sizePolicy">
+    <sizepolicy hsizetype="Preferred" vsizetype="MinimumExpanding">
+     <horstretch>0</horstretch>
+     <verstretch>0</verstretch>
+    </sizepolicy>
+   </property>
+   <property name="features">
+    <set>QDockWidget::DockWidgetFloatable|QDockWidget::DockWidgetMovable</set>
+   </property>
+   <property name="windowTitle">
+    <string>XML Checker</string>
+   </property>
+   <attribute name="dockWidgetArea">
+    <number>1</number>
+   </attribute>
+   <widget class="QWidget" name="dockWidgetContents_4">
+    <layout class="QVBoxLayout" name="verticalLayout_7">
+     <item>
+      <layout class="QHBoxLayout" name="horizontalLayout_3">
+       <item>
+        <spacer name="horizontalSpacer_2">
+         <property name="orientation">
+          <enum>Qt::Horizontal</enum>
+         </property>
+         <property name="sizeHint" stdset="0">
+          <size>
+           <width>40</width>
+           <height>20</height>
+          </size>
+         </property>
+        </spacer>
+       </item>
+       <item>
+        <widget class="QPushButton" name="m_CheckXMLButton">
+         <property name="text">
+          <string>Check</string>
+         </property>
+        </widget>
+       </item>
+      </layout>
+     </item>
+     <item>
+      <widget class="Line" name="line_2">
+       <property name="orientation">
+        <enum>Qt::Horizontal</enum>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <widget class="QScrollArea" name="scrollArea_2">
+       <property name="widgetResizable">
+        <bool>true</bool>
+       </property>
+       <widget class="QWidget" name="scrollAreaWidgetContents">
+        <property name="geometry">
+         <rect>
+          <x>0</x>
+          <y>0</y>
+          <width>230</width>
+          <height>108</height>
+         </rect>
+        </property>
+        <layout class="QHBoxLayout" name="horizontalLayout">
+         <property name="margin">
+          <number>0</number>
+         </property>
+         <item>
+          <widget class="QPlainTextEdit" name="m_XMLToValidate"/>
+         </item>
+        </layout>
+       </widget>
+      </widget>
+     </item>
+    </layout>
+   </widget>
+  </widget>
   <action name="actionRun">
    <property name="icon">
     <iconset resource="resources/ctkCmdLineModuleExplorer.qrc">

+ 47 - 6
Applications/ctkCommandLineModuleExplorer/ctkCommandLineModuleExplorerMain.cpp

@@ -48,11 +48,11 @@ int main(int argc, char** argv)
   cmdLineParser.setArgumentPrefix("--", "-");
   cmdLineParser.setStrictModeEnabled(true);
 
-  cmdLineParser.addArgument("module", "", QVariant::String, "Path to a CLI module (executable)");
-  //cmdLineParser.addArgument("module-xml", "", QVariant::String, "Path to a CLI XML description.");
-
-  cmdLineParser.addArgument("validate-module", "", QVariant::String, "Path to a CLI module");
-  cmdLineParser.addArgument("validate-xml", "", QVariant::String, "Path to a CLI XML description.");
+  cmdLineParser.addArgument("module", "", QVariant::String, "Path to a CLI module (executable), and show the generated GUI.");
+  cmdLineParser.addArgument("validate-module", "", QVariant::String, "Path to a CLI module (executable), and validate the XML.");
+  cmdLineParser.addArgument("validate-xml", "", QVariant::String, "Path to a CLI XML file, and validate the XML.");
+  cmdLineParser.addArgument("string", "", QVariant::String, "An XML string to validate. Be careful to quote correctly." );
+  cmdLineParser.addArgument("xml", "", QVariant::Bool, "Generate XML for this application");
   cmdLineParser.addArgument("verbose", "v", QVariant::Bool, "Be verbose.");
   cmdLineParser.addArgument("help", "h", QVariant::Bool, "Print this help text.");
 
@@ -139,9 +139,50 @@ int main(int argc, char** argv)
 
     return EXIT_SUCCESS;
   }
+  else if (args.contains("string"))
+  {
+    QByteArray byteArray;
+    byteArray.append(args["string"].toString());
+    QBuffer buffer(&byteArray);
+    buffer.open(QIODevice::ReadOnly);
 
+    ctkCmdLineModuleXmlValidator validator(&buffer);
+    if (!validator.validateInput())
+    {
+      qCritical() << validator.errorString();
+      return EXIT_FAILURE;
+    }
 
-  //ctkCmdLineModuleDescription* descr = ctkCmdLineModuleDescription::parse(&input);
+    out << "Validated successfully";
+    return EXIT_SUCCESS;
+  }
+  else if (args.contains("xml"))
+  {
+    out << "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n";
+    out << "<executable>\n";
+    out << "  <category>Utilities</category>\n";
+    out << "  <title>ctkCommandLineModuleExplorer</title>\n";
+    out << "  <description><![CDATA[Used to check the validity of CLI XML descriptors.]]></description>\n";
+    out << "  <version>0.0.1</version>\n";
+    out << "  <documentation-url>http://www.commontk.org</documentation-url>\n";
+    out << "  <license>Apache 2</license>\n";
+    out << "  <contributor>Various</contributor>\n";
+    out << "  <acknowledgements><![CDATA[]]></acknowledgements>\n";
+    out << "  <parameters>\n";
+    out << "    <label>Input parameters</label>\n";
+    out << "    <description><![CDATA[Input/output parameters]]></description>\n";
+    out << "    <string>\n";
+    out << "      <name>inputText</name>\n";
+    out << "      <longflag>string</longflag>\n";
+    out << "      <description>Input text containing an XML string.</description>\n";
+    out << "      <label>Enter XML as a string:</label>\n";
+    out << "      <channel>input</channel>\n";
+    out << "    </string>\n";
+    out << "  </parameters>\n";
+    out << "</executable>\n";
+    out.flush();
+    return EXIT_SUCCESS;
+  }
 
   ctkCLModuleExplorerMainWindow mainWindow;
 

+ 1 - 0
Applications/ctkCommandLineModuleExplorer/target_libraries.cmake

@@ -7,6 +7,7 @@
 set(target_libraries
   CTKCommandLineModulesFrontendQtGui
   CTKCommandLineModulesFrontendQtWebKit
+  CTKCommandLineModulesBackendXMLChecker
   CTKCommandLineModulesBackendLocalProcess
   CTKCommandLineModulesBackendFunctionPointer
   CTKWidgets

+ 3 - 0
CMakeLists.txt

@@ -484,6 +484,9 @@ ctk_lib_option(CommandLineModules/Frontend/QtWebKit
 ctk_lib_option(CommandLineModules/Frontend/QtGui
                "Build the QtGui based Command Line Module front-end" OFF)
 
+ctk_lib_option(CommandLineModules/Backend/XMLChecker
+               "Build the Command Line Module back-end for checking XML" OFF)
+
 ctk_lib_option(CommandLineModules/Backend/LocalProcess
                "Build the Command Line Module back-end for local processes" OFF)
 

+ 62 - 0
Libs/CommandLineModules/Backend/XMLChecker/CMakeLists.txt

@@ -0,0 +1,62 @@
+project(CTKCommandLineModulesBackendXMLChecker)
+
+#
+# 3rd party dependencies
+#
+
+#
+# See CTK/CMake/ctkMacroBuildLib.cmake for details
+#
+
+set(KIT_export_directive "CTK_CMDLINEMODULEBACKENDXMLCHECKER_EXPORT")
+
+# Additional directories to include
+
+# Source files
+set(KIT_SRCS
+  ctkCmdLineModuleXMLCheckerTask.cpp
+  ctkCmdLineModuleBackendXMLChecker.cpp
+)
+
+# Headers that should run through moc
+set(KIT_MOC_SRCS
+)
+
+# UI files
+set(KIT_UI_FORMS
+)
+
+# Resources
+set(KIT_resources
+)
+
+# Target libraries - See CMake/ctkFunctionGetTargetLibraries.cmake
+# The following macro will read the target libraries from the file 'target_libraries.cmake'
+ctkFunctionGetTargetLibraries(KIT_target_libraries)
+
+ctkMacroBuildLib(
+  NAME ${PROJECT_NAME}
+  EXPORT_DIRECTIVE ${KIT_export_directive}
+  INCLUDE_DIRECTORIES ${KIT_include_directories}
+  SRCS ${KIT_SRCS}
+  MOC_SRCS ${KIT_MOC_SRCS}
+  UI_FORMS ${KIT_UI_FORMS}
+  TARGET_LIBRARIES ${KIT_target_libraries}
+  RESOURCES ${KIT_resources}
+  LIBRARY_TYPE ${CTK_LIBRARY_MODE}
+  )
+
+target_link_libraries(${PROJECT_NAME} ${QT_LIBRARIES})
+
+if(CTK_WRAP_PYTHONQT_FULL OR CTK_WRAP_PYTHONQT_LIGHT)
+  ctkMacroBuildLibWrapper(
+    TARGET ${PROJECT_NAME}
+    SRCS ${KIT_SRCS}
+    WRAPPER_LIBRARY_TYPE ${CTK_LIBRARY_MODE}
+    )
+endif()
+
+# Testing
+if(BUILD_TESTING)
+  #add_subdirectory(Testing)
+endif()

+ 120 - 0
Libs/CommandLineModules/Backend/XMLChecker/ctkCmdLineModuleBackendXMLChecker.cpp

@@ -0,0 +1,120 @@
+/*=============================================================================
+
+  Library: CTK
+
+  Copyright (c) University College London
+
+  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 "ctkCmdLineModuleBackendXMLChecker.h"
+#include "ctkCmdLineModuleXMLCheckerTask_p.h"
+
+#include "ctkCmdLineModuleFrontend.h"
+#include "ctkCmdLineModuleFuture.h"
+#include <QUrl>
+#include <QString>
+#include <QDateTime>
+#include <ctkUtils.h>
+
+//----------------------------------------------------------------------------
+struct ctkCmdLineModuleBackendXMLCheckerPrivate
+{
+  QString m_HardCodedXML;
+  QDateTime m_LastModified;
+};
+
+
+//----------------------------------------------------------------------------
+ctkCmdLineModuleBackendXMLChecker::ctkCmdLineModuleBackendXMLChecker()
+  : d(new ctkCmdLineModuleBackendXMLCheckerPrivate)
+{
+  d->m_HardCodedXML = QString("");
+  d->m_LastModified = QDateTime::currentDateTime();
+}
+
+
+//----------------------------------------------------------------------------
+ctkCmdLineModuleBackendXMLChecker::ctkCmdLineModuleBackendXMLChecker(const QString &xmlToValidate)
+  : d(new ctkCmdLineModuleBackendXMLCheckerPrivate)
+{
+  d->m_HardCodedXML = xmlToValidate;
+  d->m_LastModified = QDateTime::currentDateTime();
+}
+
+
+//----------------------------------------------------------------------------
+ctkCmdLineModuleBackendXMLChecker::~ctkCmdLineModuleBackendXMLChecker()
+{
+}
+
+
+//----------------------------------------------------------------------------
+void ctkCmdLineModuleBackendXMLChecker::setXML(const QString& xml)
+{
+  d->m_HardCodedXML = xml;
+  d->m_LastModified = QDateTime::currentDateTime();
+}
+
+
+//----------------------------------------------------------------------------
+QString ctkCmdLineModuleBackendXMLChecker::xml() const
+{
+  return d->m_HardCodedXML;
+}
+
+
+//----------------------------------------------------------------------------
+QString ctkCmdLineModuleBackendXMLChecker::name() const
+{
+  return "XML Checker";
+}
+
+
+//----------------------------------------------------------------------------
+QString ctkCmdLineModuleBackendXMLChecker::description() const
+{
+  return "Fakes a backend process, returning a static piece of XML.";
+}
+
+
+//----------------------------------------------------------------------------
+QList<QString> ctkCmdLineModuleBackendXMLChecker::schemes() const
+{
+  static QList<QString> supportedSchemes = QList<QString>() << "xmlchecker";
+  return supportedSchemes;
+}
+
+
+//----------------------------------------------------------------------------
+qint64 ctkCmdLineModuleBackendXMLChecker::timeStamp(const QUrl & /*location*/) const
+{
+  return ctk::msecsTo(QDateTime::fromTime_t(0), d->m_LastModified);
+}
+
+
+//----------------------------------------------------------------------------
+QByteArray ctkCmdLineModuleBackendXMLChecker::rawXmlDescription(const QUrl &/*location*/)
+{
+  return d->m_HardCodedXML.toAscii();
+}
+
+
+//----------------------------------------------------------------------------
+ctkCmdLineModuleFuture ctkCmdLineModuleBackendXMLChecker::run(ctkCmdLineModuleFrontend* /*frontend*/)
+{
+  // Instances of ctkCmdLineModuleProcessTask are auto-deleted by the thread pool.
+  ctkCmdLineModuleXMLCheckerTask* moduleProcess = new ctkCmdLineModuleXMLCheckerTask();
+  return moduleProcess->start();
+}

+ 91 - 0
Libs/CommandLineModules/Backend/XMLChecker/ctkCmdLineModuleBackendXMLChecker.h

@@ -0,0 +1,91 @@
+/*=============================================================================
+
+  Library: CTK
+
+  Copyright (c) University College London
+
+  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 CTKCMDLINEMODULEBACKENDXMLCHECKER_H
+#define CTKCMDLINEMODULEBACKENDXMLCHECKER_H
+
+#include "ctkCmdLineModuleBackend.h"
+
+#include "ctkCommandLineModulesBackendXMLCheckerExport.h"
+
+#include <QScopedPointer>
+
+struct ctkCmdLineModuleBackendXMLCheckerPrivate;
+
+/**
+ * @ingroup CommandLineModulesBackendXMLChecker_API
+ *
+ * @brief Provides a ctkCmdLineModuleBackend implementation
+ * to pretend to run a command line process, but actually
+ * it returns a fixed, static piece of XML which can then
+ * be validated by the core library.
+ */
+class CTK_CMDLINEMODULEBACKENDXMLCHECKER_EXPORT ctkCmdLineModuleBackendXMLChecker : public ctkCmdLineModuleBackend
+{
+
+public:
+
+  ctkCmdLineModuleBackendXMLChecker();
+  ctkCmdLineModuleBackendXMLChecker(const QString &xmlToValidate);
+  ~ctkCmdLineModuleBackendXMLChecker();
+
+  virtual QString name() const;
+  virtual QString description() const;
+
+  /**
+   * @brief This back-end can handle the "xml checker" URL scheme.
+   * @return Returns the schemes this back-end can handle.
+   */
+  virtual QList<QString> schemes() const;
+
+  /**
+   * @brief Returns the last modified time of the module at \c location.
+   * @param location The location URL of the module for which to get the timestamp.
+   * @return A timestamp.
+   */
+  virtual qint64 timeStamp(const QUrl &location) const;
+
+  /**
+   * @brief Get the raw XML description from the module at \c location.
+   * @param location The location URL of the module for which to get the XML description.
+   * @return The raw XML description.
+   *
+   * This method always calls the executable with a \c &ndash;&ndash;xml argument and returns
+   * the complete data emitted on the standard output channel.
+   */
+  virtual QByteArray rawXmlDescription(const QUrl& location);
+
+  /**
+   * @brief Run a front-end for this module in a local process.
+   * @param frontend The front-end to run.
+   * @return A future object for communicating with the running process.
+   */
+  virtual ctkCmdLineModuleFuture run(ctkCmdLineModuleFrontend *frontend);
+
+  void setXML(const QString& xml);
+  QString xml() const;
+
+private:
+
+  QScopedPointer<ctkCmdLineModuleBackendXMLCheckerPrivate> d;
+
+};
+
+#endif // CTKCMDLINEMODULEBACKENDLOCALPROCESS_H

+ 61 - 0
Libs/CommandLineModules/Backend/XMLChecker/ctkCmdLineModuleXMLCheckerTask.cpp

@@ -0,0 +1,61 @@
+/*=============================================================================
+
+  Library: CTK
+
+  Copyright (c) University College London
+
+  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 "ctkCmdLineModuleXMLCheckerTask_p.h"
+#include "ctkCmdLineModuleFuture.h"
+
+#include <QThreadPool>
+
+//----------------------------------------------------------------------------
+ctkCmdLineModuleXMLCheckerTask::ctkCmdLineModuleXMLCheckerTask()
+{
+}
+
+
+//----------------------------------------------------------------------------
+ctkCmdLineModuleFuture ctkCmdLineModuleXMLCheckerTask::start()
+{
+  this->setRunnable(this);
+  this->setProgressRange(0,0);
+  this->reportStarted();
+
+  ctkCmdLineModuleFuture future = this->future();
+  QThreadPool::globalInstance()->start(this, /*m_priority*/ 0);
+
+  return future;
+}
+
+
+//----------------------------------------------------------------------------
+void ctkCmdLineModuleXMLCheckerTask::run()
+{
+  if (this->isCanceled())
+  {
+    this->reportFinished();
+    return;
+  }
+
+  // Actually nothing to do, as we don't actually run the process.
+
+  // Report a successful finish.
+  this->setProgressRange(0,1);
+  this->setProgressValue(1);
+  this->reportFinished();
+}

+ 45 - 0
Libs/CommandLineModules/Backend/XMLChecker/ctkCmdLineModuleXMLCheckerTask_p.h

@@ -0,0 +1,45 @@
+/*=============================================================================
+
+  Library: CTK
+
+  Copyright (c) University College London
+
+  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 CTKCMDLINEMODULEXMLCHECKERTASK_P_H
+#define CTKCMDLINEMODULEXMLCHECKERTASK_P_H
+
+#include <ctkCmdLineModuleFutureInterface.h>
+#include <QRunnable>
+
+/**
+ * \class ctkCmdLineModuleXMLCheckerTask
+ * \brief Provides a ctkCmdLineModuleFutureInterface implementation specifically to
+ * run an XML Checker asynchronously.
+ * \ingroup CommandLineModulesBackendXMLChecker_API
+ */
+class ctkCmdLineModuleXMLCheckerTask : public ctkCmdLineModuleFutureInterface, public QRunnable
+{
+public:
+
+  ctkCmdLineModuleXMLCheckerTask();
+  ctkCmdLineModuleFuture start();
+
+  void run();
+
+private:
+};
+
+#endif // CTKCMDLINEMODULEXMLCHECKERTASK_P_H

+ 9 - 0
Libs/CommandLineModules/Backend/XMLChecker/target_libraries.cmake

@@ -0,0 +1,9 @@
+#
+# See CMake/ctkMacroGetTargetLibraries.cmake
+# 
+# This file should list the libraries required to build the current CTK libraries
+#
+
+set(target_libraries
+  CTKCommandLineModulesCore
+  )

+ 9 - 1
Libs/CommandLineModules/Core/ctkCmdLineModuleManager.cpp

@@ -85,7 +85,7 @@ struct ctkCmdLineModuleManagerPrivate
   QHash<QUrl, ctkCmdLineModuleReference> LocationToRef;
   QScopedPointer<ctkCmdLineModuleCache> ModuleCache;
 
-  const ctkCmdLineModuleManager::ValidationMode ValidationMode;
+  ctkCmdLineModuleManager::ValidationMode ValidationMode;
 };
 
 //----------------------------------------------------------------------------
@@ -105,6 +105,14 @@ ctkCmdLineModuleManager::ValidationMode ctkCmdLineModuleManager::validationMode(
   return d->ValidationMode;
 }
 
+
+//----------------------------------------------------------------------------
+void ctkCmdLineModuleManager::setValidationMode(const ValidationMode& mode)
+{
+  d->ValidationMode = mode;
+}
+
+
 //----------------------------------------------------------------------------
 void ctkCmdLineModuleManager::registerBackend(ctkCmdLineModuleBackend *backend)
 {

+ 5 - 0
Libs/CommandLineModules/Core/ctkCmdLineModuleManager.h

@@ -106,6 +106,11 @@ public:
   ValidationMode validationMode() const;
 
   /**
+   * @brief Set the validation mode.
+   */
+  void setValidationMode(const ValidationMode& mode);
+
+  /**
    * @brief Registers a new back-end.
    * @param backend The new back-end.
    * @throws ctkInvalidArgumentException if another back-end was already registered handling