changeset 285:3c190e2bb3af am-2

refactoring: ApplicationRunner + app hierarchy
author am@osimis.io
date Tue, 28 Aug 2018 15:26:46 +0200
parents 38b0ac8055b9
children 6b3d91857b96
files .hgignore Applications/Generic/BasicNativeApplication.cpp Applications/Generic/BasicNativeApplication.h Applications/Generic/BasicNativeApplicationRunner.cpp Applications/Generic/BasicNativeApplicationRunner.h Applications/Qt/BasicQtApplication.cpp Applications/Qt/BasicQtApplication.h Applications/Qt/BasicQtApplicationRunner.cpp Applications/Qt/BasicQtApplicationRunner.h Applications/Qt/QStoneMainWindow.cpp Applications/Qt/QStoneMainWindow.h Applications/Samples/Qt/MainWindow.cpp Applications/Samples/Qt/MainWindow.h Applications/Samples/Qt/MainWindow.ui Applications/Samples/Qt/SampleMainWindow.cpp Applications/Samples/Qt/SampleMainWindow.h Applications/Samples/Qt/SampleMainWindow.ui Applications/Samples/Qt/SampleQtApplicationRunner.h Applications/Samples/SampleApplicationBase.h Applications/Samples/SampleList.h Applications/Samples/SampleMainNative.cpp Applications/Samples/SampleMainWasm.cpp Applications/Samples/SimpleViewerApplication.h Applications/Samples/Web/index.html Applications/Samples/Web/simple-viewer.html Applications/Samples/Web/tsconfig-simple-viewer.json Framework/SmartLoader.cpp Platforms/Generic/CMakeLists.txt Resources/CMake/OrthancStoneConfiguration.cmake Resources/CMake/QtConfiguration.cmake TODO
diffstat 31 files changed, 856 insertions(+), 622 deletions(-) [+]
line wrap: on
line diff
--- a/.hgignore	Tue Aug 28 11:09:37 2018 +0200
+++ b/.hgignore	Tue Aug 28 15:26:46 2018 +0200
@@ -4,3 +4,4 @@
 Platforms/Wasm/build/
 Platforms/Wasm/build-web/
 Platforms/Wasm/ThirdPartyDownloads/
+Applications/Qt/archive/
--- a/Applications/Generic/BasicNativeApplication.cpp	Tue Aug 28 11:09:37 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,242 +0,0 @@
-/**
- * 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/>.
- **/
-
-
-#if ORTHANC_ENABLE_NATIVE != 1
-#error this file shall be included only with the ORTHANC_ENABLE_NATIVE set to 1
-#endif
-
-#include "BasicNativeApplication.h"
-#include "BasicNativeApplicationContext.h"
-#include <boost/program_options.hpp>
-
-#include "../../Framework/Toolbox/MessagingToolbox.h"
-
-#include <Core/Logging.h>
-#include <Core/HttpClient.h>
-#include <Core/Toolbox.h>
-#include <Plugins/Samples/Common/OrthancHttpConnection.h>
-#include "../../Platforms/Generic/OracleWebService.h"
-
-namespace OrthancStone
-{
-  // Anonymous namespace to avoid clashes against other compilation modules
-  namespace
-  {
-    class LogStatusBar : public IStatusBar
-    {
-    public:
-      virtual void ClearMessage()
-      {
-      }
-
-      virtual void SetMessage(const std::string& message)
-      {
-        LOG(WARNING) << message;
-      }
-    };
-  }
-
-  int BasicNativeApplication::Execute(MessageBroker& broker,
-                                   IBasicApplication& application,
-                                   int argc,
-                                   char* argv[])
-  {
-    /******************************************************************
-     * Initialize all the subcomponents of Orthanc Stone
-     ******************************************************************/
-
-    Orthanc::Logging::Initialize();
-    Orthanc::Toolbox::InitializeOpenSsl();
-    Orthanc::HttpClient::GlobalInitialize();
-
-    Initialize();
-
-    /******************************************************************
-     * Declare and parse the command-line options of the application
-     ******************************************************************/
-
-    boost::program_options::options_description options;
-
-    { // generic options
-      boost::program_options::options_description generic("Generic options");
-      generic.add_options()
-          ("help", "Display this help and exit")
-          ("verbose", "Be verbose in logs")
-          ("orthanc", boost::program_options::value<std::string>()->default_value("http://localhost:8042/"),
-          "URL to the Orthanc server")
-          ("username", "Username for the Orthanc server")
-          ("password", "Password for the Orthanc server")
-          ("https-verify", boost::program_options::value<bool>()->default_value(true), "Check HTTPS certificates")
-          ;
-
-      options.add(generic);
-    }
-
-    // platform specific options
-    DeclareCommandLineOptions(options);
-    
-    // application specific options
-    application.DeclareStartupOptions(options);
-
-    boost::program_options::variables_map parameters;
-    bool error = false;
-
-    try
-    {
-      boost::program_options::store(boost::program_options::command_line_parser(argc, argv).
-                                    options(options).run(), parameters);
-      boost::program_options::notify(parameters);
-    }
-    catch (boost::program_options::error& e)
-    {
-      LOG(ERROR) << "Error while parsing the command-line arguments: " << e.what();
-      error = true;
-    }
-
-
-    /******************************************************************
-     * Configure the application with the command-line parameters
-     ******************************************************************/
-
-    if (error || parameters.count("help"))
-    {
-      std::cout << std::endl
-                << "Usage: " << argv[0] << " [OPTION]..."
-                << std::endl
-                << "Orthanc, lightweight, RESTful DICOM server for healthcare and medical research."
-                << std::endl << std::endl
-                << "Demonstration application of Orthanc Stone using SDL."
-                << std::endl;
-
-      std::cout << options << "\n";
-      return error ? -1 : 0;
-    }
-
-    if (parameters.count("https-verify") &&
-        !parameters["https-verify"].as<bool>())
-    {
-      LOG(WARNING) << "Turning off verification of HTTPS certificates (unsafe)";
-      Orthanc::HttpClient::ConfigureSsl(false, "");
-    }
-
-    if (parameters.count("verbose"))
-    {
-      Orthanc::Logging::EnableInfoLevel(true);
-    }
-
-    ParseCommandLineOptions(parameters);
-
-
-    bool success = true;
-    try
-    {
-      /****************************************************************
-       * Initialize the connection to the Orthanc server
-       ****************************************************************/
-
-      Orthanc::WebServiceParameters webServiceParameters;
-
-      if (parameters.count("orthanc"))
-      {
-        webServiceParameters.SetUrl(parameters["orthanc"].as<std::string>());
-      }
-
-      if (parameters.count("username"))
-      {
-        webServiceParameters.SetUsername(parameters["username"].as<std::string>());
-      }
-
-      if (parameters.count("password"))
-      {
-        webServiceParameters.SetPassword(parameters["password"].as<std::string>());
-      }
-
-      LOG(WARNING) << "URL to the Orthanc REST API: " << webServiceParameters.GetUrl();
-
-      {
-        OrthancPlugins::OrthancHttpConnection orthanc(webServiceParameters);
-        if (!MessagingToolbox::CheckOrthancVersion(orthanc))
-        {
-          LOG(ERROR) << "Your version of Orthanc is incompatible with Stone of Orthanc, please upgrade";
-          throw Orthanc::OrthancException(Orthanc::ErrorCode_NetworkProtocol);
-        }
-      }
-
-
-      /****************************************************************
-       * Initialize the application
-       ****************************************************************/
-
-      LOG(WARNING) << "Creating the widgets of the application";
-
-      LogStatusBar statusBar;
-
-      BasicNativeApplicationContext context;
-      Oracle oracle(4); // use 4 threads to download content
-      OracleWebService webService(broker, oracle, webServiceParameters, context);
-      context.SetWebService(webService);
-
-      application.Initialize(&context, statusBar, parameters);
-
-      {
-        BasicNativeApplicationContext::GlobalMutexLocker locker(context);
-        context.SetCentralWidget(application.GetCentralWidget());
-        context.GetCentralViewport().SetStatusBar(statusBar);
-      }
-
-      std::string title = application.GetTitle();
-      if (title.empty())
-      {
-        title = "Stone of Orthanc";
-      }
-
-      /****************************************************************
-       * Run the application
-       ****************************************************************/
-
-      Run(context, title, argc, argv);
-
-      /****************************************************************
-       * Finalize the application
-       ****************************************************************/
-
-      LOG(WARNING) << "The application has stopped";
-      application.Finalize();
-    }
-    catch (Orthanc::OrthancException& e)
-    {
-      LOG(ERROR) << "EXCEPTION: " << e.What();
-      success = false;
-    }
-
-
-    /******************************************************************
-     * Finalize all the subcomponents of Orthanc Stone
-     ******************************************************************/
-
-    Finalize();
-    Orthanc::HttpClient::GlobalFinalize();
-    Orthanc::Toolbox::FinalizeOpenSsl();
-
-    return (success ? 0 : -1);
-  }
-
-}
--- a/Applications/Generic/BasicNativeApplication.h	Tue Aug 28 11:09:37 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,51 +0,0 @@
-/**
- * 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 "../IBasicApplication.h"
-
-#if ORTHANC_ENABLE_NATIVE != 1
-#error this file shall be included only with the ORTHANC_ENABLE_NATIVE set to 1
-#endif
-
-namespace OrthancStone
-{
-  class BasicNativeApplicationContext;
-
-  class BasicNativeApplication
-  {
-  public:
-
-    int Execute(MessageBroker& broker,
-                IBasicApplication& application,
-                int argc,
-                char* argv[]);
-
-    virtual void Initialize() = 0;
-    virtual void DeclareCommandLineOptions(boost::program_options::options_description& options) = 0;
-    virtual void ParseCommandLineOptions(const boost::program_options::variables_map& parameters) = 0;
-
-    virtual void Run(BasicNativeApplicationContext& context, const std::string& title, int argc, char* argv[]) = 0;
-    virtual void Finalize() = 0;
-  };
-
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Applications/Generic/BasicNativeApplicationRunner.cpp	Tue Aug 28 15:26:46 2018 +0200
@@ -0,0 +1,240 @@
+/**
+ * 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/>.
+ **/
+
+
+#if ORTHANC_ENABLE_NATIVE != 1
+#error this file shall be included only with the ORTHANC_ENABLE_NATIVE set to 1
+#endif
+
+#include "BasicNativeApplicationRunner.h"
+#include "BasicNativeApplicationContext.h"
+#include <boost/program_options.hpp>
+
+#include "../../Framework/Toolbox/MessagingToolbox.h"
+
+#include <Core/Logging.h>
+#include <Core/HttpClient.h>
+#include <Core/Toolbox.h>
+#include <Plugins/Samples/Common/OrthancHttpConnection.h>
+#include "../../Platforms/Generic/OracleWebService.h"
+
+namespace OrthancStone
+{
+  // Anonymous namespace to avoid clashes against other compilation modules
+  namespace
+  {
+    class LogStatusBar : public IStatusBar
+    {
+    public:
+      virtual void ClearMessage()
+      {
+      }
+
+      virtual void SetMessage(const std::string& message)
+      {
+        LOG(WARNING) << message;
+      }
+    };
+  }
+
+  int BasicNativeApplicationRunner::Execute(int argc,
+                                            char* argv[])
+  {
+    /******************************************************************
+     * Initialize all the subcomponents of Orthanc Stone
+     ******************************************************************/
+
+    Orthanc::Logging::Initialize();
+    Orthanc::Toolbox::InitializeOpenSsl();
+    Orthanc::HttpClient::GlobalInitialize();
+
+    Initialize();
+
+    /******************************************************************
+     * Declare and parse the command-line options of the application
+     ******************************************************************/
+
+    boost::program_options::options_description options;
+
+    { // generic options
+      boost::program_options::options_description generic("Generic options");
+      generic.add_options()
+          ("help", "Display this help and exit")
+          ("verbose", "Be verbose in logs")
+          ("orthanc", boost::program_options::value<std::string>()->default_value("http://localhost:8042/"),
+           "URL to the Orthanc server")
+          ("username", "Username for the Orthanc server")
+          ("password", "Password for the Orthanc server")
+          ("https-verify", boost::program_options::value<bool>()->default_value(true), "Check HTTPS certificates")
+          ;
+
+      options.add(generic);
+    }
+
+    // platform specific options
+    DeclareCommandLineOptions(options);
+    
+    // application specific options
+    application_.DeclareStartupOptions(options);
+
+    boost::program_options::variables_map parameters;
+    bool error = false;
+
+    try
+    {
+      boost::program_options::store(boost::program_options::command_line_parser(argc, argv).
+                                    options(options).run(), parameters);
+      boost::program_options::notify(parameters);
+    }
+    catch (boost::program_options::error& e)
+    {
+      LOG(ERROR) << "Error while parsing the command-line arguments: " << e.what();
+      error = true;
+    }
+
+
+    /******************************************************************
+     * Configure the application with the command-line parameters
+     ******************************************************************/
+
+    if (error || parameters.count("help"))
+    {
+      std::cout << std::endl
+                << "Usage: " << argv[0] << " [OPTION]..."
+                << std::endl
+                << "Orthanc, lightweight, RESTful DICOM server for healthcare and medical research."
+                << std::endl << std::endl
+                << "Demonstration application of Orthanc Stone using SDL."
+                << std::endl;
+
+      std::cout << options << "\n";
+      return error ? -1 : 0;
+    }
+
+    if (parameters.count("https-verify") &&
+        !parameters["https-verify"].as<bool>())
+    {
+      LOG(WARNING) << "Turning off verification of HTTPS certificates (unsafe)";
+      Orthanc::HttpClient::ConfigureSsl(false, "");
+    }
+
+    if (parameters.count("verbose"))
+    {
+      Orthanc::Logging::EnableInfoLevel(true);
+    }
+
+    ParseCommandLineOptions(parameters);
+
+
+    bool success = true;
+    try
+    {
+      /****************************************************************
+       * Initialize the connection to the Orthanc server
+       ****************************************************************/
+
+      Orthanc::WebServiceParameters webServiceParameters;
+
+      if (parameters.count("orthanc"))
+      {
+        webServiceParameters.SetUrl(parameters["orthanc"].as<std::string>());
+      }
+
+      if (parameters.count("username"))
+      {
+        webServiceParameters.SetUsername(parameters["username"].as<std::string>());
+      }
+
+      if (parameters.count("password"))
+      {
+        webServiceParameters.SetPassword(parameters["password"].as<std::string>());
+      }
+
+      LOG(WARNING) << "URL to the Orthanc REST API: " << webServiceParameters.GetUrl();
+
+      {
+        OrthancPlugins::OrthancHttpConnection orthanc(webServiceParameters);
+        if (!MessagingToolbox::CheckOrthancVersion(orthanc))
+        {
+          LOG(ERROR) << "Your version of Orthanc is incompatible with Stone of Orthanc, please upgrade";
+          throw Orthanc::OrthancException(Orthanc::ErrorCode_NetworkProtocol);
+        }
+      }
+
+
+      /****************************************************************
+       * Initialize the application
+       ****************************************************************/
+
+      LOG(WARNING) << "Creating the widgets of the application";
+
+      LogStatusBar statusBar;
+
+      BasicNativeApplicationContext context;
+      Oracle oracle(4); // use 4 threads to download content
+      OracleWebService webService(broker_, oracle, webServiceParameters, context);
+      context.SetWebService(webService);
+
+      application_.Initialize(&context, statusBar, parameters);
+
+      {
+        BasicNativeApplicationContext::GlobalMutexLocker locker(context);
+        context.SetCentralWidget(application_.GetCentralWidget());
+        context.GetCentralViewport().SetStatusBar(statusBar);
+      }
+
+      std::string title = application_.GetTitle();
+      if (title.empty())
+      {
+        title = "Stone of Orthanc";
+      }
+
+      /****************************************************************
+       * Run the application
+       ****************************************************************/
+
+      Run(context, title, argc, argv);
+
+      /****************************************************************
+       * Finalize the application
+       ****************************************************************/
+
+      LOG(WARNING) << "The application is stopping";
+      application_.Finalize();
+    }
+    catch (Orthanc::OrthancException& e)
+    {
+      LOG(ERROR) << "EXCEPTION: " << e.What();
+      success = false;
+    }
+
+
+    /******************************************************************
+     * Finalize all the subcomponents of Orthanc Stone
+     ******************************************************************/
+
+    Finalize();
+    Orthanc::HttpClient::GlobalFinalize();
+    Orthanc::Toolbox::FinalizeOpenSsl();
+
+    return (success ? 0 : -1);
+  }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Applications/Generic/BasicNativeApplicationRunner.h	Tue Aug 28 15:26:46 2018 +0200
@@ -0,0 +1,58 @@
+/**
+ * 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 "../IBasicApplication.h"
+
+#if ORTHANC_ENABLE_NATIVE != 1
+#error this file shall be included only with the ORTHANC_ENABLE_NATIVE set to 1
+#endif
+
+namespace OrthancStone
+{
+  class BasicNativeApplicationContext;
+
+  class BasicNativeApplicationRunner
+  {
+  protected:
+    MessageBroker&      broker_;
+    IBasicApplication&  application_;
+  public:
+
+    BasicNativeApplicationRunner(MessageBroker& broker,
+                                 IBasicApplication& application)
+      : broker_(broker),
+        application_(application)
+    {
+    }
+    int Execute(int argc,
+                char* argv[]);
+
+    virtual void Initialize() = 0;
+    virtual void DeclareCommandLineOptions(boost::program_options::options_description& options) = 0;
+    virtual void ParseCommandLineOptions(const boost::program_options::variables_map& parameters) = 0;
+
+    virtual void Run(BasicNativeApplicationContext& context, const std::string& title, int argc, char* argv[]) = 0;
+    virtual void Finalize() = 0;
+  };
+
+}
--- a/Applications/Qt/BasicQtApplication.cpp	Tue Aug 28 11:09:37 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,68 +0,0 @@
-/**
- * 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/>.
- **/
-
-
-#if ORTHANC_ENABLE_QT != 1
-#error this file shall be included only with the ORTHANC_ENABLE_QT set to 1
-#endif
-
-#include "BasicQtApplication.h"
-#include <boost/program_options.hpp>
-#include <QApplication>
-
-#include "../../Framework/Toolbox/MessagingToolbox.h"
-
-#include <Core/Logging.h>
-#include <Core/HttpClient.h>
-#include <Core/Toolbox.h>
-#include <Plugins/Samples/Common/OrthancHttpConnection.h>
-#include "../../Platforms/Generic/OracleWebService.h"
-#include "../../Applications/Samples/Qt/MainWindow.h"
-
-
-namespace OrthancStone
-{
-  void BasicQtApplication::Initialize()
-  {
-  }
-
-  void BasicQtApplication::DeclareCommandLineOptions(boost::program_options::options_description& options)
-  {
-  }
-
-  void BasicQtApplication::Run(BasicNativeApplicationContext& context, const std::string& title, int argc, char* argv[])
-  {
-    context.Start();
-
-    QApplication app(argc, argv);
-    MainWindow window(context);
-
-    window.show();
-    app.exec();
-
-    context.Stop();
-  }
-
-  void BasicQtApplication::Finalize()
-  {
-  }
-
-
-}
--- a/Applications/Qt/BasicQtApplication.h	Tue Aug 28 11:09:37 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,42 +0,0 @@
-/**
- * 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 "../Generic/BasicNativeApplication.h"
-
-#if ORTHANC_ENABLE_QT != 1
-#error this file shall be included only with the ORTHANC_ENABLE_QT set to 1
-#endif
-
-namespace OrthancStone
-{
-  class BasicQtApplication : public BasicNativeApplication
-  {
-  public:
-    virtual void Initialize();
-    virtual void DeclareCommandLineOptions(boost::program_options::options_description& options);
-    virtual void ParseCommandLineOptions(const boost::program_options::variables_map& parameters) {}
-    virtual void Run(BasicNativeApplicationContext& context, const std::string& title, int argc, char* argv[]);
-    virtual void Finalize();
-  };
-
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Applications/Qt/BasicQtApplicationRunner.cpp	Tue Aug 28 15:26:46 2018 +0200
@@ -0,0 +1,67 @@
+/**
+ * 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/>.
+ **/
+
+
+#if ORTHANC_ENABLE_QT != 1
+#error this file shall be included only with the ORTHANC_ENABLE_QT set to 1
+#endif
+
+#include "BasicQtApplicationRunner.h"
+#include <boost/program_options.hpp>
+#include <QApplication>
+
+#include "../../Framework/Toolbox/MessagingToolbox.h"
+
+#include <Core/Logging.h>
+#include <Core/HttpClient.h>
+#include <Core/Toolbox.h>
+#include <Plugins/Samples/Common/OrthancHttpConnection.h>
+#include "../../Platforms/Generic/OracleWebService.h"
+
+
+namespace OrthancStone
+{
+  void BasicQtApplicationRunner::Initialize()
+  {
+  }
+
+  void BasicQtApplicationRunner::DeclareCommandLineOptions(boost::program_options::options_description& options)
+  {
+  }
+
+  void BasicQtApplicationRunner::Run(BasicNativeApplicationContext& context, const std::string& title, int argc, char* argv[])
+  {
+    context.Start();
+
+    QApplication app(argc, argv);
+    InitializeMainWindow(context);
+
+    window_->show();
+    app.exec();
+
+    context.Stop();
+  }
+
+  void BasicQtApplicationRunner::Finalize()
+  {
+  }
+
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Applications/Qt/BasicQtApplicationRunner.h	Tue Aug 28 15:26:46 2018 +0200
@@ -0,0 +1,55 @@
+/**
+ * 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 "../Generic/BasicNativeApplicationRunner.h"
+#include "QStoneMainWindow.h"
+
+#if ORTHANC_ENABLE_QT != 1
+#error this file shall be included only with the ORTHANC_ENABLE_QT set to 1
+#endif
+
+namespace OrthancStone
+{
+  class BasicQtApplicationRunner : public BasicNativeApplicationRunner
+  {
+  protected:
+    std::auto_ptr<QStoneMainWindow> window_;
+
+    virtual void InitializeMainWindow(BasicNativeApplicationContext& context) = 0;
+  public:
+    BasicQtApplicationRunner(MessageBroker& broker,
+                             IBasicApplication& application)
+      : BasicNativeApplicationRunner(broker, application)
+    {
+    }
+
+
+    virtual void Initialize();
+
+    virtual void DeclareCommandLineOptions(boost::program_options::options_description& options);
+    virtual void ParseCommandLineOptions(const boost::program_options::variables_map& parameters) {}
+    virtual void Run(BasicNativeApplicationContext& context, const std::string& title, int argc, char* argv[]);
+    virtual void Finalize();
+  };
+
+}
--- a/Applications/Qt/QStoneMainWindow.cpp	Tue Aug 28 11:09:37 2018 +0200
+++ b/Applications/Qt/QStoneMainWindow.cpp	Tue Aug 28 15:26:46 2018 +0200
@@ -20,20 +20,22 @@
 
 #include "QStoneMainWindow.h"
 
-QStoneMainWindow::QStoneMainWindow(OrthancStone::BasicNativeApplicationContext& context, QWidget *parent) :
-  QMainWindow(parent),
-  context_(context)
-{
-}
-
-void QStoneMainWindow::SetCentralStoneWidget(QCairoWidget *centralWidget)
+namespace OrthancStone
 {
-  cairoCentralWidget_ = centralWidget;
-  cairoCentralWidget_->SetContext(context_);
-}
+
+  QStoneMainWindow::QStoneMainWindow(BasicNativeApplicationContext& context, QWidget *parent) :
+    QMainWindow(parent),
+    context_(context)
+  {
+  }
 
-QStoneMainWindow::~QStoneMainWindow()
-{
+  void QStoneMainWindow::SetCentralStoneWidget(QCairoWidget *centralWidget)
+  {
+    cairoCentralWidget_ = centralWidget;
+    cairoCentralWidget_->SetContext(context_);
+  }
+
+  QStoneMainWindow::~QStoneMainWindow()
+  {
+  }
 }
-
-
--- a/Applications/Qt/QStoneMainWindow.h	Tue Aug 28 11:09:37 2018 +0200
+++ b/Applications/Qt/QStoneMainWindow.h	Tue Aug 28 15:26:46 2018 +0200
@@ -24,19 +24,22 @@
 #include "QCairoWidget.h"
 #include "../Generic/BasicNativeApplicationContext.h"
 
-class QStoneMainWindow : public QMainWindow
+namespace OrthancStone
 {
-  Q_OBJECT
+  class QStoneMainWindow : public QMainWindow
+  {
+    Q_OBJECT
 
-private:
-  OrthancStone::BasicNativeApplicationContext& context_;
-  QCairoWidget          *cairoCentralWidget_;
+  private:
+    OrthancStone::BasicNativeApplicationContext& context_;
+    QCairoWidget          *cairoCentralWidget_;
 
-protected:  // you must inherit this class
-  QStoneMainWindow(OrthancStone::BasicNativeApplicationContext& context, QWidget *parent = 0);
-  void SetCentralStoneWidget(QCairoWidget* centralWidget);
-public:
-  virtual ~QStoneMainWindow();
+  protected:  // you must inherit this class
+    QStoneMainWindow(BasicNativeApplicationContext& context, QWidget *parent = 0);
+    void SetCentralStoneWidget(QCairoWidget* centralWidget);
+  public:
+    virtual ~QStoneMainWindow();
 
-};
+  };
 
+}
--- a/Applications/Samples/Qt/MainWindow.cpp	Tue Aug 28 11:09:37 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,42 +0,0 @@
-/**
- * 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 "MainWindow.h"
-
-/**
- * Don't use "ui_MainWindow.h" instead of <ui_MainWindow.h> below, as
- * this makes CMake unable to detect when the UI file changes.
- **/
-#include <ui_MainWindow.h>
-
-MainWindow::MainWindow(OrthancStone::BasicNativeApplicationContext& context, QWidget *parent) :
-  QStoneMainWindow(context, parent),
-  ui_(new Ui::MainWindow)
-{
-  ui_->setupUi(this);
-  SetCentralStoneWidget(ui_->cairoCentralWidget);
-}
-
-MainWindow::~MainWindow()
-{
-  delete ui_;
-}
-
-
--- a/Applications/Samples/Qt/MainWindow.h	Tue Aug 28 11:09:37 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,41 +0,0 @@
-/**
- * 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 "../../Qt/QCairoWidget.h"
-#include "../../Qt/QStoneMainWindow.h"
-
-namespace Ui 
-{
-  class MainWindow;
-}
-
-
-class MainWindow : public QStoneMainWindow
-{
-  Q_OBJECT
-
-private:
-  Ui::MainWindow        *ui_;
-
-public:
-  explicit MainWindow(OrthancStone::BasicNativeApplicationContext& context, QWidget *parent = 0);
-  ~MainWindow();
-};
--- a/Applications/Samples/Qt/MainWindow.ui	Tue Aug 28 11:09:37 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,65 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ui version="4.0">
- <class>MainWindow</class>
- <widget class="QMainWindow" name="MainWindow">
-  <property name="geometry">
-   <rect>
-    <x>0</x>
-    <y>0</y>
-    <width>800</width>
-    <height>600</height>
-   </rect>
-  </property>
-  <property name="windowTitle">
-   <string>Stone of Orthanc</string>
-  </property>
-  <property name="layoutDirection">
-   <enum>Qt::LeftToRight</enum>
-  </property>
-  <widget class="QWidget" name="centralwidget">
-   <property name="sizePolicy">
-    <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
-     <horstretch>0</horstretch>
-     <verstretch>0</verstretch>
-    </sizepolicy>
-   </property>
-   <property name="layoutDirection">
-    <enum>Qt::LeftToRight</enum>
-   </property>
-   <layout class="QVBoxLayout" name="verticalLayout_2" stretch="0">
-    <property name="sizeConstraint">
-     <enum>QLayout::SetDefaultConstraint</enum>
-    </property>
-    <item>
-     <widget class="QCairoWidget" name="cairoCentralWidget"/>
-    </item>
-   </layout>
-  </widget>
-  <widget class="QMenuBar" name="menubar">
-   <property name="geometry">
-    <rect>
-     <x>0</x>
-     <y>0</y>
-     <width>800</width>
-     <height>25</height>
-    </rect>
-   </property>
-   <widget class="QMenu" name="menuTest">
-    <property name="title">
-     <string>Test</string>
-    </property>
-   </widget>
-   <addaction name="menuTest"/>
-  </widget>
-  <widget class="QStatusBar" name="statusbar"/>
- </widget>
- <customwidgets>
-  <customwidget>
-   <class>QCairoWidget</class>
-   <extends>QGraphicsView</extends>
-   <header location="global">QCairoWidget.h</header>
-  </customwidget>
- </customwidgets>
- <resources/>
- <connections/>
-</ui>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Applications/Samples/Qt/SampleMainWindow.cpp	Tue Aug 28 15:26:46 2018 +0200
@@ -0,0 +1,75 @@
+/**
+ * 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 "SampleMainWindow.h"
+
+/**
+ * Don't use "ui_MainWindow.h" instead of <ui_MainWindow.h> below, as
+ * this makes CMake unable to detect when the UI file changes.
+ **/
+#include <ui_SampleMainWindow.h>
+#include "../../Applications/Samples/SampleApplicationBase.h"
+
+namespace OrthancStone
+{
+  namespace Samples
+  {
+
+    SampleMainWindow::SampleMainWindow(OrthancStone::BasicNativeApplicationContext& context, OrthancStone::Samples::SampleApplicationBase& stoneSampleApplication, QWidget *parent) :
+      QStoneMainWindow(context, parent),
+      ui_(new Ui::SampleMainWindow),
+      stoneSampleApplication_(stoneSampleApplication)
+    {
+      ui_->setupUi(this);
+      SetCentralStoneWidget(ui_->cairoCentralWidget);
+
+      connect(ui_->toolButton1, &QToolButton::clicked, this, &SampleMainWindow::tool1Clicked);
+      connect(ui_->toolButton2, &QToolButton::clicked, this, &SampleMainWindow::tool2Clicked);
+      connect(ui_->pushButton1, &QPushButton::clicked, this, &SampleMainWindow::pushButton1Clicked);
+      connect(ui_->pushButton1, &QPushButton::clicked, this, &SampleMainWindow::pushButton2Clicked);
+    }
+
+    SampleMainWindow::~SampleMainWindow()
+    {
+      delete ui_;
+    }
+
+    void SampleMainWindow::tool1Clicked()
+    {
+      stoneSampleApplication_.OnTool1Clicked();
+    }
+
+    void SampleMainWindow::tool2Clicked()
+    {
+      stoneSampleApplication_.OnTool2Clicked();
+    }
+
+    void SampleMainWindow::pushButton1Clicked()
+    {
+      stoneSampleApplication_.OnPushButton1Clicked();
+    }
+
+    void SampleMainWindow::pushButton2Clicked()
+    {
+      stoneSampleApplication_.OnPushButton2Clicked();
+    }
+
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Applications/Samples/Qt/SampleMainWindow.h	Tue Aug 28 15:26:46 2018 +0200
@@ -0,0 +1,56 @@
+/**
+ * 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 "../../Qt/QCairoWidget.h"
+#include "../../Qt/QStoneMainWindow.h"
+
+namespace Ui 
+{
+  class SampleMainWindow;
+}
+
+namespace OrthancStone
+{
+  namespace Samples
+  {
+
+    class SampleApplicationBase;
+
+    class SampleMainWindow : public QStoneMainWindow
+    {
+      Q_OBJECT
+
+    private:
+      Ui::SampleMainWindow*   ui_;
+      SampleApplicationBase&  stoneSampleApplication_;
+
+    public:
+      explicit SampleMainWindow(OrthancStone::BasicNativeApplicationContext& context, SampleApplicationBase& stoneSampleApplication, QWidget *parent = 0);
+      ~SampleMainWindow();
+
+    private slots:
+      void tool1Clicked();
+      void tool2Clicked();
+      void pushButton1Clicked();
+      void pushButton2Clicked();
+    };
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Applications/Samples/Qt/SampleMainWindow.ui	Tue Aug 28 15:26:46 2018 +0200
@@ -0,0 +1,130 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>SampleMainWindow</class>
+ <widget class="QMainWindow" name="SampleMainWindow">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>903</width>
+    <height>634</height>
+   </rect>
+  </property>
+  <property name="minimumSize">
+   <size>
+    <width>500</width>
+    <height>300</height>
+   </size>
+  </property>
+  <property name="baseSize">
+   <size>
+    <width>500</width>
+    <height>300</height>
+   </size>
+  </property>
+  <property name="windowTitle">
+   <string>Stone of Orthanc</string>
+  </property>
+  <property name="layoutDirection">
+   <enum>Qt::LeftToRight</enum>
+  </property>
+  <widget class="QWidget" name="centralwidget">
+   <property name="sizePolicy">
+    <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
+     <horstretch>0</horstretch>
+     <verstretch>0</verstretch>
+    </sizepolicy>
+   </property>
+   <property name="layoutDirection">
+    <enum>Qt::LeftToRight</enum>
+   </property>
+   <layout class="QVBoxLayout" name="verticalLayout_2" stretch="0,0">
+    <property name="sizeConstraint">
+     <enum>QLayout::SetDefaultConstraint</enum>
+    </property>
+    <item>
+     <widget class="QCairoWidget" name="cairoCentralWidget">
+      <property name="minimumSize">
+       <size>
+        <width>0</width>
+        <height>500</height>
+       </size>
+      </property>
+     </widget>
+    </item>
+    <item>
+     <widget class="QGroupBox" name="horizontalGroupBox">
+      <property name="minimumSize">
+       <size>
+        <width>0</width>
+        <height>100</height>
+       </size>
+      </property>
+      <property name="maximumSize">
+       <size>
+        <width>16777215</width>
+        <height>100</height>
+       </size>
+      </property>
+      <layout class="QHBoxLayout" name="horizontalLayout">
+       <item>
+        <widget class="QToolButton" name="toolButton1">
+         <property name="text">
+          <string>tool1</string>
+         </property>
+        </widget>
+       </item>
+       <item>
+        <widget class="QToolButton" name="toolButton2">
+         <property name="text">
+          <string>tool2</string>
+         </property>
+        </widget>
+       </item>
+       <item>
+        <widget class="QPushButton" name="pushButton1">
+         <property name="text">
+          <string>action1</string>
+         </property>
+        </widget>
+       </item>
+       <item>
+        <widget class="QPushButton" name="pushButton2">
+         <property name="text">
+          <string>action2</string>
+         </property>
+        </widget>
+       </item>
+      </layout>
+     </widget>
+    </item>
+   </layout>
+  </widget>
+  <widget class="QMenuBar" name="menubar">
+   <property name="geometry">
+    <rect>
+     <x>0</x>
+     <y>0</y>
+     <width>903</width>
+     <height>22</height>
+    </rect>
+   </property>
+   <widget class="QMenu" name="menuTest">
+    <property name="title">
+     <string>Test</string>
+    </property>
+   </widget>
+   <addaction name="menuTest"/>
+  </widget>
+  <widget class="QStatusBar" name="statusbar"/>
+ </widget>
+ <customwidgets>
+  <customwidget>
+   <class>QCairoWidget</class>
+   <extends>QGraphicsView</extends>
+   <header location="global">QCairoWidget.h</header>
+  </customwidget>
+ </customwidgets>
+ <resources/>
+ <connections/>
+</ui>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Applications/Samples/Qt/SampleQtApplicationRunner.h	Tue Aug 28 15:26:46 2018 +0200
@@ -0,0 +1,51 @@
+/**
+ * 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 "../../Qt/BasicQtApplicationRunner.h"
+#include "SampleMainWindow.h"
+
+#if ORTHANC_ENABLE_QT != 1
+#error this file shall be included only with the ORTHANC_ENABLE_QT set to 1
+#endif
+
+namespace OrthancStone
+{
+  namespace Samples
+  {
+    class SampleQtApplicationRunner : public OrthancStone::BasicQtApplicationRunner
+    {
+    protected:
+      virtual void InitializeMainWindow(OrthancStone::BasicNativeApplicationContext& context)
+      {
+        window_.reset(new SampleMainWindow(context, dynamic_cast<OrthancStone::Samples::SampleApplicationBase&>(application_)));
+      }
+    public:
+      SampleQtApplicationRunner(MessageBroker& broker,
+                                SampleApplicationBase& application)
+        : OrthancStone::BasicQtApplicationRunner(broker, application)
+      {
+      }
+
+    };
+  }
+}
--- a/Applications/Samples/SampleApplicationBase.h	Tue Aug 28 11:09:37 2018 +0200
+++ b/Applications/Samples/SampleApplicationBase.h	Tue Aug 28 15:26:46 2018 +0200
@@ -22,7 +22,6 @@
 #pragma once
 
 #include "../../Applications/IBasicApplication.h"
-#include "../../Framework/Viewport/WidgetViewport.h"
 
 namespace OrthancStone
 {
@@ -31,12 +30,34 @@
     class SampleApplicationBase : public IBasicApplication
     {
     public:
+      virtual void Initialize(BasicApplicationContext* context,
+                              IStatusBar& statusBar,
+                              const boost::program_options::variables_map& parameters)
+      {
+    }
+
+
+
       virtual std::string GetTitle() const
       {
         return "Stone of Orthanc - Sample";
       }
 
-      virtual void CustomInitialize() {}
+      virtual void OnPushButton1Clicked() {}
+      virtual void OnPushButton2Clicked() {}
+      virtual void OnTool1Clicked() {}
+      virtual void OnTool2Clicked() {}
+
+      virtual void GetButtonNames(std::string& pushButton1, 
+      std::string& pushButton2, 
+      std::string& tool1, 
+      std::string& tool2
+      ) {
+        pushButton1 = "action1";
+        pushButton2 = "action2";
+        tool1 = "tool1";
+        tool2 = "tool2";
+      }
 
     };
   }
--- a/Applications/Samples/SampleList.h	Tue Aug 28 11:09:37 2018 +0200
+++ b/Applications/Samples/SampleList.h	Tue Aug 28 15:26:46 2018 +0200
@@ -2,35 +2,35 @@
 
 #if ORTHANC_STONE_SAMPLE == 1
 #include "EmptyApplication.h"
-typedef OrthancStone::Samples::EmptyApplication Application;
+typedef OrthancStone::Samples::EmptyApplication SampleApplication;
 
 #elif ORTHANC_STONE_SAMPLE == 2
 #include "TestPatternApplication.h"
-typedef OrthancStone::Samples::TestPatternApplication Application;
+typedef OrthancStone::Samples::TestPatternApplication SampleApplication;
 
 #elif ORTHANC_STONE_SAMPLE == 3
 #include "SingleFrameApplication.h"
-typedef OrthancStone::Samples::SingleFrameApplication Application;
+typedef OrthancStone::Samples::SingleFrameApplication SampleApplication;
 
 #elif ORTHANC_STONE_SAMPLE == 4
 #include "SingleVolumeApplication.h"
-typedef OrthancStone::Samples::SingleVolumeApplication Application;
+typedef OrthancStone::Samples::SingleVolumeApplication SampleApplication;
 
 #elif ORTHANC_STONE_SAMPLE == 5
 #include "BasicPetCtFusionApplication.h"
-typedef OrthancStone::Samples::BasicPetCtFusionApplication Application;
+typedef OrthancStone::Samples::BasicPetCtFusionApplication SampleApplication;
 
 #elif ORTHANC_STONE_SAMPLE == 6
 #include "SynchronizedSeriesApplication.h"
-typedef OrthancStone::Samples::SynchronizedSeriesApplication Application;
+typedef OrthancStone::Samples::SynchronizedSeriesApplication SampleApplication;
 
 #elif ORTHANC_STONE_SAMPLE == 7
 #include "LayoutPetCtFusionApplication.h"
-typedef OrthancStone::Samples::LayoutPetCtFusionApplication Application;
+typedef OrthancStone::Samples::LayoutPetCtFusionApplication SampleApplication;
 
 #elif ORTHANC_STONE_SAMPLE == 8
 #include "SimpleViewerApplication.h"
-typedef OrthancStone::Samples::SimpleViewerApplication Application;
+typedef OrthancStone::Samples::SimpleViewerApplication SampleApplication;
 
 #else
 #error Please set the ORTHANC_STONE_SAMPLE macro
--- a/Applications/Samples/SampleMainNative.cpp	Tue Aug 28 11:09:37 2018 +0200
+++ b/Applications/Samples/SampleMainNative.cpp	Tue Aug 28 15:26:46 2018 +0200
@@ -24,21 +24,21 @@
 #include "../Sdl/BasicSdlApplication.h"
 #endif
 #if ORTHANC_ENABLE_QT==1
-#include "../Qt/BasicQtApplication.h"
+#include "Qt/SampleQtApplicationRunner.h"
 #endif
 #include "../../Framework/Messages/MessageBroker.h"
 
 int main(int argc, char* argv[]) 
 {
   OrthancStone::MessageBroker broker;
-  Application application(broker);
+  SampleApplication sampleStoneApplication(broker);
 
 #if ORTHANC_ENABLE_SDL==1
   OrthancStone::BasicSdlApplication sdlApplication;
-  return sdlApplication.Execute(broker, application, argc, argv);
+  return sdlApplication.Execute(broker, sampleStoneApplication, argc, argv);
 #endif
 #if ORTHANC_ENABLE_QT==1
-  OrthancStone::BasicQtApplication qtApplication;
-  return qtApplication.Execute(broker, application, argc, argv);
+  OrthancStone::Samples::SampleQtApplicationRunner qtAppRunner(broker, sampleStoneApplication);
+  return qtAppRunner.Execute(argc, argv);
 #endif
 }
--- a/Applications/Samples/SampleMainWasm.cpp	Tue Aug 28 11:09:37 2018 +0200
+++ b/Applications/Samples/SampleMainWasm.cpp	Tue Aug 28 15:26:46 2018 +0200
@@ -28,5 +28,5 @@
 
 OrthancStone::IBasicApplication* CreateUserApplication(OrthancStone::MessageBroker& broker) {
   
-  return new Application(broker);
+  return new SampleApplication(broker);
 }
\ No newline at end of file
--- a/Applications/Samples/SimpleViewerApplication.h	Tue Aug 28 11:09:37 2018 +0200
+++ b/Applications/Samples/SimpleViewerApplication.h	Tue Aug 28 15:26:46 2018 +0200
@@ -24,6 +24,7 @@
 #include "SampleApplicationBase.h"
 
 #include "../../Framework/Layers/OrthancFrameLayerSource.h"
+#include "../../Framework/Layers/CircleMeasureTracker.h"
 #include "../../Framework/Layers/LineMeasureTracker.h"
 #include "../../Framework/Widgets/LayerWidget.h"
 #include "../../Framework/Widgets/LayoutWidget.h"
@@ -110,7 +111,14 @@
         {
           if (button == MouseButton_Left)
           {
-            return new LineMeasureTracker(statusBar, dynamic_cast<LayerWidget&>(widget).GetSlice(), x, y, 255, 0, 0, 10);
+            if (application_.currentTool_ == Tools_LineMeasure)
+            {
+              return new LineMeasureTracker(statusBar, dynamic_cast<LayerWidget&>(widget).GetSlice(), x, y, 255, 0, 0, 10);
+            }
+            else if (application_.currentTool_ == Tools_CircleMeasure)
+            {
+              return new CircleMeasureTracker(statusBar, dynamic_cast<LayerWidget&>(widget).GetSlice(), x, y, 255, 0, 0, 10);
+            }
           }
           return NULL;
         }
@@ -138,21 +146,6 @@
                                 KeyboardModifiers modifiers,
                                 IStatusBar* statusBar)
         {
-          //          int scale = (modifiers & KeyboardModifiers_Control ? 10 : 1);
-          
-          //          switch (direction)
-          //          {
-          //            case MouseWheelDirection_Up:
-          //              application_.OffsetSlice(-scale);
-          //              break;
-
-          //            case MouseWheelDirection_Down:
-          //              application_.OffsetSlice(scale);
-          //              break;
-
-          //            default:
-          //              break;
-          //          }
         }
 
         virtual void KeyPressed(WorldSceneWidget& widget,
@@ -172,7 +165,12 @@
         }
       };
 
+      enum Tools {
+        Tools_LineMeasure,
+        Tools_CircleMeasure
+      };
 
+      Tools                           currentTool_;
       std::unique_ptr<MainWidgetInteractor> mainWidgetInteractor_;
       std::unique_ptr<ThumbnailInteractor>  thumbnailInteractor_;
       LayoutWidget*                   mainLayout_;
@@ -186,18 +184,17 @@
       OrthancStone::WidgetViewport*   wasmViewport2_;
 
       IStatusBar*                     statusBar_;
-      unsigned int                    slice_;
       std::unique_ptr<SmartLoader>    smartLoader_;
       std::unique_ptr<OrthancApiClient>      orthancApiClient_;
 
     public:
       SimpleViewerApplication(MessageBroker& broker) :
         IObserver(broker),
+        currentTool_(Tools_LineMeasure),
         mainLayout_(NULL),
         currentInstanceIndex_(0),
         wasmViewport1_(NULL),
-        wasmViewport2_(NULL),
-        slice_(0)
+        wasmViewport2_(NULL)
       {
         DeclareIgnoredMessage(MessageType_Widget_ContentChanged);
         DeclareHandledMessage(MessageType_Widget_GeometryChanged);
@@ -313,7 +310,7 @@
           // if this is the first thumbnail loaded, load the first instance in the mainWidget
           if (mainWidget_->GetLayerCount() == 0)
           {
-              mainWidget_->AddLayer(smartLoader_->GetFrame(instancesIdsPerSeriesId_[seriesId][0], 0));
+            mainWidget_->AddLayer(smartLoader_->GetFrame(instancesIdsPerSeriesId_[seriesId][0], 0));
           }
         }
       }
@@ -362,10 +359,28 @@
       }
 #endif
 
+
+
       void SelectSeriesInMainViewport(const std::string& seriesId)
       {
         mainWidget_->ReplaceLayer(0, smartLoader_->GetFrame(instancesIdsPerSeriesId_[seriesId][0], 0));
       }
+
+      virtual void OnPushButton1Clicked() {}
+      virtual void OnPushButton2Clicked() {}
+      virtual void OnTool1Clicked() { currentTool_ = Tools_LineMeasure;}
+      virtual void OnTool2Clicked() { currentTool_ = Tools_CircleMeasure;}
+
+      virtual void GetButtonNames(std::string& pushButton1,
+                                  std::string& pushButton2,
+                                  std::string& tool1,
+                                  std::string& tool2
+                                  ) {
+        tool1 = "line";
+        tool2 = "circle";
+        pushButton1 = "action1";
+        pushButton2 = "action2";
+      }
     };
 
 
--- a/Applications/Samples/Web/index.html	Tue Aug 28 11:09:37 2018 +0200
+++ b/Applications/Samples/Web/index.html	Tue Aug 28 15:26:46 2018 +0200
@@ -14,7 +14,7 @@
 
 <body>
     <ul>
-        <li><a href="simple-viewer.html?instance1=XXXX&instance2=YYYY">Simple Viewer</a></li>
+        <li><a href="simple-viewer.html">Simple Viewer</a></li>
     </ul>
 </body>
 
--- a/Applications/Samples/Web/simple-viewer.html	Tue Aug 28 11:09:37 2018 +0200
+++ b/Applications/Samples/Web/simple-viewer.html	Tue Aug 28 15:26:46 2018 +0200
@@ -17,6 +17,12 @@
     <canvas id="canvas" data-width-ratio="20" data-height-ratio="50"></canvas>
     <canvas id="canvas2" data-width-ratio="70" data-height-ratio="50"></canvas>
   </div>
+  <div>
+    <button id="tool1">tool1</button>
+    <button id="tool2">tool2</button>
+    <button id="pushBouton1">action1</button>
+    <button id="pushBouton2">action2</button>
+  </div>
   <script type="text/javascript" src="app-simple-viewer.js"></script>
 </body>
 
--- a/Applications/Samples/Web/tsconfig-simple-viewer.json	Tue Aug 28 11:09:37 2018 +0200
+++ b/Applications/Samples/Web/tsconfig-simple-viewer.json	Tue Aug 28 15:26:46 2018 +0200
@@ -4,6 +4,7 @@
         "outFile": "../../../Platforms/Wasm/build-web/app-simple-viewer.js"
     },
     "include" : [
-        "simple-viewer.ts"
+        "simple-viewer.ts",
+        "common-samples.ts"
     ]
 }
\ No newline at end of file
--- a/Framework/SmartLoader.cpp	Tue Aug 28 11:09:37 2018 +0200
+++ b/Framework/SmartLoader.cpp	Tue Aug 28 15:26:46 2018 +0200
@@ -21,7 +21,6 @@
 
 #include "SmartLoader.h"
 #include "Layers/OrthancFrameLayerSource.h"
-#include "Layers/OrthancFrameLayer.h"
 
 namespace OrthancStone
 {
--- a/Platforms/Generic/CMakeLists.txt	Tue Aug 28 11:09:37 2018 +0200
+++ b/Platforms/Generic/CMakeLists.txt	Tue Aug 28 15:26:46 2018 +0200
@@ -49,12 +49,13 @@
 
 if (ENABLE_QT)
   list(APPEND APPLICATIONS_SOURCES
-    ${ORTHANC_STONE_ROOT}/Applications/Samples/Qt/MainWindow.cpp
-    ${ORTHANC_STONE_ROOT}/Applications/Samples/Qt/MainWindow.ui
+    ${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(BuildSample Target Header Sample)
+macro(BuildSingeFileSample Target Header Sample)
   add_executable(${Target}
     ${ORTHANC_STONE_ROOT}/Applications/Samples/SampleMainNative.cpp
     ${ORTHANC_STONE_ROOT}/Applications/Samples/SampleInteractor.h
@@ -76,7 +77,7 @@
 ##BuildSample(OrthancStoneBasicPetCtFusion 5)
 ##BuildSample(OrthancStoneSynchronizedSeries 6)
 ##BuildSample(OrthancStoneLayoutPetCtFusion 7)
-BuildSample(OrthancStoneSimpleViewer SimpleViewerApplication.h 8)
+BuildSingeFileSample(OrthancStoneSimpleViewer SimpleViewerApplication.h 8)
 
 
 #####################################################################
--- a/Resources/CMake/OrthancStoneConfiguration.cmake	Tue Aug 28 11:09:37 2018 +0200
+++ b/Resources/CMake/OrthancStoneConfiguration.cmake	Tue Aug 28 15:26:46 2018 +0200
@@ -177,7 +177,7 @@
 
   if (ENABLE_SDL OR ENABLE_QT)
     list(APPEND APPLICATIONS_SOURCES
-      ${ORTHANC_STONE_ROOT}/Applications/Generic/BasicNativeApplication.cpp
+      ${ORTHANC_STONE_ROOT}/Applications/Generic/BasicNativeApplicationRunner.cpp
       ${ORTHANC_STONE_ROOT}/Applications/Generic/BasicNativeApplicationContext.cpp
       )
     if (ENABLE_SDL)
@@ -217,7 +217,6 @@
   ${ORTHANC_STONE_ROOT}/Framework/Layers/LayerSourceBase.cpp
   ${ORTHANC_STONE_ROOT}/Framework/Layers/LineLayerRenderer.cpp
   ${ORTHANC_STONE_ROOT}/Framework/Layers/LineMeasureTracker.cpp
-  ${ORTHANC_STONE_ROOT}/Framework/Layers/OrthancFrameLayer.h
   ${ORTHANC_STONE_ROOT}/Framework/Layers/OrthancFrameLayerSource.cpp
   ${ORTHANC_STONE_ROOT}/Framework/Layers/RenderStyle.cpp
   ${ORTHANC_STONE_ROOT}/Framework/Layers/SliceOutlineRenderer.cpp
--- a/Resources/CMake/QtConfiguration.cmake	Tue Aug 28 11:09:37 2018 +0200
+++ b/Resources/CMake/QtConfiguration.cmake	Tue Aug 28 15:26:46 2018 +0200
@@ -28,7 +28,7 @@
 
 list(APPEND QT_SOURCES
     ${ORTHANC_STONE_ROOT}/Applications/Qt/QCairoWidget.cpp
-    ${ORTHANC_STONE_ROOT}/Applications/Qt/BasicQtApplication.cpp
+    ${ORTHANC_STONE_ROOT}/Applications/Qt/BasicQtApplicationRunner.cpp
     ${ORTHANC_STONE_ROOT}/Applications/Qt/QStoneMainWindow.cpp
 )
 
--- a/TODO	Tue Aug 28 11:09:37 2018 +0200
+++ b/TODO	Tue Aug 28 15:26:46 2018 +0200
@@ -14,6 +14,11 @@
   WorldSceneWidet shall not create Pan/ZoomMouseTracker when the Interactor does not create one
 * Update SimpleViewer sample to have 2 buttons to select the measure tracker
 
+Bugs
+----
+* LineMeasureTracker rendering generates "memory access out of bounds" in WASM
+
+
 ---------------------------------
 Radiotherapy and nuclear medicine
 ---------------------------------