changeset 295:b04b13810540 am-2

unified CMakeLists.txt into a single file for WASM/Native + bootstrap Command (to rework) + doc
author am@osimis.io
date Tue, 04 Sep 2018 15:09:42 +0200
parents faccc4b07b92
children ac9fd144feae
files .hgignore Applications/Commands/BaseCommandFactory.cpp Applications/Commands/BaseCommandFactory.h Applications/Commands/BaseCommands.yml Applications/Commands/ICommand.h Applications/Commands/ICommandExecutor.h Applications/Commands/ICommandFactory.h Applications/Samples/CMakeLists.txt Applications/Samples/SampleApplicationBase.h Applications/Samples/Web/tsconfig-simple-viewer.json Applications/Samples/build-wasm.sh Applications/Samples/build-web.sh Applications/Samples/nginx.local.conf Applications/Samples/tsconfig-stone.json Framework/SmartLoader.cpp Framework/StoneException.h Platforms/Generic/CMakeLists.txt Platforms/Generic/OracleWebService.h Platforms/Wasm/CMakeLists.txt Platforms/Wasm/build-wasm.sh Platforms/Wasm/build-web.sh Platforms/Wasm/nginx.local.conf Platforms/Wasm/tsconfig-stone.json README Resources/CMake/OrthancStoneConfiguration.cmake Resources/CMake/OrthancStoneParameters.cmake Resources/Orthanc/DownloadOrthancFramework.cmake UnitTestsSources/TestCommands.cpp
diffstat 28 files changed, 687 insertions(+), 310 deletions(-) [+]
line wrap: on
line diff
--- a/.hgignore	Thu Aug 30 17:17:11 2018 +0200
+++ b/.hgignore	Tue Sep 04 15:09:42 2018 +0200
@@ -1,7 +1,6 @@
-Platforms/Generic/CMakeLists.txt.user
+CMakeLists.txt.user
 Platforms/Generic/ThirdPartyDownloads/
-Platforms/Wasm/CMakeLists.txt.user
-Platforms/Wasm/build/
-Platforms/Wasm/build-web/
-Platforms/Wasm/ThirdPartyDownloads/
 Applications/Qt/archive/
+Applications/Samples/ThirdPartyDownloads/
+Applications/Samples/build-wasm/
+Applications/Samples/build-web/
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Applications/Commands/BaseCommandFactory.cpp	Tue Sep 04 15:09:42 2018 +0200
@@ -0,0 +1,50 @@
+/**
+ * Stone of Orthanc
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2018 Osimis S.A., Belgium
+ *
+ * This program is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Affero General Public License
+ * as published by the Free Software Foundation, either version 3 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ **/
+
+#include "BaseCommandFactory.h"
+#include "Core/OrthancException.h"
+
+namespace OrthancStone
+{
+  ICommand* BaseCommandFactory::CreateFromJson(const Json::Value& commandJson)
+  {
+    if (!commandJson.isObject() || !commandJson["command"].isString())
+    {
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_UnknownResource);  // TODO: use StoneException ?
+    }
+
+    std::string commandName = commandJson["command"].asString();
+    CommandCreationFunctions::const_iterator it = commands_.find(commandName);
+    if (it == commands_.end())
+    {
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_UnknownResource);  // TODO: use StoneException ?
+    }
+
+    // call the CreateCommandFn to build the command
+    ICommand* command = it->second();
+    if (commandJson["args"].isObject())
+    {
+      command->Configure(commandJson["args"]);
+    }
+
+    return command;
+  }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Applications/Commands/BaseCommandFactory.h	Tue Sep 04 15:09:42 2018 +0200
@@ -0,0 +1,50 @@
+/**
+ * Stone of Orthanc
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2018 Osimis S.A., Belgium
+ *
+ * This program is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Affero General Public License
+ * as published by the Free Software Foundation, either version 3 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ **/
+
+#pragma once
+
+#include <map>
+#include <memory>
+
+#include "ICommand.h"
+#include "../../Applications/Commands/ICommandFactory.h"
+
+// TODO: must be reworked completely (check trello)
+
+namespace OrthancStone
+{
+  class BaseCommandFactory
+  {
+    typedef ICommand* (*CommandCreationFn)(void);
+    typedef std::map<std::string, CommandCreationFn> CommandCreationFunctions;
+    CommandCreationFunctions commands_;
+
+  public:
+    virtual ICommand* CreateFromJson(const Json::Value& commandJson);
+
+    template<typename TCommand> void RegisterCommandClass()
+    {
+      // create the command only to get its name
+      std::auto_ptr<ICommand> command(TCommand::Create());
+
+      commands_[command->GetName()] = &TCommand::Create;
+    }
+  };
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Applications/Commands/BaseCommands.yml	Tue Sep 04 15:09:42 2018 +0200
@@ -0,0 +1,10 @@
+SelectTool:
+  target: Application
+  toolName: string
+  comment: Selects the current application tool
+DownloadDicom:
+  target: LayerWidget
+  comment: Downloads the slice currently displayed in the LayerWidget
+Export:
+  target: IWidget
+  comment: Export the content of the widget
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Applications/Commands/ICommand.h	Tue Sep 04 15:09:42 2018 +0200
@@ -0,0 +1,74 @@
+/**
+ * Stone of Orthanc
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2018 Osimis S.A., Belgium
+ *
+ * This program is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Affero General Public License
+ * as published by the Free Software Foundation, either version 3 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ **/
+
+
+#pragma once
+
+#include <json/json.h>
+
+// TODO: must be reworked completely (check trello)
+
+namespace OrthancStone
+{
+  class ICommand  // TODO noncopyable
+  {
+  protected:
+    const char* name_;
+    ICommand(const char* name)
+      : name_(name)
+    {}
+  public:
+    virtual void Execute() = 0;
+    virtual void Configure(const Json::Value& arguments) = 0;
+    const char* GetName()
+    {
+      return name_;
+    }
+  };
+
+
+  template <typename TCommand>
+  class BaseCommand : ICommand
+  {
+  protected:
+    BaseCommand(const char* name)
+      : ICommand(name)
+    {}
+
+  public:
+    static ICommand* Create() {
+      return new TCommand();
+    }
+
+    virtual void Configure(const Json::Value& arguments) {
+    }
+  };
+
+  class NoopCommand : public BaseCommand<NoopCommand>
+  {
+  public:
+    NoopCommand()
+      : BaseCommand("noop")
+    {}
+    virtual void Execute() {}
+  };
+
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Applications/Commands/ICommandExecutor.h	Tue Sep 04 15:09:42 2018 +0200
@@ -0,0 +1,32 @@
+/**
+ * Stone of Orthanc
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2018 Osimis S.A., Belgium
+ *
+ * This program is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Affero General Public License
+ * as published by the Free Software Foundation, either version 3 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ **/
+
+
+#pragma once
+
+#include <boost/noncopyable.hpp>
+
+namespace OrthancStone
+{
+  class ICommandExecutor : public boost::noncopyable
+  {
+
+  };
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Applications/Commands/ICommandFactory.h	Tue Sep 04 15:09:42 2018 +0200
@@ -0,0 +1,38 @@
+/**
+ * Stone of Orthanc
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2018 Osimis S.A., Belgium
+ *
+ * This program is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Affero General Public License
+ * as published by the Free Software Foundation, either version 3 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ **/
+
+
+#pragma once
+
+#include <boost/noncopyable.hpp>
+#include <json/json.h>
+
+#include "ICommand.h"
+
+namespace OrthancStone
+{
+
+  class ICommandFactory : public boost::noncopyable
+  {
+  public:
+    virtual ICommand* CreateFromJson(const Json::Value& commandJson) = 0;
+    template<typename TCommand> void RegisterCommandClass();
+  };
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Applications/Samples/CMakeLists.txt	Tue Sep 04 15:09:42 2018 +0200
@@ -0,0 +1,165 @@
+# Usage (Linux):
+# to build the WASM samples
+# source ~/Downloads/emsdk/emsdk_env.sh && cmake -DCMAKE_TOOLCHAIN_FILE=${EMSCRIPTEN}/cmake/Modules/Platform/Emscripten.cmake -DCMAKE_BUILD_TYPE=Release -DSTONE_SOURCES_DIR=$currentDir/../../../orthanc-stone -DORTHANC_FRAMEWORK_SOURCE=path -DORTHANC_FRAMEWORK_ROOT=$currentDir/../../../orthanc -DALLOW_DOWNLOADS=ON .. -DENABLE_WASM=ON
+# to build the Qt samples
+
+cmake_minimum_required(VERSION 2.8.3)
+project(OrthancStone)
+
+include(../../Resources/CMake/OrthancStoneParameters.cmake)
+
+
+set(ENABLE_SDL OFF CACHE BOOL "Target SDL Native application")
+set(ENABLE_QT OFF CACHE BOOL "Target Qt Native application")
+set(ENABLE_WASM OFF CACHE BOOL "Target WASM application")
+
+if (ENABLE_WASM)
+  #####################################################################
+  ## Configuration of the Emscripten compiler for WebAssembly target
+  #####################################################################
+
+  set(WASM_FLAGS "-s WASM=1")
+  set(WASM_MODULE_NAME "StoneFrameworkModule" CACHE STRING "Name of the WebAssembly module")
+  set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${WASM_FLAGS}")
+  set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${WASM_FLAGS}")
+  set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} --js-library ${STONE_SOURCES_DIR}/Applications/Samples/samples-library.js --js-library ${STONE_SOURCES_DIR}/Platforms/Wasm/WasmWebService.js --js-library ${STONE_SOURCES_DIR}/Platforms/Wasm/default-library.js  -s EXTRA_EXPORTED_RUNTIME_METHODS='[\"ccall\", \"cwrap\"]'")
+
+  # Handling of memory
+  #set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -s ALLOW_MEMORY_GROWTH=1")  # Resize
+  #set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -s TOTAL_MEMORY=536870912")  # 512MB
+  set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -s EXPORT_NAME='\"${WASM_MODULE_NAME}\"' -s ALLOW_MEMORY_GROWTH=1 -s TOTAL_MEMORY=536870912 -s TOTAL_STACK=128000000")  # 512MB + resize
+  #set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -s ALLOW_MEMORY_GROWTH=1 -s TOTAL_MEMORY=1073741824")  # 1GB + resize
+
+  # To debug exceptions
+  #set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -s DEMANGLE_SUPPORT=1 -s ASSERTIONS=2")
+
+  add_definitions(-DORTHANC_ENABLE_WASM=1)
+  set(ORTHANC_SANDBOXED ON)
+
+elseif (ENABLE_QT OR ENABLE_SDL)
+
+  set(ENABLE_NATIVE ON)
+  set(ORTHANC_SANDBOXED OFF)
+  set(ENABLE_CRYPTO_OPTIONS ON)
+  set(ENABLE_GOOGLE_TEST ON)
+  set(ENABLE_WEB_CLIENT ON)
+
+endif()
+
+#####################################################################
+## Configuration for Orthanc
+#####################################################################
+
+# include(../../Resources/CMake/Version.cmake)
+
+if (ORTHANC_STONE_VERSION STREQUAL "mainline")
+  set(ORTHANC_FRAMEWORK_VERSION "mainline")
+  set(ORTHANC_FRAMEWORK_DEFAULT_SOURCE "hg")
+else()
+  set(ORTHANC_FRAMEWORK_VERSION "1.4.1")
+  set(ORTHANC_FRAMEWORK_DEFAULT_SOURCE "web")
+endif()
+
+set(ORTHANC_FRAMEWORK_SOURCE "${ORTHANC_FRAMEWORK_DEFAULT_SOURCE}" CACHE STRING "Source of the Orthanc source code (can be \"hg\", \"archive\", \"web\" or \"path\")")
+set(ORTHANC_FRAMEWORK_ARCHIVE "" CACHE STRING "Path to the Orthanc archive, if ORTHANC_FRAMEWORK_SOURCE is \"archive\"")
+set(ORTHANC_FRAMEWORK_ROOT "" CACHE STRING "Path to the Orthanc source directory, if ORTHANC_FRAMEWORK_SOURCE is \"path\"")
+
+
+#####################################################################
+## Build a static library containing the Orthanc Stone framework
+#####################################################################
+
+
+LIST(APPEND ORTHANC_BOOST_COMPONENTS program_options)
+
+include(../../Resources/CMake/OrthancStoneConfiguration.cmake)
+
+add_library(OrthancStone STATIC
+  ${ORTHANC_STONE_SOURCES}
+  )
+
+#####################################################################
+## Build all the sample applications
+#####################################################################
+
+include_directories(${ORTHANC_STONE_ROOT})
+
+# files common to all samples
+list(APPEND APPLICATIONS_SOURCES
+  ${ORTHANC_STONE_ROOT}/Applications/Samples/SampleInteractor.h
+  ${ORTHANC_STONE_ROOT}/Applications/Samples/SampleApplicationBase.h
+  )
+
+if (ENABLE_QT)
+  list(APPEND APPLICATIONS_SOURCES
+    ${ORTHANC_STONE_ROOT}/Applications/Samples/Qt/SampleQtApplicationRunner.h
+    ${ORTHANC_STONE_ROOT}/Applications/Samples/Qt/SampleMainWindow.cpp
+    ${ORTHANC_STONE_ROOT}/Applications/Samples/Qt/SampleMainWindow.ui
+    )
+endif()
+
+if (ENABLE_NATIVE)
+  list(APPEND APPLICATIONS_SOURCES
+    ${ORTHANC_STONE_ROOT}/Applications/Samples/SampleMainNative.cpp
+    )
+
+elseif (ENABLE_WASM)
+
+  list(APPEND APPLICATIONS_SOURCES
+    ${ORTHANC_STONE_ROOT}/Applications/Samples/SampleMainWasm.cpp
+    ${STONE_WASM_SOURCES}
+    )
+endif()
+
+
+macro(BuildSingleFileSample Target Header Sample)
+  add_executable(${Target}
+    ${ORTHANC_STONE_ROOT}/Applications/Samples/${Header}
+    ${APPLICATIONS_SOURCES}
+    )
+  set_target_properties(${Target} PROPERTIES COMPILE_DEFINITIONS ORTHANC_STONE_SAMPLE=${Sample})
+  target_link_libraries(${Target} OrthancStone)
+endmacro()
+
+#BuildSingleFileSample(OrthancStoneEmpty EmptyApplication.h 1)
+#BuildSingleFileSample(OrthancStoneTestPattern TestPatternApplication.h 2)
+#BuildSingleFileSample(OrthancStoneSingleFrame SingleFrameApplication.h 3)
+#BuildSingleFileSample(OrthancStoneSingleVolume SingleVolumeApplication.h 4)
+#BuildSingleFileSample(OrthancStoneBasicPetCtFusion 5)
+#BuildSingleFileSample(OrthancStoneSynchronizedSeries 6)
+#BuildSingleFileSample(OrthancStoneLayoutPetCtFusion 7)
+BuildSingleFileSample(OrthancStoneSimpleViewer SimpleViewerApplication.h 8)
+
+#####################################################################
+## Build the unit tests
+#####################################################################
+
+if (ENABLE_NATIVE)
+  add_executable(UnitTests
+    ${GOOGLE_TEST_SOURCES}
+    ${ORTHANC_STONE_ROOT}/UnitTestsSources/TestMessageBroker.cpp
+    ${ORTHANC_STONE_ROOT}/UnitTestsSources/TestCommands.cpp
+    ${ORTHANC_STONE_ROOT}/UnitTestsSources/UnitTestsMain.cpp
+    )
+
+  target_link_libraries(UnitTests OrthancStone)
+endif()
+
+#####################################################################
+## Generate the documentation if Doxygen is present
+#####################################################################
+
+find_package(Doxygen)
+if (DOXYGEN_FOUND)
+  configure_file(
+    ${ORTHANC_STONE_ROOT}/Resources/OrthancStone.doxygen
+    ${CMAKE_CURRENT_BINARY_DIR}/OrthancStone.doxygen
+    @ONLY)
+
+  add_custom_target(doc
+    ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/OrthancStone.doxygen
+    COMMENT "Generating documentation with Doxygen" VERBATIM
+    )
+else()
+  message("Doxygen not found. The documentation will not be built.")
+endif()
--- a/Applications/Samples/SampleApplicationBase.h	Thu Aug 30 17:17:11 2018 +0200
+++ b/Applications/Samples/SampleApplicationBase.h	Tue Sep 04 15:09:42 2018 +0200
@@ -13,7 +13,7 @@
  * WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  * Affero General Public License for more details.
- * 
+ *
  * You should have received a copy of the GNU Affero General Public License
  * along with this program. If not, see <http://www.gnu.org/licenses/>.
  **/
@@ -34,9 +34,7 @@
                               IStatusBar& statusBar,
                               const boost::program_options::variables_map& parameters)
       {
-    }
-
-
+      }
 
       virtual std::string GetTitle() const
       {
@@ -48,11 +46,11 @@
       virtual void OnTool1Clicked() {}
       virtual void OnTool2Clicked() {}
 
-      virtual void GetButtonNames(std::string& pushButton1, 
-      std::string& pushButton2, 
-      std::string& tool1, 
-      std::string& tool2
-      ) {
+      virtual void GetButtonNames(std::string& pushButton1,
+                                  std::string& pushButton2,
+                                  std::string& tool1,
+                                  std::string& tool2
+                                  ) {
         pushButton1 = "action1";
         pushButton2 = "action2";
         tool1 = "tool1";
--- a/Applications/Samples/Web/tsconfig-simple-viewer.json	Thu Aug 30 17:17:11 2018 +0200
+++ b/Applications/Samples/Web/tsconfig-simple-viewer.json	Tue Sep 04 15:09:42 2018 +0200
@@ -1,7 +1,7 @@
 {
     "extends" : "./tsconfig-samples",
     "compilerOptions": {
-        "outFile": "../../../Platforms/Wasm/build-web/app-simple-viewer.js"
+        "outFile": "../build-web/app-simple-viewer.js"
     },
     "include" : [
         "simple-viewer.ts",
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Applications/Samples/build-wasm.sh	Tue Sep 04 15:09:42 2018 +0200
@@ -0,0 +1,15 @@
+#!/bin/bash
+
+currentDir=$(pwd)
+samplesRootDir=$(pwd)
+
+mkdir -p $samplesRootDir/build-wasm
+cd $samplesRootDir/build-wasm
+
+source ~/Downloads/emsdk/emsdk_env.sh
+cmake -DCMAKE_TOOLCHAIN_FILE=${EMSCRIPTEN}/cmake/Modules/Platform/Emscripten.cmake -DCMAKE_BUILD_TYPE=Release -DSTONE_SOURCES_DIR=$currentDir/../../../orthanc-stone -DORTHANC_FRAMEWORK_SOURCE=path -DORTHANC_FRAMEWORK_ROOT=$currentDir/../../../orthanc -DALLOW_DOWNLOADS=ON .. -DENABLE_WASM=ON
+make -j 5
+
+echo "-- building the web application -- "
+cd $currentDir
+./build-web.sh
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Applications/Samples/build-web.sh	Tue Sep 04 15:09:42 2018 +0200
@@ -0,0 +1,19 @@
+#!/bin/bash
+
+# this script currently assumes that the wasm code has been built on its side and is availabie in Wasm/build/
+
+currentDir=$(pwd)
+samplesRootDir=$(pwd)
+
+outputDir=$samplesRootDir/build-web/
+mkdir -p $outputDir
+
+cp $samplesRootDir/Web/index.html $outputDir
+cp $samplesRootDir/Web/samples-styles.css $outputDir
+
+cp $samplesRootDir/Web/simple-viewer.html $outputDir
+tsc --allowJs --project $samplesRootDir/Web/tsconfig-simple-viewer.json
+cp $currentDir/build-wasm/OrthancStoneSimpleViewer.js  $outputDir
+cp $currentDir/build-wasm/OrthancStoneSimpleViewer.wasm  $outputDir
+
+cd $currentDir
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Applications/Samples/nginx.local.conf	Tue Sep 04 15:09:42 2018 +0200
@@ -0,0 +1,44 @@
+# Local config to serve the WASM samples static files and reverse proxy Orthanc.
+# Uses port 9977 instead of 80.
+
+# `events` section is mandatory
+events {
+  worker_connections 1024; # Default: 1024
+}
+
+http {
+
+  # prevent nginx sync issues on OSX
+  proxy_buffering off;
+
+  server {
+    listen 9977 default_server;
+    client_max_body_size 4G;
+
+    # location may have to be adjusted depending on your OS and nginx install
+    include /etc/nginx/mime.types;
+    # if not in your system mime.types, add this line to support WASM:
+    # types {
+    #    application/wasm                      wasm; 
+    # }
+
+    # serve WASM static files
+    root build-web/;
+    location / {
+	}
+
+    # reverse proxy orthanc
+	location /orthanc/ {
+		rewrite /orthanc(.*) $1 break;
+		proxy_pass http://127.0.0.1:8042;
+		proxy_set_header Host $http_host;
+		proxy_set_header my-auth-header good-token;
+		proxy_request_buffering off;
+		proxy_max_temp_file_size 0;
+		client_max_body_size 0;
+	}
+
+
+  }
+  
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Applications/Samples/tsconfig-stone.json	Tue Sep 04 15:09:42 2018 +0200
@@ -0,0 +1,7 @@
+{
+    "include" : [
+        "../../Platforms/Wasm/stone-framework-loader.ts",
+        "../../Platforms/Wasm/wasm-application-runner.ts",
+        "../../Platforms/Wasm/wasm-viewport.ts"
+    ]
+}
--- a/Framework/SmartLoader.cpp	Thu Aug 30 17:17:11 2018 +0200
+++ b/Framework/SmartLoader.cpp	Tue Sep 04 15:09:42 2018 +0200
@@ -46,12 +46,12 @@
     switch (message.GetType()) {
     case MessageType_LayerSource_GeometryReady:
     {
-      const OrthancFrameLayerSource* layerSource=dynamic_cast<const OrthancFrameLayerSource*>(&from);
+      //const OrthancFrameLayerSource* layerSource=dynamic_cast<const OrthancFrameLayerSource*>(&from);
       // TODO keep track of objects that have been loaded already
     }; break;
     case MessageType_LayerSource_LayerReady:
     {
-      const OrthancFrameLayerSource* layerSource=dynamic_cast<const OrthancFrameLayerSource*>(&from);
+      //const OrthancFrameLayerSource* layerSource=dynamic_cast<const OrthancFrameLayerSource*>(&from);
       // TODO keep track of objects that have been loaded already
     }; break;
 //    case MessageType_OrthancApi_GetStudyIds_Ready:
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Framework/StoneException.h	Tue Sep 04 15:09:42 2018 +0200
@@ -0,0 +1,31 @@
+/**
+ * Stone of Orthanc
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2018 Osimis S.A., Belgium
+ *
+ * This program is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Affero General Public License
+ * as published by the Free Software Foundation, either version 3 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Affero General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ **/
+
+
+#pragma once
+
+#include "Core/OrthancException.h"
+
+namespace OrthancStone
+{
+
+
+}
+
--- a/Platforms/Generic/CMakeLists.txt	Thu Aug 30 17:17:11 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,113 +0,0 @@
-cmake_minimum_required(VERSION 2.8)
-project(OrthancStone)
-
-
-#####################################################################
-## Configuration for Orthanc
-#####################################################################
-
-include(../../Resources/CMake/Version.cmake)
-
-if (ORTHANC_STONE_VERSION STREQUAL "mainline")
-  set(ORTHANC_FRAMEWORK_VERSION "mainline")
-  set(ORTHANC_FRAMEWORK_DEFAULT_SOURCE "hg")
-else()
-  set(ORTHANC_FRAMEWORK_VERSION "1.3.2")
-  set(ORTHANC_FRAMEWORK_DEFAULT_SOURCE "web")
-endif()
-
-set(ORTHANC_FRAMEWORK_SOURCE "${ORTHANC_FRAMEWORK_DEFAULT_SOURCE}" CACHE STRING "Source of the Orthanc source code (can be \"hg\", \"archive\", \"web\" or \"path\")")
-set(ORTHANC_FRAMEWORK_ARCHIVE "" CACHE STRING "Path to the Orthanc archive, if ORTHANC_FRAMEWORK_SOURCE is \"archive\"")
-set(ORTHANC_FRAMEWORK_ROOT "" CACHE STRING "Path to the Orthanc source directory, if ORTHANC_FRAMEWORK_SOURCE is \"path\"")
-
-
-#####################################################################
-## Build a static library containing the Orthanc Stone framework
-#####################################################################
-
-include(../../Resources/CMake/OrthancStoneParameters.cmake)
-
-LIST(APPEND ORTHANC_BOOST_COMPONENTS program_options)
-
-SET(ENABLE_SDL ON)
-SET(ENABLE_QT OFF)
-SET(ORTHANC_SANDBOXED OFF)
-SET(ENABLE_CRYPTO_OPTIONS ON)
-SET(ENABLE_GOOGLE_TEST ON)
-SET(ENABLE_WEB_CLIENT ON)
-
-include(../../Resources/CMake/OrthancStoneConfiguration.cmake)
-
-add_library(OrthancStone STATIC
-  ${ORTHANC_STONE_SOURCES}
-  )
-
-
-#####################################################################
-## Build all the sample applications
-#####################################################################
-
-if (ENABLE_QT)
-  list(APPEND APPLICATIONS_SOURCES
-    ${ORTHANC_STONE_ROOT}/Applications/Samples/Qt/SampleQtApplicationRunner.h
-    ${ORTHANC_STONE_ROOT}/Applications/Samples/Qt/SampleMainWindow.cpp
-    ${ORTHANC_STONE_ROOT}/Applications/Samples/Qt/SampleMainWindow.ui
-    )
-endif()
-
-macro(BuildSingeFileSample Target Header Sample)
-  add_executable(${Target}
-    ${ORTHANC_STONE_ROOT}/Applications/Samples/SampleMainNative.cpp
-    ${ORTHANC_STONE_ROOT}/Applications/Samples/SampleInteractor.h
-    ${ORTHANC_STONE_ROOT}/Applications/Samples/SampleApplicationBase.h
-    ${ORTHANC_STONE_ROOT}/Applications/Samples/${Header}
-    ${APPLICATIONS_SOURCES}
-    )
-  set_target_properties(${Target} PROPERTIES COMPILE_DEFINITIONS ORTHANC_STONE_SAMPLE=${Sample})
-  target_link_libraries(${Target} OrthancStone)
-endmacro()
-
-
-# TODO - Re-enable all these samples!
-
-#BuildSample(OrthancStoneEmpty EmptyApplication.h 1)
-#BuildSample(OrthancStoneTestPattern TestPatternApplication.h 2)
-#BuildSample(OrthancStoneSingleFrame SingleFrameApplication.h 3)
-#BuildSample(OrthancStoneSingleVolume SingleVolumeApplication.h 4)
-##BuildSample(OrthancStoneBasicPetCtFusion 5)
-##BuildSample(OrthancStoneSynchronizedSeries 6)
-##BuildSample(OrthancStoneLayoutPetCtFusion 7)
-BuildSingeFileSample(OrthancStoneSimpleViewer SimpleViewerApplication.h 8)
-
-
-#####################################################################
-## Build the unit tests
-#####################################################################
-
-add_executable(UnitTests
-  ${GOOGLE_TEST_SOURCES}
-  ${ORTHANC_STONE_ROOT}/UnitTestsSources/TestMessageBroker.cpp
-  ${ORTHANC_STONE_ROOT}/UnitTestsSources/UnitTestsMain.cpp
-  )
-
-target_link_libraries(UnitTests OrthancStone)
-
-
-#####################################################################
-## Generate the documentation if Doxygen is present
-#####################################################################
-
-find_package(Doxygen)
-if (DOXYGEN_FOUND)
-  configure_file(
-    ${ORTHANC_STONE_ROOT}/Resources/OrthancStone.doxygen
-    ${CMAKE_CURRENT_BINARY_DIR}/OrthancStone.doxygen
-    @ONLY)
-
-  add_custom_target(doc
-    ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/OrthancStone.doxygen
-    COMMENT "Generating documentation with Doxygen" VERBATIM
-    )
-else()
-  message("Doxygen not found. The documentation will not be built.")
-endif()
--- a/Platforms/Generic/OracleWebService.h	Thu Aug 30 17:17:11 2018 +0200
+++ b/Platforms/Generic/OracleWebService.h	Tue Sep 04 15:09:42 2018 +0200
@@ -30,6 +30,8 @@
 namespace OrthancStone
 {
   // The OracleWebService performs HTTP requests in a native environment.
+  // It uses a thread pool to handle multiple HTTP requests in a same time.
+  // It works asynchronously to mimick the behaviour of the WebService running in a WASM environment.
   class OracleWebService : public IWebService
   {
   private:
--- a/Platforms/Wasm/CMakeLists.txt	Thu Aug 30 17:17:11 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,88 +0,0 @@
-# Usage (Linux):
-# source ~/Downloads/emsdk/emsdk_env.sh && cmake -DCMAKE_TOOLCHAIN_FILE=${EMSCRIPTEN}/cmake/Modules/Platform/Emscripten.cmake ..
-
-cmake_minimum_required(VERSION 2.8.3)
-
-
-#####################################################################
-## Configuration of the Emscripten compiler for WebAssembly target
-#####################################################################
-
-set(WASM_FLAGS "-s WASM=1")
-set(WASM_MODULE_NAME "StoneFrameworkModule" CACHE STRING "Name of the WebAssembly module")
-set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${WASM_FLAGS}")
-set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${WASM_FLAGS}")
-set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} --js-library ${STONE_SOURCES_DIR}/Applications/Samples/samples-library.js --js-library ${STONE_SOURCES_DIR}/Platforms/Wasm/WasmWebService.js --js-library ${STONE_SOURCES_DIR}/Platforms/Wasm/default-library.js  -s EXTRA_EXPORTED_RUNTIME_METHODS='[\"ccall\", \"cwrap\"]'")
-
-# Handling of memory
-#set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -s ALLOW_MEMORY_GROWTH=1")  # Resize
-#set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -s TOTAL_MEMORY=536870912")  # 512MB
-set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -s EXPORT_NAME='\"${WASM_MODULE_NAME}\"' -s ALLOW_MEMORY_GROWTH=1 -s TOTAL_MEMORY=536870912 -s TOTAL_STACK=128000000")  # 512MB + resize
-#set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -s ALLOW_MEMORY_GROWTH=1 -s TOTAL_MEMORY=1073741824")  # 1GB + resize
-
-# To debug exceptions
-#set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -s DEMANGLE_SUPPORT=1 -s ASSERTIONS=2")
-
-
-#####################################################################
-## Build a static library containing the Orthanc Stone framework
-#####################################################################
-
-include(../../Resources/CMake/OrthancStoneParameters.cmake)
-
-SET(ORTHANC_SANDBOXED ON)
-SET(ENABLE_QT OFF)
-SET(ENABLE_SDL OFF)
-add_definitions(-DORTHANC_ENABLE_WASM=1)
-
-include(../../Resources/CMake/OrthancStoneConfiguration.cmake)
-
-add_library(OrthancStone STATIC ${ORTHANC_STONE_SOURCES})
-
-
-
-# Regenerate a dummy "WasmWebService.c" file each time the "WasmWebService.js" file
-# is modified, so as to force a new execution of the linking
-add_custom_command(
-    OUTPUT "${AUTOGENERATED_DIR}/WasmWebService.c"
-    COMMAND ${CMAKE_COMMAND} -E touch "${AUTOGENERATED_DIR}/WasmWebService.c" ""
-    DEPENDS "${ORTHANC_STONE_ROOT}/Platforms/Wasm/WasmWebService.js")
-
-add_custom_command(
-    OUTPUT "${AUTOGENERATED_DIR}/default-library.c"
-    COMMAND ${CMAKE_COMMAND} -E touch "${AUTOGENERATED_DIR}/default-library.c" ""
-    DEPENDS "${ORTHANC_STONE_ROOT}/Platforms/Wasm/default-library.js")
-
-
-#####################################################################
-## Build all the sample applications
-#####################################################################
-
-include_directories(${ORTHANC_STONE_ROOT})
-
-
-macro(BuildSample Target Header Sample)
-  add_executable(${Target}
-    ${STONE_WASM_SOURCES}
-
-    ${AUTOGENERATED_DIR}/WasmWebService.c
-    ${AUTOGENERATED_DIR}/default-library.c
-
-    ${ORTHANC_STONE_ROOT}/Applications/Samples/SampleMainWasm.cpp
-#    ${ORTHANC_STONE_ROOT}/Applications/Samples/SampleApplicationContext.cpp
-    ${ORTHANC_STONE_ROOT}/Applications/Samples/SampleInteractor.h
-    ${ORTHANC_STONE_ROOT}/Applications/Samples/SampleApplicationBase.h
-    ${ORTHANC_STONE_ROOT}/Applications/Samples/${Header}
-    )
-  set_target_properties(${Target} PROPERTIES COMPILE_DEFINITIONS ORTHANC_STONE_SAMPLE=${Sample})
-  target_link_libraries(${Target} OrthancStone)
-endmacro()
-
-#BuildSample(OrthancStoneEmpty EmptyApplication.h 1)
-#BuildSample(OrthancStoneTestPattern TestPatternApplication.h 2)
-#BuildSample(OrthancStoneSingleFrame SingleFrameApplication.h 3)
-#BuildSample(OrthancStoneSingleVolume SingleVolumeApplication.h 4)
-#BuildSample(OrthancStoneBasicPetCtFusion 5)
-#BuildSample(OrthancStoneSynchronizedSeries 6)
-#BuildSample(OrthancStoneLayoutPetCtFusion 7)
-BuildSample(OrthancStoneSimpleViewer SimpleViewerApplication.h 8)
--- a/Platforms/Wasm/build-wasm.sh	Thu Aug 30 17:17:11 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,15 +0,0 @@
-#!/bin/bash
-
-currentDir=$(pwd)
-wasmRootDir=$(pwd)
-
-mkdir -p $wasmRootDir/build
-cd $wasmRootDir/build
-
-source ~/Downloads/emsdk/emsdk_env.sh
-cmake -DCMAKE_TOOLCHAIN_FILE=${EMSCRIPTEN}/cmake/Modules/Platform/Emscripten.cmake -DCMAKE_BUILD_TYPE=Release -DSTONE_SOURCES_DIR=$currentDir/../../../orthanc-stone -DORTHANC_FRAMEWORK_SOURCE=path -DORTHANC_FRAMEWORK_ROOT=$currentDir/../../../orthanc -DALLOW_DOWNLOADS=ON ..
-make -j 5
-
-echo "-- building the web application -- "
-cd $currentDir
-./build-web.sh
\ No newline at end of file
--- a/Platforms/Wasm/build-web.sh	Thu Aug 30 17:17:11 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,24 +0,0 @@
-#!/bin/bash
-
-# this script currently assumes that the wasm code has been built on its side and is availabie in Wasm/build/
-
-currentDir=$(pwd)
-wasmRootDir=$(pwd)
-samplesRootDir=$(pwd)/../../Applications/Samples/
-
-outputDir=$wasmRootDir/build-web/
-mkdir -p $outputDir
-
-cp $samplesRootDir/Web/index.html $outputDir
-cp $samplesRootDir/Web/samples-styles.css $outputDir
-
-cp $samplesRootDir/Web/simple-viewer.html $outputDir
-tsc --allowJs --project $samplesRootDir/Web/tsconfig-simple-viewer.json
-cp $currentDir/build/OrthancStoneSimpleViewer.js  $outputDir
-cp $currentDir/build/OrthancStoneSimpleViewer.wasm  $outputDir
-
-
-# cat ../wasm/build/wasm-app.js $currentDir/../../../orthanc-stone/Platforms/WebAssembly/defaults.js > $outputDir/app.js
-
-cd $currentDir
-
--- a/Platforms/Wasm/nginx.local.conf	Thu Aug 30 17:17:11 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,44 +0,0 @@
-# Local config to serve the WASM samples static files and reverse proxy Orthanc.
-# Uses port 9977 instead of 80.
-
-# `events` section is mandatory
-events {
-  worker_connections 1024; # Default: 1024
-}
-
-http {
-
-  # prevent nginx sync issues on OSX
-  proxy_buffering off;
-
-  server {
-    listen 9977 default_server;
-    client_max_body_size 4G;
-
-    # location may have to be adjusted depending on your OS and nginx install
-    include /etc/nginx/mime.types;
-    # if not in your system mime.types, add this line to support WASM:
-    # types {
-    #    application/wasm                      wasm; 
-    # }
-
-    # serve WASM static files
-    root build-web/;
-    location / {
-	}
-
-    # reverse proxy orthanc
-	location /orthanc/ {
-		rewrite /orthanc(.*) $1 break;
-		proxy_pass http://127.0.0.1:8042;
-		proxy_set_header Host $http_host;
-		proxy_set_header my-auth-header good-token;
-		proxy_request_buffering off;
-		proxy_max_temp_file_size 0;
-		client_max_body_size 0;
-	}
-
-
-  }
-  
-}
--- a/Platforms/Wasm/tsconfig-stone.json	Thu Aug 30 17:17:11 2018 +0200
+++ b/Platforms/Wasm/tsconfig-stone.json	Tue Sep 04 15:09:42 2018 +0200
@@ -1,7 +1,7 @@
 {
     "include" : [
-        "../../../Platforms/Wasm/stone-framework-loader.ts",
-        "../../../Platforms/Wasm/wasm-application-runner.ts",
-        "../../../Platforms/Wasm/wasm-viewport.ts"
+        "stone-framework-loader.ts",
+        "wasm-application-runner.ts",
+        "wasm-viewport.ts"
     ]
 }
--- a/README	Thu Aug 30 17:17:11 2018 +0200
+++ b/README	Tue Sep 04 15:09:42 2018 +0200
@@ -93,7 +93,7 @@
 to build the WASM samples:
 -------------------------
 ```
-cd ~/orthanc-stone/Platforms/Wasm
+cd ~/orthanc-stone/Applications/Samples
 ./build-wasm.sh
 ```
 
@@ -112,7 +112,7 @@
 ```
 mkdir -p ~/builds/orthanc-stone-build
 cd ~/builds/orthanc-stone-build
-cmake -DALLOW_DOWNLOADS=ON ~/orthanc-stone/
+cmake -DALLOW_DOWNLOADS=ON -DENABLE_SDL=ON ~/orthanc-stone/Applications/Samples/
 cmake --build . --target OrthancStoneSimpleViewer -- -j 5
 ```
 
@@ -122,7 +122,7 @@
 Orthanc
 
 # launch the sample
-./OrthancStoneSimpleViewer --instance1=XX --instance2=XX
+./OrthancStoneSimpleViewer --studyId=XX
 ``` 
 
 
--- a/Resources/CMake/OrthancStoneConfiguration.cmake	Thu Aug 30 17:17:11 2018 +0200
+++ b/Resources/CMake/OrthancStoneConfiguration.cmake	Tue Sep 04 15:09:42 2018 +0200
@@ -164,6 +164,10 @@
 set(APPLICATIONS_SOURCES
     ${ORTHANC_STONE_ROOT}/Applications/IStoneApplication.h
     ${ORTHANC_STONE_ROOT}/Applications/StoneApplicationContext.cpp
+    ${ORTHANC_STONE_ROOT}/Applications/Commands/BaseCommandFactory.cpp
+    ${ORTHANC_STONE_ROOT}/Applications/Commands/ICommand.h
+    ${ORTHANC_STONE_ROOT}/Applications/Commands/ICommandExecutor.h
+    ${ORTHANC_STONE_ROOT}/Applications/Commands/ICommandFactory.h
     )
 
 if (NOT ORTHANC_SANDBOXED)
@@ -190,7 +194,7 @@
         )
     endif()
   endif()
-else()
+elseif (ENABLE_WASM)
   list(APPEND APPLICATIONS_SOURCES
     ${ORTHANC_STONE_ROOT}/Applications/Wasm/StartupParametersBuilder.cpp
     )
@@ -200,7 +204,20 @@
     ${ORTHANC_STONE_ROOT}/Platforms/Wasm/WasmWebService.cpp
     ${ORTHANC_STONE_ROOT}/Platforms/Wasm/WasmViewport.cpp
     ${ORTHANC_STONE_ROOT}/Platforms/Wasm/IStoneApplicationToWebApplicationAdapter.h
+    ${AUTOGENERATED_DIR}/WasmWebService.c
+    ${AUTOGENERATED_DIR}/default-library.c
   )
+
+  # Regenerate a dummy "WasmWebService.c" file each time the "WasmWebService.js" file
+  # is modified, so as to force a new execution of the linking
+  add_custom_command(
+    OUTPUT "${AUTOGENERATED_DIR}/WasmWebService.c"
+    COMMAND ${CMAKE_COMMAND} -E touch "${AUTOGENERATED_DIR}/WasmWebService.c" ""
+    DEPENDS "${ORTHANC_STONE_ROOT}/Platforms/Wasm/WasmWebService.js")
+  add_custom_command(
+    OUTPUT "${AUTOGENERATED_DIR}/default-library.c"
+    COMMAND ${CMAKE_COMMAND} -E touch "${AUTOGENERATED_DIR}/default-library.c" ""
+    DEPENDS "${ORTHANC_STONE_ROOT}/Platforms/Wasm/default-library.js")
 endif()
 
 list(APPEND ORTHANC_STONE_SOURCES
@@ -209,6 +226,8 @@
   #${ORTHANC_STONE_ROOT}/Framework/Layers/SingleFrameRendererFactory.cpp
   ${ORTHANC_STONE_ROOT}/Framework/StoneEnumerations.cpp
   ${ORTHANC_STONE_ROOT}/Framework/SmartLoader.cpp
+  ${ORTHANC_STONE_ROOT}/Framework/dev.h
+  ${ORTHANC_STONE_ROOT}/Framework/StoneException.h
   ${ORTHANC_STONE_ROOT}/Framework/Layers/CircleMeasureTracker.cpp
   ${ORTHANC_STONE_ROOT}/Framework/Layers/ColorFrameRenderer.cpp
   ${ORTHANC_STONE_ROOT}/Framework/Layers/DicomStructureSetRendererFactory.cpp
--- a/Resources/CMake/OrthancStoneParameters.cmake	Thu Aug 30 17:17:11 2018 +0200
+++ b/Resources/CMake/OrthancStoneParameters.cmake	Tue Sep 04 15:09:42 2018 +0200
@@ -49,5 +49,3 @@
 ## the Stone of Orthanc
 #####################################################################
 
-set(ENABLE_SDL ON CACHE INTERNAL "Include support for SDL")
-set(ENABLE_QT OFF CACHE INTERNAL "Include support for Qt")
--- a/Resources/Orthanc/DownloadOrthancFramework.cmake	Thu Aug 30 17:17:11 2018 +0200
+++ b/Resources/Orthanc/DownloadOrthancFramework.cmake	Tue Sep 04 15:09:42 2018 +0200
@@ -84,6 +84,8 @@
       set(ORTHANC_FRAMEWORK_MD5 "dac95bd6cf86fb19deaf4e612961f378")
     elseif (ORTHANC_FRAMEWORK_VERSION STREQUAL "1.3.2")
       set(ORTHANC_FRAMEWORK_MD5 "d0ccdf68e855d8224331f13774992750")
+    elseif (ORTHANC_FRAMEWORK_VERSION STREQUAL "1.4.1")
+      set(ORTHANC_FRAMEWORK_MD5 "d41d8cd98f00b204e9800998ecf8427e")
     endif()
   endif()
 endif()
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/UnitTestsSources/TestCommands.cpp	Tue Sep 04 15:09:42 2018 +0200
@@ -0,0 +1,108 @@
+/**
+ * Stone of Orthanc
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2018 Osimis S.A., Belgium
+ *
+ * This program is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Affero General Public License
+ * as published by the Free Software Foundation, either version 3 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ **/
+
+
+#include "gtest/gtest.h"
+
+#include "../Applications/Commands/BaseCommandFactory.h"
+#include "Core/OrthancException.h"
+
+class CommandIncrement: public OrthancStone::BaseCommand<CommandIncrement>
+{
+public:
+  static int counter;
+  int increment_;
+public:
+  CommandIncrement()
+    : OrthancStone::BaseCommand<CommandIncrement>("increment"),
+      increment_(0)
+  {}
+
+  virtual void Execute()
+  {
+    counter += increment_;
+  }
+  virtual void Configure(const Json::Value& arguments)
+  {
+    increment_ = arguments["increment"].asInt();
+  }
+};
+
+// COMMAND("name", "arg1", "int", "arg2", "string")
+// COMMAND(name, arg1, arg2)
+
+
+int CommandIncrement::counter = 0;
+
+TEST(Commands, CreateNoop)
+{
+  OrthancStone::BaseCommandFactory factory;
+
+  factory.RegisterCommandClass<OrthancStone::NoopCommand>();
+
+  Json::Value cmdJson;
+  cmdJson["command"] = "noop";
+
+  std::auto_ptr<OrthancStone::ICommand> command(factory.CreateFromJson(cmdJson));
+
+  ASSERT_TRUE(command.get() != NULL);
+  ASSERT_EQ("noop", command->GetName());
+}
+
+TEST(Commands, Execute)
+{
+  OrthancStone::BaseCommandFactory factory;
+
+  factory.RegisterCommandClass<OrthancStone::NoopCommand>();
+  factory.RegisterCommandClass<CommandIncrement>();
+
+  Json::Value cmdJson;
+  cmdJson["command"] = "increment";
+  cmdJson["args"]["increment"] = 2;
+
+  std::auto_ptr<OrthancStone::ICommand> command(factory.CreateFromJson(cmdJson));
+
+  ASSERT_TRUE(command.get() != NULL);
+  CommandIncrement::counter = 0;
+  command->Execute();
+  ASSERT_EQ(2, CommandIncrement::counter);
+}
+
+TEST(Commands, TryCreateUnknowCommand)
+{
+  OrthancStone::BaseCommandFactory factory;
+  factory.RegisterCommandClass<OrthancStone::NoopCommand>();
+
+  Json::Value cmdJson;
+  cmdJson["command"] = "unknown";
+
+  ASSERT_THROW(std::auto_ptr<OrthancStone::ICommand> command(factory.CreateFromJson(cmdJson)), Orthanc::OrthancException);
+}
+
+TEST(Commands, TryCreateCommandFromInvalidJson)
+{
+  OrthancStone::BaseCommandFactory factory;
+  factory.RegisterCommandClass<OrthancStone::NoopCommand>();
+
+  Json::Value cmdJson;
+  cmdJson["command-name"] = "noop";
+
+  ASSERT_THROW(std::auto_ptr<OrthancStone::ICommand> command(factory.CreateFromJson(cmdJson)), Orthanc::OrthancException);
+}