# HG changeset patch
# User am@osimis.io
# Date 1535640968 -7200
# Node ID 36ebe6ec8fe833f97e449f61ce0ad55829990486
# Parent 8c8da145fefa2eebd36e504dae145429fc7ff8b1# Parent 3a8bac80535263e6fd840ff5d34babd0f5a9e45a
merged default into am-2
diff -r 3a8bac805352 -r 36ebe6ec8fe8 .hgignore
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/.hgignore Thu Aug 30 16:56:08 2018 +0200
@@ -0,0 +1,7 @@
+Platforms/Generic/CMakeLists.txt.user
+Platforms/Generic/ThirdPartyDownloads/
+Platforms/Wasm/CMakeLists.txt.user
+Platforms/Wasm/build/
+Platforms/Wasm/build-web/
+Platforms/Wasm/ThirdPartyDownloads/
+Applications/Qt/archive/
diff -r 3a8bac805352 -r 36ebe6ec8fe8 Applications/BasicApplicationContext.cpp
--- a/Applications/BasicApplicationContext.cpp Tue Aug 28 21:00:35 2018 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,144 +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 .
- **/
-
-
-#include "BasicApplicationContext.h"
-
-namespace OrthancStone
-{
- void BasicApplicationContext::UpdateThread(BasicApplicationContext* that)
- {
- while (!that->stopped_)
- {
- {
- ViewportLocker locker(*that);
- locker.GetViewport().UpdateContent();
- }
-
- boost::this_thread::sleep(boost::posix_time::milliseconds(that->updateDelay_));
- }
- }
-
-
- BasicApplicationContext::BasicApplicationContext(Orthanc::WebServiceParameters& orthanc) :
- oracle_(viewportMutex_, 4), // Use 4 threads to download
- //oracle_(viewportMutex_, 1), // Disable threading to be reproducible
- webService_(oracle_, orthanc),
- stopped_(true),
- updateDelay_(100) // By default, 100ms between each refresh of the content
- {
- srand(time(NULL));
- }
-
-
- BasicApplicationContext::~BasicApplicationContext()
- {
- for (Interactors::iterator it = interactors_.begin(); it != interactors_.end(); ++it)
- {
- assert(*it != NULL);
- delete *it;
- }
-
- for (SlicedVolumes::iterator it = slicedVolumes_.begin(); it != slicedVolumes_.end(); ++it)
- {
- assert(*it != NULL);
- delete *it;
- }
-
- for (VolumeLoaders::iterator it = volumeLoaders_.begin(); it != volumeLoaders_.end(); ++it)
- {
- assert(*it != NULL);
- delete *it;
- }
- }
-
-
- IWidget& BasicApplicationContext::SetCentralWidget(IWidget* widget) // Takes ownership
- {
- viewport_.SetCentralWidget(widget);
- return *widget;
- }
-
-
- ISlicedVolume& BasicApplicationContext::AddSlicedVolume(ISlicedVolume* volume)
- {
- if (volume == NULL)
- {
- throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer);
- }
- else
- {
- slicedVolumes_.push_back(volume);
- return *volume;
- }
- }
-
-
- IVolumeLoader& BasicApplicationContext::AddVolumeLoader(IVolumeLoader* loader)
- {
- if (loader == NULL)
- {
- throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer);
- }
- else
- {
- volumeLoaders_.push_back(loader);
- return *loader;
- }
- }
-
-
- IWorldSceneInteractor& BasicApplicationContext::AddInteractor(IWorldSceneInteractor* interactor)
- {
- if (interactor == NULL)
- {
- throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer);
- }
-
- interactors_.push_back(interactor);
-
- return *interactor;
- }
-
-
- void BasicApplicationContext::Start()
- {
- oracle_.Start();
-
- if (viewport_.HasUpdateContent())
- {
- stopped_ = false;
- updateThread_ = boost::thread(UpdateThread, this);
- }
- }
-
-
- void BasicApplicationContext::Stop()
- {
- stopped_ = true;
-
- if (updateThread_.joinable())
- {
- updateThread_.join();
- }
-
- oracle_.Stop();
- }
-}
diff -r 3a8bac805352 -r 36ebe6ec8fe8 Applications/BasicApplicationContext.h
--- a/Applications/BasicApplicationContext.h Tue Aug 28 21:00:35 2018 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,102 +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 .
- **/
-
-
-#pragma once
-
-#include "../Framework/Viewport/WidgetViewport.h"
-#include "../Framework/Volumes/ISlicedVolume.h"
-#include "../Framework/Volumes/IVolumeLoader.h"
-#include "../Framework/Widgets/IWorldSceneInteractor.h"
-#include "../Platforms/Generic/OracleWebService.h"
-
-#include
-#include
-
-namespace OrthancStone
-{
- class BasicApplicationContext : public boost::noncopyable
- {
- private:
- typedef std::list SlicedVolumes;
- typedef std::list VolumeLoaders;
- typedef std::list Interactors;
-
- static void UpdateThread(BasicApplicationContext* that);
-
- Oracle oracle_;
- OracleWebService webService_;
- boost::mutex viewportMutex_;
- WidgetViewport viewport_;
- SlicedVolumes slicedVolumes_;
- VolumeLoaders volumeLoaders_;
- Interactors interactors_;
- boost::thread updateThread_;
- bool stopped_;
- unsigned int updateDelay_;
-
- public:
- class ViewportLocker : public boost::noncopyable
- {
- private:
- boost::mutex::scoped_lock lock_;
- IViewport& viewport_;
-
- public:
- ViewportLocker(BasicApplicationContext& that) :
- lock_(that.viewportMutex_),
- viewport_(that.viewport_)
- {
- }
-
- IViewport& GetViewport() const
- {
- return viewport_;
- }
- };
-
-
- BasicApplicationContext(Orthanc::WebServiceParameters& orthanc);
-
- ~BasicApplicationContext();
-
- IWidget& SetCentralWidget(IWidget* widget); // Takes ownership
-
- IWebService& GetWebService()
- {
- return webService_;
- }
-
- ISlicedVolume& AddSlicedVolume(ISlicedVolume* volume);
-
- IVolumeLoader& AddVolumeLoader(IVolumeLoader* loader);
-
- IWorldSceneInteractor& AddInteractor(IWorldSceneInteractor* interactor);
-
- void Start();
-
- void Stop();
-
- void SetUpdateDelay(unsigned int delay) // In milliseconds
- {
- updateDelay_ = delay;
- }
- };
-}
diff -r 3a8bac805352 -r 36ebe6ec8fe8 Applications/Generic/BasicNativeApplicationContext.cpp
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/Applications/Generic/BasicNativeApplicationContext.cpp Thu Aug 30 16:56:08 2018 +0200
@@ -0,0 +1,80 @@
+/**
+ * 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 .
+ **/
+
+
+#include "BasicNativeApplicationContext.h"
+#include "../../Platforms/Generic/OracleWebService.h"
+
+namespace OrthancStone
+{
+ IWidget& BasicNativeApplicationContext::SetCentralWidget(IWidget* widget) // Takes ownership
+ {
+ centralViewport_->SetCentralWidget(widget);
+ return *widget;
+ }
+
+
+ void BasicNativeApplicationContext::UpdateThread(BasicNativeApplicationContext* that)
+ {
+ while (!that->stopped_)
+ {
+ {
+ GlobalMutexLocker locker(*that);
+ that->GetCentralViewport().UpdateContent();
+ }
+
+ boost::this_thread::sleep(boost::posix_time::milliseconds(that->updateDelayInMs_));
+ }
+ }
+
+
+ BasicNativeApplicationContext::BasicNativeApplicationContext() :
+ centralViewport_(new OrthancStone::WidgetViewport()),
+ stopped_(true),
+ updateDelayInMs_(100) // By default, 100ms between each refresh of the content
+ {
+ srand(time(NULL));
+ }
+
+
+ void BasicNativeApplicationContext::Start()
+ {
+ dynamic_cast(webService_)->Start();
+
+ if (centralViewport_->HasUpdateContent())
+ {
+ stopped_ = false;
+ updateThread_ = boost::thread(UpdateThread, this);
+ }
+ }
+
+
+ void BasicNativeApplicationContext::Stop()
+ {
+ stopped_ = true;
+
+ if (updateThread_.joinable())
+ {
+ updateThread_.join();
+ }
+
+ dynamic_cast(webService_)->Stop();
+ }
+}
diff -r 3a8bac805352 -r 36ebe6ec8fe8 Applications/Generic/BasicNativeApplicationContext.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/Applications/Generic/BasicNativeApplicationContext.h Thu Aug 30 16:56:08 2018 +0200
@@ -0,0 +1,73 @@
+/**
+ * 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 .
+ **/
+
+
+#pragma once
+
+#include "../../Framework/Viewport/WidgetViewport.h"
+#include "../../Framework/Volumes/ISlicedVolume.h"
+#include "../../Framework/Volumes/IVolumeLoader.h"
+
+#include
+#include
+#include "../StoneApplicationContext.h"
+
+namespace OrthancStone
+{
+ class BasicNativeApplicationContext : public StoneApplicationContext
+ {
+ private:
+
+ static void UpdateThread(BasicNativeApplicationContext* that);
+
+ boost::mutex globalMutex_;
+ std::unique_ptr centralViewport_;
+ boost::thread updateThread_;
+ bool stopped_;
+ unsigned int updateDelayInMs_;
+
+ public:
+ class GlobalMutexLocker: public boost::noncopyable
+ {
+ boost::mutex::scoped_lock lock_;
+ public:
+ GlobalMutexLocker(BasicNativeApplicationContext& that):
+ lock_(that.globalMutex_)
+ {}
+ };
+
+ BasicNativeApplicationContext();
+
+ virtual ~BasicNativeApplicationContext() {}
+
+ virtual IWidget& SetCentralWidget(IWidget* widget); // Takes ownership
+ IViewport& GetCentralViewport() {return *(centralViewport_.get());}
+
+ void Start();
+
+ void Stop();
+
+ void SetUpdateDelay(unsigned int delayInMs)
+ {
+ updateDelayInMs_ = delayInMs;
+ }
+
+ };
+}
diff -r 3a8bac805352 -r 36ebe6ec8fe8 Applications/Generic/BasicNativeApplicationRunner.cpp
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/Applications/Generic/BasicNativeApplicationRunner.cpp Thu Aug 30 16:56:08 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 .
+ **/
+
+
+#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
+
+#include "../../Framework/Toolbox/MessagingToolbox.h"
+
+#include
+#include
+#include
+#include
+#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()->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()->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())
+ {
+ 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());
+ }
+
+ if (parameters.count("username"))
+ {
+ webServiceParameters.SetUsername(parameters["username"].as());
+ }
+
+ if (parameters.count("password"))
+ {
+ webServiceParameters.SetPassword(parameters["password"].as());
+ }
+
+ 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);
+ }
+
+}
diff -r 3a8bac805352 -r 36ebe6ec8fe8 Applications/Generic/BasicNativeApplicationRunner.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/Applications/Generic/BasicNativeApplicationRunner.h Thu Aug 30 16:56:08 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 .
+ **/
+
+
+#pragma once
+
+#include "../IStoneApplication.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_;
+ IStoneApplication& application_;
+ public:
+
+ BasicNativeApplicationRunner(MessageBroker& broker,
+ IStoneApplication& 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;
+ };
+
+}
diff -r 3a8bac805352 -r 36ebe6ec8fe8 Applications/IBasicApplication.cpp
--- a/Applications/IBasicApplication.cpp Tue Aug 28 21:00:35 2018 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,300 +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 .
- **/
-
-
-#include "IBasicApplication.h"
-
-#include "../Framework/Toolbox/MessagingToolbox.h"
-#include "Sdl/SdlEngine.h"
-
-#include
-#include
-#include
-#include
-
-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;
- }
- };
- }
-
-
-#if ORTHANC_ENABLE_SDL == 1
- static void DeclareSdlCommandLineOptions(boost::program_options::options_description& options)
- {
- // Declare the supported parameters
- 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()->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()->default_value(true), "Check HTTPS certificates")
- ;
-
- options.add(generic);
-
- boost::program_options::options_description sdl("SDL options");
- sdl.add_options()
- ("width", boost::program_options::value()->default_value(1024), "Initial width of the SDL window")
- ("height", boost::program_options::value()->default_value(768), "Initial height of the SDL window")
- ("opengl", boost::program_options::value()->default_value(true), "Enable OpenGL in SDL")
- ;
-
- options.add(sdl);
- }
-
-
- int IBasicApplication::ExecuteWithSdl(IBasicApplication& application,
- int argc,
- char* argv[])
- {
- /******************************************************************
- * Initialize all the subcomponents of Orthanc Stone
- ******************************************************************/
-
- Orthanc::Logging::Initialize();
- Orthanc::Toolbox::InitializeOpenSsl();
- Orthanc::HttpClient::GlobalInitialize();
- SdlWindow::GlobalInitialize();
-
-
- /******************************************************************
- * Declare and parse the command-line options of the application
- ******************************************************************/
-
- boost::program_options::options_description options;
- DeclareSdlCommandLineOptions(options);
- application.DeclareCommandLineOptions(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())
- {
- LOG(WARNING) << "Turning off verification of HTTPS certificates (unsafe)";
- Orthanc::HttpClient::ConfigureSsl(false, "");
- }
-
- if (parameters.count("verbose"))
- {
- Orthanc::Logging::EnableInfoLevel(true);
- }
-
- if (!parameters.count("width") ||
- !parameters.count("height") ||
- !parameters.count("opengl"))
- {
- LOG(ERROR) << "Parameter \"width\", \"height\" or \"opengl\" is missing";
- return -1;
- }
-
- int w = parameters["width"].as();
- int h = parameters["height"].as();
- if (w <= 0 || h <= 0)
- {
- LOG(ERROR) << "Parameters \"width\" and \"height\" must be positive";
- return -1;
- }
-
- unsigned int width = static_cast(w);
- unsigned int height = static_cast(h);
- LOG(WARNING) << "Initial display size: " << width << "x" << height;
-
- bool opengl = parameters["opengl"].as();
- if (opengl)
- {
- LOG(WARNING) << "OpenGL is enabled, disable it with option \"--opengl=off\" if the application crashes";
- }
- else
- {
- LOG(WARNING) << "OpenGL is disabled, enable it with option \"--opengl=on\" for best performance";
- }
-
- bool success = true;
- try
- {
- /****************************************************************
- * Initialize the connection to the Orthanc server
- ****************************************************************/
-
- Orthanc::WebServiceParameters webService;
-
- if (parameters.count("orthanc"))
- {
- webService.SetUrl(parameters["orthanc"].as());
- }
-
- std::string username, password;
-
- if (parameters.count("username"))
- {
- username = parameters["username"].as();
- }
-
- if (parameters.count("password"))
- {
- password = parameters["password"].as();
- }
-
- if (!username.empty() ||
- !password.empty())
- {
- webService.SetCredentials(username, password);
- }
-
- LOG(WARNING) << "URL to the Orthanc REST API: " << webService.GetUrl();
-
- {
- OrthancPlugins::OrthancHttpConnection orthanc(webService);
- 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;
- BasicApplicationContext context(webService);
-
- application.Initialize(context, statusBar, parameters);
-
- {
- BasicApplicationContext::ViewportLocker locker(context);
- locker.GetViewport().SetStatusBar(statusBar);
- }
-
- std::string title = application.GetTitle();
- if (title.empty())
- {
- title = "Stone of Orthanc";
- }
-
- {
- /**************************************************************
- * Run the application inside a SDL window
- **************************************************************/
-
- LOG(WARNING) << "Starting the application";
-
- SdlWindow window(title.c_str(), width, height, opengl);
- SdlEngine sdl(window, context);
-
- {
- BasicApplicationContext::ViewportLocker locker(context);
- locker.GetViewport().Register(sdl); // (*)
- }
-
- context.Start();
- sdl.Run();
-
- LOG(WARNING) << "Stopping the application";
-
- // Don't move the "Stop()" command below out of the block,
- // otherwise the application might crash, because the
- // "SdlEngine" is an observer of the viewport (*) and the
- // update thread started by "context.Start()" would call a
- // destructed object (the "SdlEngine" is deleted with the
- // lexical scope).
- context.Stop();
- }
-
-
- /****************************************************************
- * 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
- ******************************************************************/
-
- SdlWindow::GlobalFinalize();
- Orthanc::HttpClient::GlobalFinalize();
- Orthanc::Toolbox::FinalizeOpenSsl();
-
- return (success ? 0 : -1);
- }
-#endif
-
-}
diff -r 3a8bac805352 -r 36ebe6ec8fe8 Applications/IBasicApplication.h
--- a/Applications/IBasicApplication.h Tue Aug 28 21:00:35 2018 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,57 +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 .
- **/
-
-
-#pragma once
-
-#include "BasicApplicationContext.h"
-
-#include
-
-#if ORTHANC_ENABLE_SDL == 1
-# include // Necessary to avoid undefined reference to `SDL_main'
-#endif
-
-namespace OrthancStone
-{
- class IBasicApplication : public boost::noncopyable
- {
- public:
- virtual ~IBasicApplication()
- {
- }
-
- virtual void DeclareCommandLineOptions(boost::program_options::options_description& options) = 0;
-
- virtual std::string GetTitle() const = 0;
-
- virtual void Initialize(BasicApplicationContext& context,
- IStatusBar& statusBar,
- const boost::program_options::variables_map& parameters) = 0;
-
- virtual void Finalize() = 0;
-
-#if ORTHANC_ENABLE_SDL == 1
- static int ExecuteWithSdl(IBasicApplication& application,
- int argc,
- char* argv[]);
-#endif
- };
-}
diff -r 3a8bac805352 -r 36ebe6ec8fe8 Applications/IStoneApplication.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/Applications/IStoneApplication.h Thu Aug 30 16:56:08 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 .
+ **/
+
+
+#pragma once
+
+#include "StoneApplicationContext.h"
+#include
+#include "../Framework/Viewport/WidgetViewport.h"
+#include "json/json.h"
+
+namespace OrthancStone
+{
+ // a StoneApplication is an application that can actually be executed
+ // in multiple environments. i.e: it can run natively integrated in a QtApplication
+ // or it can be executed as part of a WebPage when compiled into WebAssembly.
+ class IStoneApplication : public boost::noncopyable
+ {
+ protected:
+ StoneApplicationContext* context_;
+
+ public:
+ virtual ~IStoneApplication()
+ {
+ }
+
+ virtual void DeclareStartupOptions(boost::program_options::options_description& options) = 0;
+ virtual void Initialize(StoneApplicationContext* context,
+ IStatusBar& statusBar,
+ const boost::program_options::variables_map& parameters) = 0;
+#if ORTHANC_ENABLE_WASM==1
+ virtual void InitializeWasm() {} // specific initialization when the app is running in WebAssembly. This is called after the other Initialize()
+#endif
+
+ virtual std::string GetTitle() const = 0;
+ virtual IWidget* GetCentralWidget() = 0;
+
+ virtual void Finalize() = 0;
+ };
+
+}
diff -r 3a8bac805352 -r 36ebe6ec8fe8 Applications/Qt/BasicQtApplicationRunner.cpp
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/Applications/Qt/BasicQtApplicationRunner.cpp Thu Aug 30 16:56:08 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 .
+ **/
+
+
+#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
+#include
+
+#include "../../Framework/Toolbox/MessagingToolbox.h"
+
+#include
+#include
+#include
+#include
+#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()
+ {
+ }
+
+
+}
diff -r 3a8bac805352 -r 36ebe6ec8fe8 Applications/Qt/BasicQtApplicationRunner.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/Applications/Qt/BasicQtApplicationRunner.h Thu Aug 30 16:56:08 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 .
+ **/
+
+
+#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 window_;
+
+ virtual void InitializeMainWindow(BasicNativeApplicationContext& context) = 0;
+ public:
+ BasicQtApplicationRunner(MessageBroker& broker,
+ IStoneApplication& 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();
+ };
+
+}
diff -r 3a8bac805352 -r 36ebe6ec8fe8 Applications/Qt/QCairoWidget.cpp
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/Applications/Qt/QCairoWidget.cpp Thu Aug 30 16:56:08 2018 +0200
@@ -0,0 +1,164 @@
+/**
+ * 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 .
+ **/
+
+#include "QCairoWidget.h"
+
+#include
+#include
+
+#include
+
+QCairoWidget::QCairoWidget(QWidget *parent) :
+ QWidget(parent),
+ context_(NULL)
+{
+ setFocusPolicy(Qt::StrongFocus); // catch keyPressEvents
+}
+
+QCairoWidget::~QCairoWidget()
+{
+}
+
+void QCairoWidget::SetContext(OrthancStone::BasicNativeApplicationContext& context)
+{
+ context_ = &context;
+ context_->GetCentralViewport().Register(*this); // get notified each time the content of the central viewport changes
+}
+
+void QCairoWidget::paintEvent(QPaintEvent* /*event*/)
+{
+ QPainter painter(this);
+
+ if (image_.get() != NULL && context_ != NULL)
+ {
+ OrthancStone::BasicNativeApplicationContext::GlobalMutexLocker locker(*context_);
+ OrthancStone::IViewport& viewport = context_->GetCentralViewport();
+ Orthanc::ImageAccessor a = surface_.GetAccessor();
+ viewport.Render(a);
+ painter.drawImage(0, 0, *image_);
+ }
+ else
+ {
+ painter.fillRect(rect(), Qt::red);
+ }
+}
+
+OrthancStone::KeyboardModifiers GetKeyboardModifiers(QInputEvent* event)
+{
+ Qt::KeyboardModifiers qtModifiers = event->modifiers();
+ int stoneModifiers = static_cast(OrthancStone::KeyboardModifiers_None);
+ if ((qtModifiers & Qt::AltModifier) != 0)
+ {
+ stoneModifiers |= static_cast(OrthancStone::KeyboardModifiers_Alt);
+ }
+ if ((qtModifiers & Qt::ControlModifier) != 0)
+ {
+ stoneModifiers |= static_cast(OrthancStone::KeyboardModifiers_Control);
+ }
+ if ((qtModifiers & Qt::ShiftModifier) != 0)
+ {
+ stoneModifiers |= static_cast(OrthancStone::KeyboardModifiers_Shift);
+ }
+ return static_cast(stoneModifiers);
+}
+
+void QCairoWidget::mousePressEvent(QMouseEvent* event)
+{
+ OrthancStone::KeyboardModifiers stoneModifiers = GetKeyboardModifiers(event);
+
+ OrthancStone::MouseButton button;
+
+ switch (event->button())
+ {
+ case Qt::LeftButton:
+ button = OrthancStone::MouseButton_Left;
+ break;
+
+ case Qt::RightButton:
+ button = OrthancStone::MouseButton_Right;
+ break;
+
+ case Qt::MiddleButton:
+ button = OrthancStone::MouseButton_Middle;
+ break;
+
+ default:
+ return; // Unsupported button
+ }
+ context_->GetCentralViewport().MouseDown(button, event->pos().x(), event->pos().y(), stoneModifiers);
+}
+
+
+void QCairoWidget::mouseReleaseEvent(QMouseEvent* /*eventNotUsed*/)
+{
+ context_->GetCentralViewport().MouseLeave();
+}
+
+
+void QCairoWidget::mouseMoveEvent(QMouseEvent* event)
+{
+ context_->GetCentralViewport().MouseMove(event->pos().x(), event->pos().y());
+}
+
+
+void QCairoWidget::wheelEvent(QWheelEvent * event)
+{
+ OrthancStone::KeyboardModifiers stoneModifiers = GetKeyboardModifiers(event);
+
+ if (event->orientation() == Qt::Vertical)
+ {
+ if (event->delta() < 0) // TODO: compare direction with SDL and make sure we send the same directions
+ {
+ context_->GetCentralViewport().MouseWheel(OrthancStone::MouseWheelDirection_Up, event->pos().x(), event->pos().y(), stoneModifiers);
+ }
+ else
+ {
+ context_->GetCentralViewport().MouseWheel(OrthancStone::MouseWheelDirection_Down, event->pos().x(), event->pos().y(), stoneModifiers);
+ }
+ }
+}
+
+void QCairoWidget::keyPressEvent(QKeyEvent *event)
+{
+ OrthancStone::KeyboardModifiers stoneModifiers = GetKeyboardModifiers(event);
+
+ context_->GetCentralViewport().KeyPressed(event->text()[0].toLatin1(), stoneModifiers);
+}
+
+
+void QCairoWidget::resizeEvent(QResizeEvent* event)
+{
+ grabGesture(Qt::PanGesture);
+ QWidget::resizeEvent(event);
+
+ if (event)
+ {
+ surface_.SetSize(event->size().width(), event->size().height());
+
+ image_.reset(new QImage(reinterpret_cast(surface_.GetBuffer()),
+ event->size().width(),
+ event->size().height(),
+ surface_.GetPitch(),
+ QImage::Format_RGB32));
+
+ context_->GetCentralViewport().SetSize(event->size().width(), event->size().height());
+
+ }
+}
diff -r 3a8bac805352 -r 36ebe6ec8fe8 Applications/Qt/QCairoWidget.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/Applications/Qt/QCairoWidget.h Thu Aug 30 16:56:08 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 .
+ **/
+
+#pragma once
+
+#include "../../Framework/Widgets/CairoWidget.h"
+#include "../../Applications/Generic/BasicNativeApplicationContext.h"
+#include "../../Framework/Viewport/CairoSurface.h"
+
+#include
+#include
+#include
+#include
+
+class QCairoWidget : public QWidget, public OrthancStone::IViewport::IObserver
+{
+ Q_OBJECT
+
+private:
+ std::auto_ptr image_;
+ OrthancStone::CairoSurface surface_;
+ OrthancStone::BasicNativeApplicationContext* context_;
+
+protected:
+ virtual void paintEvent(QPaintEvent *event);
+
+ virtual void resizeEvent(QResizeEvent *event);
+
+ virtual void mouseMoveEvent(QMouseEvent *event);
+
+ virtual void mousePressEvent(QMouseEvent *event);
+
+ virtual void mouseReleaseEvent(QMouseEvent *event);
+
+ virtual void wheelEvent(QWheelEvent *event);
+
+ virtual void keyPressEvent(QKeyEvent *event);
+
+public:
+ explicit QCairoWidget(QWidget *parent);
+
+ virtual ~QCairoWidget();
+
+ void SetContext(OrthancStone::BasicNativeApplicationContext& context);
+
+ virtual void OnViewportContentChanged(const OrthancStone::IViewport& /*sceneNotUsed*/)
+ {
+ update(); // schedule a repaint (handled by Qt)
+ emit ContentChanged();
+ }
+
+signals:
+
+ void ContentChanged();
+
+public slots:
+
+};
diff -r 3a8bac805352 -r 36ebe6ec8fe8 Applications/Qt/QStoneMainWindow.cpp
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/Applications/Qt/QStoneMainWindow.cpp Thu Aug 30 16:56:08 2018 +0200
@@ -0,0 +1,41 @@
+/**
+ * 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 .
+ **/
+
+#include "QStoneMainWindow.h"
+
+namespace OrthancStone
+{
+
+ QStoneMainWindow::QStoneMainWindow(BasicNativeApplicationContext& context, QWidget *parent) :
+ QMainWindow(parent),
+ context_(context)
+ {
+ }
+
+ void QStoneMainWindow::SetCentralStoneWidget(QCairoWidget *centralWidget)
+ {
+ cairoCentralWidget_ = centralWidget;
+ cairoCentralWidget_->SetContext(context_);
+ }
+
+ QStoneMainWindow::~QStoneMainWindow()
+ {
+ }
+}
diff -r 3a8bac805352 -r 36ebe6ec8fe8 Applications/Qt/QStoneMainWindow.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/Applications/Qt/QStoneMainWindow.h Thu Aug 30 16:56:08 2018 +0200
@@ -0,0 +1,45 @@
+/**
+ * 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 .
+ **/
+#pragma once
+
+#include
+
+#include "QCairoWidget.h"
+#include "../Generic/BasicNativeApplicationContext.h"
+
+namespace OrthancStone
+{
+ class QStoneMainWindow : public QMainWindow
+ {
+ Q_OBJECT
+
+ private:
+ OrthancStone::BasicNativeApplicationContext& context_;
+ QCairoWidget *cairoCentralWidget_;
+
+ protected: // you must inherit this class
+ QStoneMainWindow(BasicNativeApplicationContext& context, QWidget *parent = 0);
+ void SetCentralStoneWidget(QCairoWidget* centralWidget);
+ public:
+ virtual ~QStoneMainWindow();
+
+ };
+
+}
diff -r 3a8bac805352 -r 36ebe6ec8fe8 Applications/Samples/EmptyApplication.h
--- a/Applications/Samples/EmptyApplication.h Tue Aug 28 21:00:35 2018 +0200
+++ b/Applications/Samples/EmptyApplication.h Thu Aug 30 16:56:08 2018 +0200
@@ -32,7 +32,7 @@
class EmptyApplication : public SampleApplicationBase
{
public:
- virtual void DeclareCommandLineOptions(boost::program_options::options_description& options)
+ virtual void DeclareStartupOptions(boost::program_options::options_description& options)
{
boost::program_options::options_description generic("Sample options");
generic.add_options()
@@ -44,15 +44,14 @@
options.add(generic);
}
- virtual void Initialize(BasicApplicationContext& context,
- IStatusBar& statusBar,
+ virtual void Initialize(IStatusBar& statusBar,
const boost::program_options::variables_map& parameters)
{
int red = parameters["red"].as();
int green = parameters["green"].as();
int blue = parameters["blue"].as();
- context.SetCentralWidget(new EmptyWidget(red, green, blue));
+ context_->SetCentralWidget(new EmptyWidget(red, green, blue));
}
};
}
diff -r 3a8bac805352 -r 36ebe6ec8fe8 Applications/Samples/Qt/SampleMainWindow.cpp
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/Applications/Samples/Qt/SampleMainWindow.cpp Thu Aug 30 16:56:08 2018 +0200
@@ -0,0 +1,86 @@
+/**
+ * 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 .
+ **/
+
+#include "SampleMainWindow.h"
+
+/**
+ * Don't use "ui_MainWindow.h" instead of below, as
+ * this makes CMake unable to detect when the UI file changes.
+ **/
+#include
+#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);
+
+ std::string pushButton1Name;
+ std::string pushButton2Name;
+ std::string tool1Name;
+ std::string tool2Name;
+ stoneSampleApplication_.GetButtonNames(pushButton1Name, pushButton2Name, tool1Name, tool2Name);
+
+ ui_->toolButton1->setText(QString::fromStdString(tool1Name));
+ ui_->toolButton2->setText(QString::fromStdString(tool2Name));
+ ui_->pushButton1->setText(QString::fromStdString(pushButton1Name));
+ ui_->pushButton2->setText(QString::fromStdString(pushButton2Name));
+ }
+
+ SampleMainWindow::~SampleMainWindow()
+ {
+ delete ui_;
+ }
+
+ void SampleMainWindow::tool1Clicked()
+ {
+ stoneSampleApplication_.OnTool1Clicked();
+ }
+
+ void SampleMainWindow::tool2Clicked()
+ {
+ stoneSampleApplication_.OnTool2Clicked();
+ }
+
+ void SampleMainWindow::pushButton1Clicked()
+ {
+ stoneSampleApplication_.OnPushButton1Clicked();
+ }
+
+ void SampleMainWindow::pushButton2Clicked()
+ {
+ stoneSampleApplication_.OnPushButton2Clicked();
+ }
+
+ }
+}
diff -r 3a8bac805352 -r 36ebe6ec8fe8 Applications/Samples/Qt/SampleMainWindow.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/Applications/Samples/Qt/SampleMainWindow.h Thu Aug 30 16:56:08 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 .
+ **/
+#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();
+ };
+ }
+}
diff -r 3a8bac805352 -r 36ebe6ec8fe8 Applications/Samples/Qt/SampleMainWindow.ui
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/Applications/Samples/Qt/SampleMainWindow.ui Thu Aug 30 16:56:08 2018 +0200
@@ -0,0 +1,130 @@
+
+
+ SampleMainWindow
+
+
+
+ 0
+ 0
+ 903
+ 634
+
+
+
+
+ 500
+ 300
+
+
+
+
+ 500
+ 300
+
+
+
+ Stone of Orthanc
+
+
+ Qt::LeftToRight
+
+
+
+
+ 0
+ 0
+
+
+
+ Qt::LeftToRight
+
+
+
+ QLayout::SetDefaultConstraint
+
+
+
+
+
+ 0
+ 500
+
+
+
+
+
+
+
+
+ 0
+ 100
+
+
+
+
+ 16777215
+ 100
+
+
+
+
+
+
+ tool1
+
+
+
+
+
+
+ tool2
+
+
+
+
+
+
+ action1
+
+
+
+
+
+
+ action2
+
+
+
+
+
+
+
+
+
+
+
+ 0
+ 0
+ 903
+ 22
+
+
+
+
+ Test
+
+
+
+
+
+
+
+
+ QCairoWidget
+ QGraphicsView
+ QCairoWidget.h
+
+
+
+
+
diff -r 3a8bac805352 -r 36ebe6ec8fe8 Applications/Samples/Qt/SampleQtApplicationRunner.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/Applications/Samples/Qt/SampleQtApplicationRunner.h Thu Aug 30 16:56:08 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 .
+ **/
+
+
+#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(application_)));
+ }
+ public:
+ SampleQtApplicationRunner(MessageBroker& broker,
+ SampleApplicationBase& application)
+ : OrthancStone::BasicQtApplicationRunner(broker, application)
+ {
+ }
+
+ };
+ }
+}
diff -r 3a8bac805352 -r 36ebe6ec8fe8 Applications/Samples/SampleApplicationBase.h
--- a/Applications/Samples/SampleApplicationBase.h Tue Aug 28 21:00:35 2018 +0200
+++ b/Applications/Samples/SampleApplicationBase.h Thu Aug 30 16:56:08 2018 +0200
@@ -21,27 +21,44 @@
#pragma once
-#include "../IBasicApplication.h"
+#include "../../Applications/IStoneApplication.h"
namespace OrthancStone
{
namespace Samples
{
- class SampleApplicationBase : public IBasicApplication
+ class SampleApplicationBase : public IStoneApplication
{
public:
+ virtual void Initialize(StoneApplicationContext* context,
+ IStatusBar& statusBar,
+ const boost::program_options::variables_map& parameters)
+ {
+ }
+
+
+
virtual std::string GetTitle() const
{
return "Stone of Orthanc - Sample";
}
- virtual void DeclareCommandLineOptions(boost::program_options::options_description& options)
- {
+ 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";
}
- virtual void Finalize()
- {
- }
};
}
}
diff -r 3a8bac805352 -r 36ebe6ec8fe8 Applications/Samples/SampleList.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/Applications/Samples/SampleList.h Thu Aug 30 16:56:08 2018 +0200
@@ -0,0 +1,37 @@
+// The macro "ORTHANC_STONE_SAMPLE" must be set by the CMake script
+
+#if ORTHANC_STONE_SAMPLE == 1
+#include "EmptyApplication.h"
+typedef OrthancStone::Samples::EmptyApplication SampleApplication;
+
+#elif ORTHANC_STONE_SAMPLE == 2
+#include "TestPatternApplication.h"
+typedef OrthancStone::Samples::TestPatternApplication SampleApplication;
+
+#elif ORTHANC_STONE_SAMPLE == 3
+#include "SingleFrameApplication.h"
+typedef OrthancStone::Samples::SingleFrameApplication SampleApplication;
+
+#elif ORTHANC_STONE_SAMPLE == 4
+#include "SingleVolumeApplication.h"
+typedef OrthancStone::Samples::SingleVolumeApplication SampleApplication;
+
+#elif ORTHANC_STONE_SAMPLE == 5
+#include "BasicPetCtFusionApplication.h"
+typedef OrthancStone::Samples::BasicPetCtFusionApplication SampleApplication;
+
+#elif ORTHANC_STONE_SAMPLE == 6
+#include "SynchronizedSeriesApplication.h"
+typedef OrthancStone::Samples::SynchronizedSeriesApplication SampleApplication;
+
+#elif ORTHANC_STONE_SAMPLE == 7
+#include "LayoutPetCtFusionApplication.h"
+typedef OrthancStone::Samples::LayoutPetCtFusionApplication SampleApplication;
+
+#elif ORTHANC_STONE_SAMPLE == 8
+#include "SimpleViewerApplication.h"
+typedef OrthancStone::Samples::SimpleViewerApplication SampleApplication;
+
+#else
+#error Please set the ORTHANC_STONE_SAMPLE macro
+#endif
diff -r 3a8bac805352 -r 36ebe6ec8fe8 Applications/Samples/SampleMainNative.cpp
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/Applications/Samples/SampleMainNative.cpp Thu Aug 30 16:56:08 2018 +0200
@@ -0,0 +1,44 @@
+/**
+ * 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 .
+ **/
+
+
+#include "SampleList.h"
+#if ORTHANC_ENABLE_SDL==1
+#include "../Sdl/BasicSdlApplication.h"
+#endif
+#if ORTHANC_ENABLE_QT==1
+#include "Qt/SampleQtApplicationRunner.h"
+#endif
+#include "../../Framework/Messages/MessageBroker.h"
+
+int main(int argc, char* argv[])
+{
+ OrthancStone::MessageBroker broker;
+ SampleApplication sampleStoneApplication(broker);
+
+#if ORTHANC_ENABLE_SDL==1
+ OrthancStone::BasicSdlApplication sdlApplication;
+ return sdlApplication.Execute(broker, sampleStoneApplication, argc, argv);
+#endif
+#if ORTHANC_ENABLE_QT==1
+ OrthancStone::Samples::SampleQtApplicationRunner qtAppRunner(broker, sampleStoneApplication);
+ return qtAppRunner.Execute(argc, argv);
+#endif
+}
diff -r 3a8bac805352 -r 36ebe6ec8fe8 Applications/Samples/SampleMainSdl.cpp
--- a/Applications/Samples/SampleMainSdl.cpp Tue Aug 28 21:00:35 2018 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,62 +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 .
- **/
-
-
-// The macro "ORTHANC_STONE_SAMPLE" must be set by the CMake script
-
-#if ORTHANC_STONE_SAMPLE == 1
-#include "EmptyApplication.h"
-typedef OrthancStone::Samples::EmptyApplication Application;
-
-#elif ORTHANC_STONE_SAMPLE == 2
-#include "TestPatternApplication.h"
-typedef OrthancStone::Samples::TestPatternApplication Application;
-
-#elif ORTHANC_STONE_SAMPLE == 3
-#include "SingleFrameApplication.h"
-typedef OrthancStone::Samples::SingleFrameApplication Application;
-
-#elif ORTHANC_STONE_SAMPLE == 4
-#include "SingleVolumeApplication.h"
-typedef OrthancStone::Samples::SingleVolumeApplication Application;
-
-#elif ORTHANC_STONE_SAMPLE == 5
-#include "BasicPetCtFusionApplication.h"
-typedef OrthancStone::Samples::BasicPetCtFusionApplication Application;
-
-#elif ORTHANC_STONE_SAMPLE == 6
-#include "SynchronizedSeriesApplication.h"
-typedef OrthancStone::Samples::SynchronizedSeriesApplication Application;
-
-#elif ORTHANC_STONE_SAMPLE == 7
-#include "LayoutPetCtFusionApplication.h"
-typedef OrthancStone::Samples::LayoutPetCtFusionApplication Application;
-
-#else
-#error Please set the ORTHANC_STONE_SAMPLE macro
-#endif
-
-
-int main(int argc, char* argv[])
-{
- Application application;
-
- return OrthancStone::IBasicApplication::ExecuteWithSdl(application, argc, argv);
-}
diff -r 3a8bac805352 -r 36ebe6ec8fe8 Applications/Samples/SampleMainWasm.cpp
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/Applications/Samples/SampleMainWasm.cpp Thu Aug 30 16:56:08 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 .
+ **/
+
+#include "Platforms/Wasm/WasmWebService.h"
+#include "Platforms/Wasm/WasmViewport.h"
+
+#include
+
+#include "SampleList.h"
+
+
+OrthancStone::IStoneApplication* CreateUserApplication(OrthancStone::MessageBroker& broker) {
+
+ return new SampleApplication(broker);
+}
\ No newline at end of file
diff -r 3a8bac805352 -r 36ebe6ec8fe8 Applications/Samples/SimpleViewerApplication.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/Applications/Samples/SimpleViewerApplication.h Thu Aug 30 16:56:08 2018 +0200
@@ -0,0 +1,417 @@
+/**
+ * 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 .
+ **/
+
+
+#pragma once
+
+#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"
+#include "../../Framework/Messages/IObserver.h"
+#include "../../Framework/SmartLoader.h"
+
+#if ORTHANC_ENABLE_WASM==1
+#include "../../Platforms/Wasm/IStoneApplicationToWebApplicationAdapter.h"
+#include "../../Platforms/Wasm/Defaults.h"
+#endif
+#include
+
+namespace OrthancStone
+{
+ namespace Samples
+ {
+ class SimpleViewerApplication :
+ public SampleApplicationBase,
+#if ORTHANC_ENABLE_WASM==1
+ public IStoneApplicationToWebApplicationAdapter,
+#endif
+ public IObserver
+ {
+ private:
+ class ThumbnailInteractor : public IWorldSceneInteractor
+ {
+ private:
+ SimpleViewerApplication& application_;
+ public:
+ ThumbnailInteractor(SimpleViewerApplication& application) :
+ application_(application)
+ {
+ }
+
+ virtual IWorldSceneMouseTracker* CreateMouseTracker(WorldSceneWidget& widget,
+ const ViewportGeometry& view,
+ MouseButton button,
+ KeyboardModifiers modifiers,
+ double x,
+ double y,
+ IStatusBar* statusBar)
+ {
+ if (button == MouseButton_Left)
+ {
+ statusBar->SetMessage("selected thumbnail " + widget.GetName());
+ std::string seriesId = widget.GetName().substr(strlen("thumbnail-series-"));
+ application_.SelectSeriesInMainViewport(seriesId);
+ }
+ return NULL;
+ }
+ virtual void MouseOver(CairoContext& context,
+ WorldSceneWidget& widget,
+ const ViewportGeometry& view,
+ double x,
+ double y,
+ IStatusBar* statusBar)
+ {}
+
+ virtual void MouseWheel(WorldSceneWidget& widget,
+ MouseWheelDirection direction,
+ KeyboardModifiers modifiers,
+ IStatusBar* statusBar)
+ {}
+
+ virtual void KeyPressed(WorldSceneWidget& widget,
+ char key,
+ KeyboardModifiers modifiers,
+ IStatusBar* statusBar)
+ {}
+
+ };
+
+ class MainWidgetInteractor : public IWorldSceneInteractor
+ {
+ private:
+ SimpleViewerApplication& application_;
+
+ public:
+ MainWidgetInteractor(SimpleViewerApplication& application) :
+ application_(application)
+ {
+ }
+
+ virtual IWorldSceneMouseTracker* CreateMouseTracker(WorldSceneWidget& widget,
+ const ViewportGeometry& view,
+ MouseButton button,
+ KeyboardModifiers modifiers,
+ double x,
+ double y,
+ IStatusBar* statusBar)
+ {
+ if (button == MouseButton_Left)
+ {
+ if (application_.currentTool_ == Tools_LineMeasure)
+ {
+ return new LineMeasureTracker(statusBar, dynamic_cast(widget).GetSlice(), x, y, 255, 0, 0, 10);
+ }
+ else if (application_.currentTool_ == Tools_CircleMeasure)
+ {
+ return new CircleMeasureTracker(statusBar, dynamic_cast(widget).GetSlice(), x, y, 255, 0, 0, 10);
+ }
+ }
+ return NULL;
+ }
+
+ virtual void MouseOver(CairoContext& context,
+ WorldSceneWidget& widget,
+ const ViewportGeometry& view,
+ double x,
+ double y,
+ IStatusBar* statusBar)
+ {
+ if (statusBar != NULL)
+ {
+ Vector p = dynamic_cast(widget).GetSlice().MapSliceToWorldCoordinates(x, y);
+
+ char buf[64];
+ sprintf(buf, "X = %.02f Y = %.02f Z = %.02f (in cm)",
+ p[0] / 10.0, p[1] / 10.0, p[2] / 10.0);
+ statusBar->SetMessage(buf);
+ }
+ }
+
+ virtual void MouseWheel(WorldSceneWidget& widget,
+ MouseWheelDirection direction,
+ KeyboardModifiers modifiers,
+ IStatusBar* statusBar)
+ {
+ }
+
+ virtual void KeyPressed(WorldSceneWidget& widget,
+ char key,
+ KeyboardModifiers modifiers,
+ IStatusBar* statusBar)
+ {
+ switch (key)
+ {
+ case 's':
+ widget.SetDefaultView();
+ break;
+
+ default:
+ break;
+ }
+ }
+ };
+
+ enum Tools {
+ Tools_LineMeasure,
+ Tools_CircleMeasure
+ };
+
+ Tools currentTool_;
+ std::unique_ptr mainWidgetInteractor_;
+ std::unique_ptr thumbnailInteractor_;
+ LayoutWidget* mainLayout_;
+ LayoutWidget* thumbnailsLayout_;
+ LayerWidget* mainWidget_;
+ std::vector thumbnails_;
+ std::map> instancesIdsPerSeriesId_;
+ std::map seriesTags_;
+
+ unsigned int currentInstanceIndex_;
+ OrthancStone::WidgetViewport* wasmViewport1_;
+ OrthancStone::WidgetViewport* wasmViewport2_;
+
+ IStatusBar* statusBar_;
+ std::unique_ptr smartLoader_;
+ std::unique_ptr orthancApiClient_;
+
+ public:
+ SimpleViewerApplication(MessageBroker& broker) :
+ IObserver(broker),
+ currentTool_(Tools_LineMeasure),
+ mainLayout_(NULL),
+ currentInstanceIndex_(0),
+ wasmViewport1_(NULL),
+ wasmViewport2_(NULL)
+ {
+ DeclareIgnoredMessage(MessageType_Widget_ContentChanged);
+ DeclareHandledMessage(MessageType_Widget_GeometryChanged);
+
+ DeclareHandledMessage(MessageType_OrthancApi_GetStudyIds_Ready);
+ DeclareHandledMessage(MessageType_OrthancApi_GetStudy_Ready);
+ DeclareHandledMessage(MessageType_OrthancApi_GetSeries_Ready);
+ }
+
+ virtual void Finalize() {}
+ virtual IWidget* GetCentralWidget() {return mainLayout_;}
+
+ virtual void DeclareStartupOptions(boost::program_options::options_description& options)
+ {
+ boost::program_options::options_description generic("Sample options");
+ generic.add_options()
+ ("studyId", boost::program_options::value(),
+ "Orthanc ID of the study")
+ ;
+
+ options.add(generic);
+ }
+
+ virtual void Initialize(StoneApplicationContext* context,
+ IStatusBar& statusBar,
+ const boost::program_options::variables_map& parameters)
+ {
+ using namespace OrthancStone;
+
+ context_ = context;
+ statusBar_ = &statusBar;
+
+ {// initialize viewports and layout
+ mainLayout_ = new LayoutWidget("main-layout");
+ mainLayout_->SetPadding(10);
+ mainLayout_->SetBackgroundCleared(true);
+ mainLayout_->SetBackgroundColor(0, 0, 0);
+ mainLayout_->SetHorizontal();
+
+ thumbnailsLayout_ = new LayoutWidget("thumbnail-layout");
+ thumbnailsLayout_->SetPadding(10);
+ thumbnailsLayout_->SetBackgroundCleared(true);
+ thumbnailsLayout_->SetBackgroundColor(50, 50, 50);
+ thumbnailsLayout_->SetVertical();
+
+ mainWidget_ = new LayerWidget(broker_, "main-viewport");
+ mainWidget_->RegisterObserver(*this);
+
+ // hierarchy
+ mainLayout_->AddWidget(thumbnailsLayout_);
+ mainLayout_->AddWidget(mainWidget_);
+
+ // sources
+ smartLoader_.reset(new SmartLoader(broker_, context_->GetWebService()));
+ smartLoader_->SetImageQuality(SliceImageQuality_FullPam);
+
+ mainLayout_->SetTransmitMouseOver(true);
+ mainWidgetInteractor_.reset(new MainWidgetInteractor(*this));
+ mainWidget_->SetInteractor(*mainWidgetInteractor_);
+ thumbnailInteractor_.reset(new ThumbnailInteractor(*this));
+ }
+
+ statusBar.SetMessage("Use the key \"s\" to reinitialize the layout");
+ statusBar.SetMessage("Use the key \"n\" to go to next image in the main viewport");
+
+ orthancApiClient_.reset(new OrthancApiClient(broker_, context_->GetWebService()));
+
+ if (parameters.count("studyId") < 1)
+ {
+ LOG(WARNING) << "The study ID is missing, will take the first studyId found in Orthanc";
+ orthancApiClient_->ScheduleGetStudyIds(*this);
+ }
+ else
+ {
+ SelectStudy(parameters["studyId"].as());
+ }
+ }
+
+ void OnStudyListReceived(const Json::Value& response)
+ {
+ if (response.isArray() && response.size() > 1)
+ {
+ SelectStudy(response[0].asString());
+ }
+ }
+ void OnStudyReceived(const Json::Value& response)
+ {
+ if (response.isObject() && response["Series"].isArray())
+ {
+ for (size_t i=0; i < response["Series"].size(); i++)
+ {
+ orthancApiClient_->ScheduleGetSeries(*this, response["Series"][(int)i].asString());
+ }
+ }
+ }
+
+ void OnSeriesReceived(const Json::Value& response)
+ {
+ if (response.isObject() && response["Instances"].isArray() && response["Instances"].size() > 0)
+ {
+ // keep track of all instances IDs
+ const std::string& seriesId = response["ID"].asString();
+ seriesTags_[seriesId] = response;
+ instancesIdsPerSeriesId_[seriesId] = std::vector();
+ for (size_t i = 0; i < response["Instances"].size(); i++)
+ {
+ const std::string& instanceId = response["Instances"][static_cast(i)].asString();
+ instancesIdsPerSeriesId_[seriesId].push_back(instanceId);
+ }
+
+ // load the first instance in the thumbnail
+ LoadThumbnailForSeries(seriesId, instancesIdsPerSeriesId_[seriesId][0]);
+
+ // 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));
+ }
+ }
+ }
+
+ void LoadThumbnailForSeries(const std::string& seriesId, const std::string& instanceId)
+ {
+ LOG(INFO) << "Loading thumbnail for series " << seriesId;
+ LayerWidget* thumbnailWidget = new LayerWidget(broker_, "thumbnail-series-" + seriesId);
+ thumbnails_.push_back(thumbnailWidget);
+ thumbnailsLayout_->AddWidget(thumbnailWidget);
+ thumbnailWidget->RegisterObserver(*this);
+ thumbnailWidget->AddLayer(smartLoader_->GetFrame(instanceId, 0));
+ thumbnailWidget->SetInteractor(*thumbnailInteractor_);
+ }
+
+ void SelectStudy(const std::string& studyId)
+ {
+ orthancApiClient_->ScheduleGetStudy(*this, studyId);
+ }
+
+ virtual void HandleMessage(IObservable& from, const IMessage& message) {
+ switch (message.GetType()) {
+ case MessageType_Widget_GeometryChanged:
+ LOG(INFO) << "Widget geometry ready: " << dynamic_cast(from).GetName();
+ dynamic_cast(from).SetDefaultView();
+ break;
+ case MessageType_OrthancApi_GetStudyIds_Ready:
+ OnStudyListReceived(dynamic_cast(message).response_);
+ break;
+ case MessageType_OrthancApi_GetSeries_Ready:
+ OnSeriesReceived(dynamic_cast(message).response_);
+ break;
+ case MessageType_OrthancApi_GetStudy_Ready:
+ OnStudyReceived(dynamic_cast(message).response_);
+ break;
+ default:
+ VLOG("unhandled message type" << message.GetType());
+ }
+ }
+
+ void SelectSeriesInMainViewport(const std::string& seriesId)
+ {
+ mainWidget_->ReplaceLayer(0, smartLoader_->GetFrame(instancesIdsPerSeriesId_[seriesId][0], 0));
+#if ORTHANC_ENABLE_WASM==1
+ NotifyStatusUpdateFromCppToWeb("series-description=" + seriesTags_[seriesId]["MainDicomTags"]["SeriesDescription"].asString());
+#endif
+ }
+
+ 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";
+ }
+
+#if ORTHANC_ENABLE_WASM==1
+ virtual void HandleMessageFromWeb(std::string& output, const std::string& input) {
+ if (input == "select-tool:line-measure")
+ {
+ currentTool_ = Tools_LineMeasure;
+ NotifyStatusUpdateFromCppToWeb("currentTool=line-measure");
+ }
+ else if (input == "select-tool:circle-measure")
+ {
+ currentTool_ = Tools_CircleMeasure;
+ NotifyStatusUpdateFromCppToWeb("currentTool=circle-measure");
+ }
+
+ output = "ok";
+ }
+
+ virtual void NotifyStatusUpdateFromCppToWeb(const std::string& statusUpdateMessage) {
+ UpdateStoneApplicationStatusFromCpp(statusUpdateMessage.c_str());
+ }
+
+ virtual void InitializeWasm() {
+
+ AttachWidgetToWasmViewport("canvas", thumbnailsLayout_);
+ AttachWidgetToWasmViewport("canvas2", mainWidget_);
+ }
+#endif
+ };
+
+
+ }
+}
diff -r 3a8bac805352 -r 36ebe6ec8fe8 Applications/Samples/SingleFrameApplication.h
--- a/Applications/Samples/SingleFrameApplication.h Tue Aug 28 21:00:35 2018 +0200
+++ b/Applications/Samples/SingleFrameApplication.h Thu Aug 30 16:56:08 2018 +0200
@@ -214,7 +214,7 @@
{
}
- virtual void DeclareCommandLineOptions(boost::program_options::options_description& options)
+ virtual void DeclareStartupOptions(boost::program_options::options_description& options)
{
boost::program_options::options_description generic("Sample options");
generic.add_options()
@@ -229,8 +229,7 @@
options.add(generic);
}
- virtual void Initialize(BasicApplicationContext& context,
- IStatusBar& statusBar,
+ virtual void Initialize(IStatusBar& statusBar,
const boost::program_options::variables_map& parameters)
{
using namespace OrthancStone;
@@ -250,7 +249,7 @@
#if 1
std::auto_ptr layer
- (new OrthancFrameLayerSource(context.GetWebService()));
+ (new OrthancFrameLayerSource(context_->GetWebService()));
//layer->SetImageQuality(SliceImageQuality_Jpeg50);
layer->LoadFrame(instance, frame);
//layer->LoadSeries("6f1b492a-e181e200-44e51840-ef8db55e-af529ab6");
@@ -271,7 +270,7 @@
// 0178023P**
// Extent of the CT layer: (-35.068 -20.368) => (34.932 49.632)
std::auto_ptr ct;
- ct.reset(new OrthancFrameLayerSource(context.GetWebService()));
+ ct.reset(new OrthancFrameLayerSource(context_->GetWebService()));
//ct->LoadInstance("c804a1a2-142545c9-33b32fe2-3df4cec0-a2bea6d6", 0);
//ct->LoadInstance("4bd4304f-47478948-71b24af2-51f4f1bc-275b6c1b", 0); // BAD SLICE
//ct->SetImageQuality(SliceImageQuality_Jpeg50);
@@ -281,7 +280,7 @@
widget->AddLayer(ct.release());
std::auto_ptr pet;
- pet.reset(new OrthancFrameLayerSource(context.GetWebService()));
+ pet.reset(new OrthancFrameLayerSource(context_->GetWebService()));
//pet->LoadInstance("a1c4dc6b-255d27f0-88069875-8daed730-2f5ee5c6", 0);
pet->LoadSeries("aabad2e7-80702b5d-e599d26c-4f13398e-38d58a9e");
pet->Register(*this);
@@ -309,8 +308,8 @@
widget_ = widget.get();
widget_->SetTransmitMouseOver(true);
- widget_->SetInteractor(context.AddInteractor(new Interactor(*this)));
- context.SetCentralWidget(widget.release());
+ widget_->SetInteractor(context_->AddInteractor(new Interactor(*this)));
+ context_->SetCentralWidget(widget.release());
}
};
}
diff -r 3a8bac805352 -r 36ebe6ec8fe8 Applications/Samples/SingleVolumeApplication.h
--- a/Applications/Samples/SingleVolumeApplication.h Tue Aug 28 21:00:35 2018 +0200
+++ b/Applications/Samples/SingleVolumeApplication.h Thu Aug 30 16:56:08 2018 +0200
@@ -89,7 +89,7 @@
public:
- virtual void DeclareCommandLineOptions(boost::program_options::options_description& options)
+ virtual void DeclareStartupOptions(boost::program_options::options_description& options)
{
boost::program_options::options_description generic("Sample options");
generic.add_options()
@@ -108,8 +108,7 @@
options.add(generic);
}
- virtual void Initialize(BasicApplicationContext& context,
- IStatusBar& statusBar,
+ virtual void Initialize(IStatusBar& statusBar,
const boost::program_options::variables_map& parameters)
{
using namespace OrthancStone;
@@ -147,8 +146,8 @@
throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
}
- unsigned int threads = parameters["threads"].as();
- bool reverse = parameters["reverse"].as();
+ //unsigned int threads = parameters["threads"].as();
+ //bool reverse = parameters["reverse"].as();
std::string tmp = parameters["projection"].as();
Orthanc::Toolbox::ToLowerCase(tmp);
@@ -175,7 +174,7 @@
std::auto_ptr widget(new LayerWidget);
#if 0
- std::auto_ptr volume(new OrthancVolumeImage(context.GetWebService(), true));
+ std::auto_ptr volume(new OrthancVolumeImage(context_->GetWebService(), true));
if (series.empty())
{
volume->ScheduleLoadInstance(instance);
@@ -187,8 +186,8 @@
widget->AddLayer(new VolumeImageSource(*volume));
- context.AddInteractor(new Interactor(*volume, *widget, projection, 0));
- context.AddSlicedVolume(volume.release());
+ context_->AddInteractor(new Interactor(*volume, *widget, projection, 0));
+ context_->AddSlicedVolume(volume.release());
{
RenderStyle s;
@@ -199,14 +198,14 @@
widget->SetLayerStyle(0, s);
}
#else
- std::auto_ptr ct(new OrthancVolumeImage(context.GetWebService(), false));
+ std::auto_ptr ct(new OrthancVolumeImage(context_->GetWebService(), false));
//ct->ScheduleLoadSeries("15a6f44a-ac7b88fe-19c462d9-dddd918e-b01550d8"); // 0178023P
//ct->ScheduleLoadSeries("dd069910-4f090474-7d2bba07-e5c10783-f9e4fb1d");
//ct->ScheduleLoadSeries("a04ecf01-79b2fc33-58239f7e-ad9db983-28e81afa"); // IBA
//ct->ScheduleLoadSeries("03677739-1d8bca40-db1daf59-d74ff548-7f6fc9c0"); // 0522c0001 TCIA
ct->ScheduleLoadSeries("295e8a13-dfed1320-ba6aebb2-9a13e20f-1b3eb953"); // Captain
- std::auto_ptr pet(new OrthancVolumeImage(context.GetWebService(), true));
+ std::auto_ptr pet(new OrthancVolumeImage(context_->GetWebService(), true));
//pet->ScheduleLoadSeries("48d2997f-8e25cd81-dd715b64-bd79cdcc-e8fcee53"); // 0178023P
//pet->ScheduleLoadSeries("aabad2e7-80702b5d-e599d26c-4f13398e-38d58a9e");
//pet->ScheduleLoadInstance("830a69ff-8e4b5ee3-b7f966c8-bccc20fb-d322dceb"); // IBA 1
@@ -216,7 +215,7 @@
pet->ScheduleLoadInstance("f080888c-0ab7528a-f7d9c28c-84980eb1-ff3b0ae6"); // Captain 1
//pet->ScheduleLoadInstance("4f78055b-6499a2c5-1e089290-394acc05-3ec781c1"); // Captain 2
- std::auto_ptr rtStruct(new StructureSetLoader(context.GetWebService()));
+ std::auto_ptr rtStruct(new StructureSetLoader(context_->GetWebService()));
//rtStruct->ScheduleLoadInstance("c2ebc17b-6b3548db-5e5da170-b8ecab71-ea03add3"); // 0178023P
//rtStruct->ScheduleLoadInstance("54460695-ba3885ee-ddf61ac0-f028e31d-a6e474d9"); // IBA
//rtStruct->ScheduleLoadInstance("17cd032b-ad92a438-ca05f06a-f9e96668-7e3e9e20"); // 0522c0001 TCIA
@@ -226,12 +225,12 @@
widget->AddLayer(new VolumeImageSource(*pet));
widget->AddLayer(new DicomStructureSetRendererFactory(*rtStruct));
- context.AddInteractor(new Interactor(*pet, *widget, projection, 1));
- //context.AddInteractor(new VolumeImageInteractor(*ct, *widget, projection));
+ context_->AddInteractor(new Interactor(*pet, *widget, projection, 1));
+ //context_->AddInteractor(new VolumeImageInteractor(*ct, *widget, projection));
- context.AddSlicedVolume(ct.release());
- context.AddSlicedVolume(pet.release());
- context.AddVolumeLoader(rtStruct.release());
+ context_->AddSlicedVolume(ct.release());
+ context_->AddSlicedVolume(pet.release());
+ context_->AddVolumeLoader(rtStruct.release());
{
RenderStyle s;
@@ -263,7 +262,7 @@
statusBar.SetMessage("Use the keys \"c\" to draw circles");
widget->SetTransmitMouseOver(true);
- context.SetCentralWidget(widget.release());
+ context_->SetCentralWidget(widget.release());
}
};
}
diff -r 3a8bac805352 -r 36ebe6ec8fe8 Applications/Samples/TestPatternApplication.h
--- a/Applications/Samples/TestPatternApplication.h Tue Aug 28 21:00:35 2018 +0200
+++ b/Applications/Samples/TestPatternApplication.h Thu Aug 30 16:56:08 2018 +0200
@@ -34,7 +34,7 @@
class TestPatternApplication : public SampleApplicationBase
{
public:
- virtual void DeclareCommandLineOptions(boost::program_options::options_description& options)
+ virtual void DeclareStartupOptions(boost::program_options::options_description& options)
{
boost::program_options::options_description generic("Sample options");
generic.add_options()
@@ -44,8 +44,7 @@
options.add(generic);
}
- virtual void Initialize(BasicApplicationContext& context,
- IStatusBar& statusBar,
+ virtual void Initialize(IStatusBar& statusBar,
const boost::program_options::variables_map& parameters)
{
using namespace OrthancStone;
@@ -56,8 +55,8 @@
layout->AddWidget(new TestCairoWidget(parameters["animate"].as()));
layout->AddWidget(new TestWorldSceneWidget(parameters["animate"].as()));
- context.SetCentralWidget(layout.release());
- context.SetUpdateDelay(25); // If animation, update the content each 25ms
+ context_->SetCentralWidget(layout.release());
+ context_->SetUpdateDelay(25); // If animation, update the content each 25ms
}
};
}
diff -r 3a8bac805352 -r 36ebe6ec8fe8 Applications/Samples/Web/index.html
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/Applications/Samples/Web/index.html Thu Aug 30 16:56:08 2018 +0200
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
+
+
+
+ Wasm Samples
+
+
+
+
+
+
+
\ No newline at end of file
diff -r 3a8bac805352 -r 36ebe6ec8fe8 Applications/Samples/Web/samples-styles.css
diff -r 3a8bac805352 -r 36ebe6ec8fe8 Applications/Samples/Web/simple-viewer.html
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/Applications/Samples/Web/simple-viewer.html Thu Aug 30 16:56:08 2018 +0200
@@ -0,0 +1,34 @@
+
+
+
+
+
+
+
+
+
+
+
+ Simple Viewer
+
+
+
+
+
+
+
+
+
+
+
+
+
+ line
+ circle
+
+
+
+
+
+
+
\ No newline at end of file
diff -r 3a8bac805352 -r 36ebe6ec8fe8 Applications/Samples/Web/simple-viewer.ts
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/Applications/Samples/Web/simple-viewer.ts Thu Aug 30 16:56:08 2018 +0200
@@ -0,0 +1,39 @@
+///
+
+InitializeWasmApplication("OrthancStoneSimpleViewer", "/orthanc");
+
+function SelectTool(toolName: string) {
+ SendMessageToStoneApplication("select-tool:" + toolName);
+}
+
+function PerformAction(actionName: string) {
+ SendMessageToStoneApplication("perform-action:" + actionName);
+}
+
+//initializes the buttons
+//-----------------------
+// install "SelectTool" handlers
+document.querySelectorAll("[tool-selector]").forEach((e) => {
+ console.log(e);
+ (e as HTMLInputElement).addEventListener("click", () => {
+ console.log(e);
+ SelectTool(e.attributes["tool-selector"].value);
+ });
+});
+
+// install "PerformAction" handlers
+document.querySelectorAll("[action-trigger]").forEach((e) => {
+ (e as HTMLInputElement).addEventListener("click", () => {
+ PerformAction(e.attributes["action-trigger"].value);
+ });
+});
+
+// this method is called "from the C++ code" when the StoneApplication is updated.
+// it can be used to update the UI of the application
+function UpdateWebApplication(statusUpdateMessage: string) {
+ console.log(statusUpdateMessage);
+
+ if (statusUpdateMessage.startsWith("series-description=")) {
+ document.getElementById("series-description").innerText = statusUpdateMessage.split("=")[1];
+ }
+}
diff -r 3a8bac805352 -r 36ebe6ec8fe8 Applications/Samples/Web/tsconfig-samples.json
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/Applications/Samples/Web/tsconfig-samples.json Thu Aug 30 16:56:08 2018 +0200
@@ -0,0 +1,11 @@
+{
+ "extends" : "../../../Platforms/Wasm/tsconfig-stone",
+ "compilerOptions": {
+ "sourceMap": false,
+ "lib" : [
+ "es2017",
+ "dom",
+ "dom.iterable"
+ ]
+ }
+}
diff -r 3a8bac805352 -r 36ebe6ec8fe8 Applications/Samples/Web/tsconfig-simple-viewer.json
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/Applications/Samples/Web/tsconfig-simple-viewer.json Thu Aug 30 16:56:08 2018 +0200
@@ -0,0 +1,10 @@
+{
+ "extends" : "./tsconfig-samples",
+ "compilerOptions": {
+ "outFile": "../../../Platforms/Wasm/build-web/app-simple-viewer.js"
+ },
+ "include" : [
+ "simple-viewer.ts",
+ "common-samples.ts"
+ ]
+}
\ No newline at end of file
diff -r 3a8bac805352 -r 36ebe6ec8fe8 Applications/Samples/samples-library.js
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/Applications/Samples/samples-library.js Thu Aug 30 16:56:08 2018 +0200
@@ -0,0 +1,8 @@
+// this file contains the JS method you want to expose to C++ code
+
+// mergeInto(LibraryManager.library, {
+// ScheduleRedraw: function() {
+// ScheduleRedraw();
+// }
+// });
+
\ No newline at end of file
diff -r 3a8bac805352 -r 36ebe6ec8fe8 Applications/Sdl/BasicSdlApplication.cpp
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/Applications/Sdl/BasicSdlApplication.cpp Thu Aug 30 16:56:08 2018 +0200
@@ -0,0 +1,127 @@
+/**
+ * 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 .
+ **/
+
+
+#if ORTHANC_ENABLE_SDL != 1
+#error this file shall be included only with the ORTHANC_ENABLE_SDL set to 1
+#endif
+
+#include "BasicSdlApplication.h"
+#include
+
+#include "../../Framework/Toolbox/MessagingToolbox.h"
+#include "SdlEngine.h"
+
+#include
+#include
+#include
+#include
+#include "../../Platforms/Generic/OracleWebService.h"
+
+namespace OrthancStone
+{
+ void BasicSdlApplication::Initialize()
+ {
+ SdlWindow::GlobalInitialize();
+ }
+
+ void BasicSdlApplication::DeclareCommandLineOptions(boost::program_options::options_description& options)
+ {
+ boost::program_options::options_description sdl("SDL options");
+ sdl.add_options()
+ ("width", boost::program_options::value()->default_value(1024), "Initial width of the SDL window")
+ ("height", boost::program_options::value()->default_value(768), "Initial height of the SDL window")
+ ("opengl", boost::program_options::value()->default_value(true), "Enable OpenGL in SDL")
+ ;
+
+ options.add(sdl);
+ }
+
+ void BasicSdlApplication::ParseCommandLineOptions(const boost::program_options::variables_map& parameters)
+ {
+ if (!parameters.count("width") ||
+ !parameters.count("height") ||
+ !parameters.count("opengl"))
+ {
+ LOG(ERROR) << "Parameter \"width\", \"height\" or \"opengl\" is missing";
+ throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
+ }
+
+ int w = parameters["width"].as();
+ int h = parameters["height"].as();
+ if (w <= 0 || h <= 0)
+ {
+ LOG(ERROR) << "Parameters \"width\" and \"height\" must be positive";
+ throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
+ }
+
+ width_ = static_cast(w);
+ height_ = static_cast(h);
+ LOG(WARNING) << "Initial display size: " << width_ << "x" << height_;
+
+ enableOpenGl_ = parameters["opengl"].as();
+ if (enableOpenGl_)
+ {
+ LOG(WARNING) << "OpenGL is enabled, disable it with option \"--opengl=off\" if the application crashes";
+ }
+ else
+ {
+ LOG(WARNING) << "OpenGL is disabled, enable it with option \"--opengl=on\" for best performance";
+ }
+
+ }
+
+ void BasicSdlApplication::Run(BasicNativeApplicationContext& context, const std::string& title, int argc, char* argv[])
+ {
+ /**************************************************************
+ * Run the application inside a SDL window
+ **************************************************************/
+
+ LOG(WARNING) << "Starting the application";
+
+ SdlWindow window(title.c_str(), width_, height_, enableOpenGl_);
+ SdlEngine sdl(window, context);
+
+ {
+ BasicNativeApplicationContext::GlobalMutexLocker locker(context);
+ context.GetCentralViewport().Register(sdl); // (*)
+ }
+
+ context.Start();
+ sdl.Run();
+
+ LOG(WARNING) << "Stopping the application";
+
+ // Don't move the "Stop()" command below out of the block,
+ // otherwise the application might crash, because the
+ // "SdlEngine" is an observer of the viewport (*) and the
+ // update thread started by "context.Start()" would call a
+ // destructed object (the "SdlEngine" is deleted with the
+ // lexical scope).
+ context.Stop();
+ }
+
+ void BasicSdlApplication::Finalize()
+ {
+ SdlWindow::GlobalFinalize();
+ }
+
+
+}
diff -r 3a8bac805352 -r 36ebe6ec8fe8 Applications/Sdl/BasicSdlApplication.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/Applications/Sdl/BasicSdlApplication.h Thu Aug 30 16:56:08 2018 +0200
@@ -0,0 +1,47 @@
+/**
+ * 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 .
+ **/
+
+
+#pragma once
+
+#include "../Generic/BasicNativeApplication.h"
+
+#if ORTHANC_ENABLE_SDL != 1
+#error this file shall be included only with the ORTHANC_ENABLE_SDL set to 1
+#endif
+
+#include // Necessary to avoid undefined reference to `SDL_main'
+
+namespace OrthancStone
+{
+ class BasicSdlApplication : public BasicNativeApplication
+ {
+ unsigned int width_;
+ unsigned int height_;
+ bool enableOpenGl_;
+ public:
+ virtual void Initialize();
+ virtual void DeclareCommandLineOptions(boost::program_options::options_description& options);
+ virtual void Run(BasicNativeApplicationContext& context, const std::string& title, int argc, char* argv[]);
+ virtual void ParseCommandLineOptions(const boost::program_options::variables_map& parameters);
+ virtual void Finalize();
+ };
+
+}
diff -r 3a8bac805352 -r 36ebe6ec8fe8 Applications/Sdl/SdlEngine.cpp
--- a/Applications/Sdl/SdlEngine.cpp Tue Aug 28 21:00:35 2018 +0200
+++ b/Applications/Sdl/SdlEngine.cpp Thu Aug 30 16:56:08 2018 +0200
@@ -29,11 +29,10 @@
namespace OrthancStone
{
- void SdlEngine::SetSize(BasicApplicationContext::ViewportLocker& locker,
- unsigned int width,
+ void SdlEngine::SetSize(unsigned int width,
unsigned int height)
{
- locker.GetViewport().SetSize(width, height);
+ context_.GetCentralViewport().SetSize(width, height);
surface_.SetSize(width, height);
}
@@ -42,8 +41,8 @@
{
if (viewportChanged_)
{
- BasicApplicationContext::ViewportLocker locker(context_);
- surface_.Render(locker.GetViewport());
+ BasicNativeApplicationContext::GlobalMutexLocker locker(context_);
+ surface_.Render(context_.GetCentralViewport());
viewportChanged_ = false;
}
@@ -99,7 +98,7 @@
SdlEngine::SdlEngine(SdlWindow& window,
- BasicApplicationContext& context) :
+ BasicNativeApplicationContext& context) :
window_(window),
context_(context),
surface_(window),
@@ -119,9 +118,9 @@
const uint8_t* keyboardState = SDL_GetKeyboardState(&scancodeCount);
{
- BasicApplicationContext::ViewportLocker locker(context_);
- SetSize(locker, window_.GetWidth(), window_.GetHeight());
- locker.GetViewport().SetDefaultView();
+ BasicNativeApplicationContext::GlobalMutexLocker locker(context_);
+ SetSize(window_.GetWidth(), window_.GetHeight());
+ context_.GetCentralViewport().SetDefaultView();
}
bool stop = false;
@@ -134,7 +133,7 @@
while (!stop &&
SDL_PollEvent(&event))
{
- BasicApplicationContext::ViewportLocker locker(context_);
+ BasicNativeApplicationContext::GlobalMutexLocker locker(context_);
if (event.type == SDL_QUIT)
{
@@ -148,15 +147,15 @@
switch (event.button.button)
{
case SDL_BUTTON_LEFT:
- locker.GetViewport().MouseDown(MouseButton_Left, event.button.x, event.button.y, modifiers);
+ context_.GetCentralViewport().MouseDown(MouseButton_Left, event.button.x, event.button.y, modifiers);
break;
case SDL_BUTTON_RIGHT:
- locker.GetViewport().MouseDown(MouseButton_Right, event.button.x, event.button.y, modifiers);
+ context_.GetCentralViewport().MouseDown(MouseButton_Right, event.button.x, event.button.y, modifiers);
break;
case SDL_BUTTON_MIDDLE:
- locker.GetViewport().MouseDown(MouseButton_Middle, event.button.x, event.button.y, modifiers);
+ context_.GetCentralViewport().MouseDown(MouseButton_Middle, event.button.x, event.button.y, modifiers);
break;
default:
@@ -165,26 +164,26 @@
}
else if (event.type == SDL_MOUSEMOTION)
{
- locker.GetViewport().MouseMove(event.button.x, event.button.y);
+ context_.GetCentralViewport().MouseMove(event.button.x, event.button.y);
}
else if (event.type == SDL_MOUSEBUTTONUP)
{
- locker.GetViewport().MouseUp();
+ context_.GetCentralViewport().MouseUp();
}
else if (event.type == SDL_WINDOWEVENT)
{
switch (event.window.event)
{
case SDL_WINDOWEVENT_LEAVE:
- locker.GetViewport().MouseLeave();
+ context_.GetCentralViewport().MouseLeave();
break;
case SDL_WINDOWEVENT_ENTER:
- locker.GetViewport().MouseEnter();
+ context_.GetCentralViewport().MouseEnter();
break;
case SDL_WINDOWEVENT_SIZE_CHANGED:
- SetSize(locker, event.window.data1, event.window.data2);
+ SetSize(event.window.data1, event.window.data2);
break;
default:
@@ -200,11 +199,11 @@
if (event.wheel.y > 0)
{
- locker.GetViewport().MouseWheel(MouseWheelDirection_Up, x, y, modifiers);
+ context_.GetCentralViewport().MouseWheel(MouseWheelDirection_Up, x, y, modifiers);
}
else if (event.wheel.y < 0)
{
- locker.GetViewport().MouseWheel(MouseWheelDirection_Down, x, y, modifiers);
+ context_.GetCentralViewport().MouseWheel(MouseWheelDirection_Down, x, y, modifiers);
}
}
else if (event.type == SDL_KEYDOWN &&
@@ -214,50 +213,50 @@
switch (event.key.keysym.sym)
{
- case SDLK_a: locker.GetViewport().KeyPressed('a', modifiers); break;
- case SDLK_b: locker.GetViewport().KeyPressed('b', modifiers); break;
- case SDLK_c: locker.GetViewport().KeyPressed('c', modifiers); break;
- case SDLK_d: locker.GetViewport().KeyPressed('d', modifiers); break;
- case SDLK_e: locker.GetViewport().KeyPressed('e', modifiers); break;
+ case SDLK_a: context_.GetCentralViewport().KeyPressed('a', modifiers); break;
+ case SDLK_b: context_.GetCentralViewport().KeyPressed('b', modifiers); break;
+ case SDLK_c: context_.GetCentralViewport().KeyPressed('c', modifiers); break;
+ case SDLK_d: context_.GetCentralViewport().KeyPressed('d', modifiers); break;
+ case SDLK_e: context_.GetCentralViewport().KeyPressed('e', modifiers); break;
case SDLK_f: window_.ToggleMaximize(); break;
- case SDLK_g: locker.GetViewport().KeyPressed('g', modifiers); break;
- case SDLK_h: locker.GetViewport().KeyPressed('h', modifiers); break;
- case SDLK_i: locker.GetViewport().KeyPressed('i', modifiers); break;
- case SDLK_j: locker.GetViewport().KeyPressed('j', modifiers); break;
- case SDLK_k: locker.GetViewport().KeyPressed('k', modifiers); break;
- case SDLK_l: locker.GetViewport().KeyPressed('l', modifiers); break;
- case SDLK_m: locker.GetViewport().KeyPressed('m', modifiers); break;
- case SDLK_n: locker.GetViewport().KeyPressed('n', modifiers); break;
- case SDLK_o: locker.GetViewport().KeyPressed('o', modifiers); break;
- case SDLK_p: locker.GetViewport().KeyPressed('p', modifiers); break;
+ case SDLK_g: context_.GetCentralViewport().KeyPressed('g', modifiers); break;
+ case SDLK_h: context_.GetCentralViewport().KeyPressed('h', modifiers); break;
+ case SDLK_i: context_.GetCentralViewport().KeyPressed('i', modifiers); break;
+ case SDLK_j: context_.GetCentralViewport().KeyPressed('j', modifiers); break;
+ case SDLK_k: context_.GetCentralViewport().KeyPressed('k', modifiers); break;
+ case SDLK_l: context_.GetCentralViewport().KeyPressed('l', modifiers); break;
+ case SDLK_m: context_.GetCentralViewport().KeyPressed('m', modifiers); break;
+ case SDLK_n: context_.GetCentralViewport().KeyPressed('n', modifiers); break;
+ case SDLK_o: context_.GetCentralViewport().KeyPressed('o', modifiers); break;
+ case SDLK_p: context_.GetCentralViewport().KeyPressed('p', modifiers); break;
case SDLK_q: stop = true; break;
- case SDLK_r: locker.GetViewport().KeyPressed('r', modifiers); break;
- case SDLK_s: locker.GetViewport().KeyPressed('s', modifiers); break;
- case SDLK_t: locker.GetViewport().KeyPressed('t', modifiers); break;
- case SDLK_u: locker.GetViewport().KeyPressed('u', modifiers); break;
- case SDLK_v: locker.GetViewport().KeyPressed('v', modifiers); break;
- case SDLK_w: locker.GetViewport().KeyPressed('w', modifiers); break;
- case SDLK_x: locker.GetViewport().KeyPressed('x', modifiers); break;
- case SDLK_y: locker.GetViewport().KeyPressed('y', modifiers); break;
- case SDLK_z: locker.GetViewport().KeyPressed('z', modifiers); break;
- case SDLK_KP_0: locker.GetViewport().KeyPressed('0', modifiers); break;
- case SDLK_KP_1: locker.GetViewport().KeyPressed('1', modifiers); break;
- case SDLK_KP_2: locker.GetViewport().KeyPressed('2', modifiers); break;
- case SDLK_KP_3: locker.GetViewport().KeyPressed('3', modifiers); break;
- case SDLK_KP_4: locker.GetViewport().KeyPressed('4', modifiers); break;
- case SDLK_KP_5: locker.GetViewport().KeyPressed('5', modifiers); break;
- case SDLK_KP_6: locker.GetViewport().KeyPressed('6', modifiers); break;
- case SDLK_KP_7: locker.GetViewport().KeyPressed('7', modifiers); break;
- case SDLK_KP_8: locker.GetViewport().KeyPressed('8', modifiers); break;
- case SDLK_KP_9: locker.GetViewport().KeyPressed('9', modifiers); break;
+ case SDLK_r: context_.GetCentralViewport().KeyPressed('r', modifiers); break;
+ case SDLK_s: context_.GetCentralViewport().KeyPressed('s', modifiers); break;
+ case SDLK_t: context_.GetCentralViewport().KeyPressed('t', modifiers); break;
+ case SDLK_u: context_.GetCentralViewport().KeyPressed('u', modifiers); break;
+ case SDLK_v: context_.GetCentralViewport().KeyPressed('v', modifiers); break;
+ case SDLK_w: context_.GetCentralViewport().KeyPressed('w', modifiers); break;
+ case SDLK_x: context_.GetCentralViewport().KeyPressed('x', modifiers); break;
+ case SDLK_y: context_.GetCentralViewport().KeyPressed('y', modifiers); break;
+ case SDLK_z: context_.GetCentralViewport().KeyPressed('z', modifiers); break;
+ case SDLK_KP_0: context_.GetCentralViewport().KeyPressed('0', modifiers); break;
+ case SDLK_KP_1: context_.GetCentralViewport().KeyPressed('1', modifiers); break;
+ case SDLK_KP_2: context_.GetCentralViewport().KeyPressed('2', modifiers); break;
+ case SDLK_KP_3: context_.GetCentralViewport().KeyPressed('3', modifiers); break;
+ case SDLK_KP_4: context_.GetCentralViewport().KeyPressed('4', modifiers); break;
+ case SDLK_KP_5: context_.GetCentralViewport().KeyPressed('5', modifiers); break;
+ case SDLK_KP_6: context_.GetCentralViewport().KeyPressed('6', modifiers); break;
+ case SDLK_KP_7: context_.GetCentralViewport().KeyPressed('7', modifiers); break;
+ case SDLK_KP_8: context_.GetCentralViewport().KeyPressed('8', modifiers); break;
+ case SDLK_KP_9: context_.GetCentralViewport().KeyPressed('9', modifiers); break;
case SDLK_PLUS:
case SDLK_KP_PLUS:
- locker.GetViewport().KeyPressed('+', modifiers); break;
+ context_.GetCentralViewport().KeyPressed('+', modifiers); break;
case SDLK_MINUS:
case SDLK_KP_MINUS:
- locker.GetViewport().KeyPressed('-', modifiers); break;
+ context_.GetCentralViewport().KeyPressed('-', modifiers); break;
default:
break;
diff -r 3a8bac805352 -r 36ebe6ec8fe8 Applications/Sdl/SdlEngine.h
--- a/Applications/Sdl/SdlEngine.h Tue Aug 28 21:00:35 2018 +0200
+++ b/Applications/Sdl/SdlEngine.h Thu Aug 30 16:56:08 2018 +0200
@@ -24,7 +24,7 @@
#if ORTHANC_ENABLE_SDL == 1
#include "SdlCairoSurface.h"
-#include "../BasicApplicationContext.h"
+#include "../Generic/BasicNativeApplicationContext.h"
namespace OrthancStone
{
@@ -32,12 +32,11 @@
{
private:
SdlWindow& window_;
- BasicApplicationContext& context_;
+ BasicNativeApplicationContext& context_;
SdlCairoSurface surface_;
bool viewportChanged_;
- void SetSize(BasicApplicationContext::ViewportLocker& locker,
- unsigned int width,
+ void SetSize(unsigned int width,
unsigned int height);
void RenderFrame();
@@ -47,11 +46,11 @@
public:
SdlEngine(SdlWindow& window,
- BasicApplicationContext& context);
+ BasicNativeApplicationContext& context);
virtual ~SdlEngine();
- virtual void NotifyChange(const IViewport& viewport)
+ virtual void OnViewportContentChanged(const IViewport& viewport)
{
viewportChanged_ = true;
}
diff -r 3a8bac805352 -r 36ebe6ec8fe8 Applications/StoneApplicationContext.cpp
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/Applications/StoneApplicationContext.cpp Thu Aug 30 16:56:08 2018 +0200
@@ -0,0 +1,26 @@
+/**
+ * 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 .
+ **/
+
+
+#include "StoneApplicationContext.h"
+
+namespace OrthancStone
+{
+}
diff -r 3a8bac805352 -r 36ebe6ec8fe8 Applications/StoneApplicationContext.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/Applications/StoneApplicationContext.h Thu Aug 30 16:56:08 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 .
+ **/
+
+
+#pragma once
+
+#include "../Framework/Toolbox/IWebService.h"
+#include "../Framework/Viewport/WidgetViewport.h"
+
+#include
+
+namespace OrthancStone
+{
+ // a StoneApplicationContext contains the services that a StoneApplication
+ // uses and that depends on the environment in which the Application executes.
+ // I.e, the StoneApplicationContext provides a WebService interface such that
+ // the StoneApplication can perform HTTP requests. In a WASM environment,
+ // the WebService is provided by the browser while, in a native environment,
+ // the WebService is provided by the OracleWebService (a C++ Http client)
+ class StoneApplicationContext : public boost::noncopyable
+ {
+
+ protected:
+ IWebService* webService_;
+ public:
+ StoneApplicationContext()
+ : webService_(NULL)
+ {
+ }
+
+ IWebService& GetWebService() {return *webService_;}
+ void SetWebService(IWebService& webService)
+ {
+ webService_ = &webService;
+ }
+
+ virtual ~StoneApplicationContext() {}
+ };
+}
diff -r 3a8bac805352 -r 36ebe6ec8fe8 Applications/Wasm/StartupParametersBuilder.cpp
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/Applications/Wasm/StartupParametersBuilder.cpp Thu Aug 30 16:56:08 2018 +0200
@@ -0,0 +1,43 @@
+#include "StartupParametersBuilder.h"
+
+namespace OrthancStone
+{
+ void StartupParametersBuilder::Clear() {
+ startupParameters_.clear();
+ }
+
+ void StartupParametersBuilder::SetStartupParameter(const char* name, const char* value) {
+ startupParameters_.push_back(std::make_tuple(name, value));
+ }
+
+ void StartupParametersBuilder::GetStartupParameters(boost::program_options::variables_map& parameters, const boost::program_options::options_description& options) {
+
+ const char* argv[startupParameters_.size() + 1];
+ int argCounter = 0;
+ argv[0] = "Toto.exe";
+ argCounter++;
+
+ std::string cmdLine = "";
+ for (StartupParameters::const_iterator it = startupParameters_.begin(); it != startupParameters_.end(); it++) {
+ char* arg = new char[128];
+ snprintf(arg, 128, "--%s=%s", std::get<0>(*it).c_str(), std::get<1>(*it).c_str());
+ argv[argCounter] = arg;
+ cmdLine = cmdLine + " --" + std::get<0>(*it) + "=" + std::get<1>(*it);
+ argCounter++;
+ }
+
+ printf("simulated cmdLine = %s\n", cmdLine.c_str());
+
+ try
+ {
+ boost::program_options::store(boost::program_options::command_line_parser(argCounter, argv).
+ options(options).run(), parameters);
+ boost::program_options::notify(parameters);
+ }
+ catch (boost::program_options::error& e)
+ {
+ printf("Error while parsing the command-line arguments: %s\n", e.what());
+ }
+
+ }
+}
\ No newline at end of file
diff -r 3a8bac805352 -r 36ebe6ec8fe8 Applications/Wasm/StartupParametersBuilder.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/Applications/Wasm/StartupParametersBuilder.h Thu Aug 30 16:56:08 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 .
+ **/
+
+
+#pragma once
+
+#include
+#include
+
+#if ORTHANC_ENABLE_SDL == 1
+#error this file shall be included only with the ORTHANC_ENABLE_SDL set to 0
+#endif
+
+namespace OrthancStone
+{
+ // This class is used to generate boost program options from a dico.
+ // In a Wasm context, startup options are passed as URI arguments that
+ // are then passed to this class as a dico.
+ // This class regenerates a fake command-line and parses it to produce
+ // the same output as if the app was started at command-line.
+ class StartupParametersBuilder
+ {
+ typedef std::list> StartupParameters;
+ StartupParameters startupParameters_;
+
+ public:
+
+ void Clear();
+ void SetStartupParameter(const char* name, const char* value);
+ void GetStartupParameters(boost::program_options::variables_map& parameters_, const boost::program_options::options_description& options);
+ };
+
+}
diff -r 3a8bac805352 -r 36ebe6ec8fe8 Framework/Layers/CircleMeasureTracker.cpp
--- a/Framework/Layers/CircleMeasureTracker.cpp Tue Aug 28 21:00:35 2018 +0200
+++ b/Framework/Layers/CircleMeasureTracker.cpp Thu Aug 30 16:56:08 2018 +0200
@@ -76,8 +76,10 @@
if (fontSize_ != 0)
{
cairo_move_to(cr, x, y);
+#if ORTHANC_ENABLE_NATIVE==1 // text rendering currently fails in wasm
CairoFont font("sans-serif", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL);
font.Draw(context, FormatRadius(), static_cast(fontSize_) / zoom);
+#endif
}
}
diff -r 3a8bac805352 -r 36ebe6ec8fe8 Framework/Layers/DicomStructureSetRendererFactory.h
--- a/Framework/Layers/DicomStructureSetRendererFactory.h Tue Aug 28 21:00:35 2018 +0200
+++ b/Framework/Layers/DicomStructureSetRendererFactory.h Thu Aug 30 16:56:08 2018 +0200
@@ -37,21 +37,22 @@
{
LayerSourceBase::NotifyGeometryReady();
}
-
+
virtual void NotifyGeometryError(const IVolumeLoader& loader)
{
LayerSourceBase::NotifyGeometryError();
}
-
+
virtual void NotifyContentChange(const IVolumeLoader& loader)
{
LayerSourceBase::NotifyContentChange();
}
-
+
StructureSetLoader& loader_;
public:
- DicomStructureSetRendererFactory(StructureSetLoader& loader) :
+ DicomStructureSetRendererFactory(MessageBroker& broker, StructureSetLoader& loader) :
+ LayerSourceBase(broker),
loader_(loader)
{
loader_.Register(*this);
diff -r 3a8bac805352 -r 36ebe6ec8fe8 Framework/Layers/ILayerSource.h
--- a/Framework/Layers/ILayerSource.h Tue Aug 28 21:00:35 2018 +0200
+++ b/Framework/Layers/ILayerSource.h Thu Aug 30 16:56:08 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 .
**/
@@ -23,47 +23,80 @@
#include "ILayerRenderer.h"
#include "../Toolbox/Slice.h"
+#include "../../Framework/Messages/IObservable.h"
+#include "../../Framework/Messages/IMessage.h"
namespace OrthancStone
{
- class ILayerSource : public boost::noncopyable
+ class ILayerSource : public IObservable
{
public:
- class IObserver : public boost::noncopyable
+ struct SliceChangedMessage : public IMessage
+ {
+ const Slice& slice_;
+ SliceChangedMessage(const Slice& slice)
+ : IMessage(MessageType_LayerSource_SliceChanged),
+ slice_(slice)
+ {
+ }
+ };
+
+ struct LayerReadyMessage : public IMessage
{
- public:
- virtual ~IObserver()
+ std::auto_ptr& layer_;
+ const CoordinateSystem3D& slice_;
+ bool isError_;
+
+ LayerReadyMessage(std::auto_ptr& layer,
+ const CoordinateSystem3D& slice,
+ bool isError) // TODO Shouldn't this be separate as NotifyLayerError?
+ : IMessage(MessageType_LayerSource_LayerReady),
+ layer_(layer),
+ slice_(slice),
+ isError_(isError)
{
}
+ };
- // Triggered as soon as the source has enough information to
- // answer to "GetExtent()"
- virtual void NotifyGeometryReady(const ILayerSource& source) = 0;
-
- virtual void NotifyGeometryError(const ILayerSource& source) = 0;
-
- // Triggered if the content of several slices in the source
- // volume has changed
- virtual void NotifyContentChange(const ILayerSource& source) = 0;
+ // class IObserver : public boost::noncopyable
+ // {
+ // public:
+ // virtual ~IObserver()
+ // {
+ // }
+
+ // // Triggered as soon as the source has enough information to
+ // // answer to "GetExtent()"
+ // virtual void NotifyGeometryReady(const ILayerSource& source) = 0;
+
+ // virtual void NotifyGeometryError(const ILayerSource& source) = 0;
- // Triggered if the content of some individual slice in the
- // source volume has changed
- virtual void NotifySliceChange(const ILayerSource& source,
- const Slice& slice) = 0;
-
- // The layer must be deleted by the observer that releases the
- // std::auto_ptr
- virtual void NotifyLayerReady(std::auto_ptr& layer,
- const ILayerSource& source,
- const CoordinateSystem3D& slice,
- bool isError) = 0; // TODO Shouldn't this be separate as NotifyLayerError?
- };
+ // // Triggered if the content of several slices in the source
+ // // volume has changed
+ // virtual void NotifyContentChange(const ILayerSource& source) = 0;
+
+ // // Triggered if the content of some individual slice in the
+ // // source volume has changed
+ // virtual void NotifySliceChange(const ILayerSource& source,
+ // const Slice& slice) = 0;
+
+ // // The layer must be deleted by the observer that releases the
+ // // std::auto_ptr
+ // virtual void NotifyLayerReady(std::auto_ptr& layer,
+ // const ILayerSource& source,
+ // const CoordinateSystem3D& slice,
+ // bool isError) = 0; // TODO Shouldn't this be separate as NotifyLayerError?
+ // };
+ ILayerSource(MessageBroker& broker)
+ : IObservable(broker)
+ {}
+
virtual ~ILayerSource()
{
}
- virtual void Register(IObserver& observer) = 0;
+ // virtual void Register(IObserver& observer) = 0;
virtual bool GetExtent(std::vector& points,
const CoordinateSystem3D& viewportSlice) = 0;
diff -r 3a8bac805352 -r 36ebe6ec8fe8 Framework/Layers/LayerSourceBase.cpp
--- a/Framework/Layers/LayerSourceBase.cpp Tue Aug 28 21:00:35 2018 +0200
+++ b/Framework/Layers/LayerSourceBase.cpp Thu Aug 30 16:56:08 2018 +0200
@@ -25,63 +25,32 @@
namespace OrthancStone
{
- namespace
- {
- class LayerReadyFunctor : public boost::noncopyable
- {
- private:
- std::auto_ptr layer_;
- const CoordinateSystem3D& slice_;
- bool isError_;
-
- public:
- LayerReadyFunctor(ILayerRenderer* layer,
- const CoordinateSystem3D& slice,
- bool isError) :
- layer_(layer),
- slice_(slice),
- isError_(isError)
- {
- }
-
- void operator() (ILayerSource::IObserver& observer,
- const ILayerSource& source)
- {
- observer.NotifyLayerReady(layer_, source, slice_, isError_);
- }
- };
- }
-
void LayerSourceBase::NotifyGeometryReady()
{
- observers_.Apply(*this, &IObserver::NotifyGeometryReady);
+ EmitMessage(IMessage(MessageType_LayerSource_GeometryReady));
}
void LayerSourceBase::NotifyGeometryError()
{
- observers_.Apply(*this, &IObserver::NotifyGeometryError);
- }
+ EmitMessage(IMessage(MessageType_LayerSource_GeometryError));
+ }
void LayerSourceBase::NotifyContentChange()
{
- observers_.Apply(*this, &IObserver::NotifyContentChange);
+ EmitMessage(IMessage(MessageType_LayerSource_ContentChanged));
}
void LayerSourceBase::NotifySliceChange(const Slice& slice)
{
- observers_.Apply(*this, &IObserver::NotifySliceChange, slice);
+ EmitMessage(ILayerSource::SliceChangedMessage(slice));
}
void LayerSourceBase::NotifyLayerReady(ILayerRenderer* layer,
const CoordinateSystem3D& slice,
bool isError)
{
- LayerReadyFunctor functor(layer, slice, isError);
- observers_.Notify(*this, functor);
+ std::auto_ptr renderer(layer);
+ EmitMessage(ILayerSource::LayerReadyMessage(renderer, slice, isError));
}
- void LayerSourceBase::Register(IObserver& observer)
- {
- observers_.Register(observer);
- }
}
diff -r 3a8bac805352 -r 36ebe6ec8fe8 Framework/Layers/LayerSourceBase.h
--- a/Framework/Layers/LayerSourceBase.h Tue Aug 28 21:00:35 2018 +0200
+++ b/Framework/Layers/LayerSourceBase.h Thu Aug 30 16:56:08 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 .
**/
@@ -28,11 +28,6 @@
{
class LayerSourceBase : public ILayerSource
{
- private:
- typedef ObserversRegistry Observers;
-
- Observers observers_;
-
protected:
void NotifyGeometryReady();
@@ -46,7 +41,15 @@
const CoordinateSystem3D& slice,
bool isError);
- public:
- virtual void Register(IObserver& observer);
+ LayerSourceBase(MessageBroker& broker)
+ : ILayerSource(broker)
+ {
+ DeclareEmittableMessage(MessageType_LayerSource_GeometryReady);
+ DeclareEmittableMessage(MessageType_LayerSource_GeometryError);
+ DeclareEmittableMessage(MessageType_LayerSource_ContentChanged);
+ DeclareEmittableMessage(MessageType_LayerSource_SliceChanged);
+ DeclareEmittableMessage(MessageType_LayerSource_LayerReady);
+ }
+
};
}
diff -r 3a8bac805352 -r 36ebe6ec8fe8 Framework/Layers/LineMeasureTracker.cpp
--- a/Framework/Layers/LineMeasureTracker.cpp Tue Aug 28 21:00:35 2018 +0200
+++ b/Framework/Layers/LineMeasureTracker.cpp Thu Aug 30 16:56:08 2018 +0200
@@ -63,8 +63,10 @@
if (fontSize_ != 0)
{
cairo_move_to(cr, x2_, y2_ - static_cast(fontSize_) / zoom);
+#if ORTHANC_ENABLE_NATIVE==1 // text rendering currently fails in wasm
CairoFont font("sans-serif", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL);
font.Draw(context, FormatLength(), static_cast(fontSize_) / zoom);
+#endif
}
}
diff -r 3a8bac805352 -r 36ebe6ec8fe8 Framework/Layers/OrthancFrameLayerSource.cpp
--- a/Framework/Layers/OrthancFrameLayerSource.cpp Tue Aug 28 21:00:35 2018 +0200
+++ b/Framework/Layers/OrthancFrameLayerSource.cpp Thu Aug 30 16:56:08 2018 +0200
@@ -31,47 +31,59 @@
namespace OrthancStone
{
- void OrthancFrameLayerSource::NotifyGeometryReady(const OrthancSlicesLoader& loader)
+ void OrthancFrameLayerSource::HandleMessage(IObservable& from, const IMessage& message)
{
- if (loader.GetSliceCount() > 0)
+ switch (message.GetType())
+ {
+ case MessageType_SliceLoader_GeometryReady:
+ {
+ const OrthancSlicesLoader& loader = dynamic_cast(from);
+ if (loader.GetSliceCount() > 0)
+ {
+ LayerSourceBase::NotifyGeometryReady();
+ }
+ else
+ {
+ LayerSourceBase::NotifyGeometryError();
+ }
+
+ }; break;
+ case MessageType_SliceLoader_GeometryError:
{
- LayerSourceBase::NotifyGeometryReady();
- }
- else
+ const OrthancSlicesLoader& loader = dynamic_cast(from);
+ LayerSourceBase::NotifyGeometryError();
+ }; break;
+ case MessageType_SliceLoader_ImageReady:
{
- LayerSourceBase::NotifyGeometryError();
+ const OrthancSlicesLoader::SliceImageReadyMessage& msg = dynamic_cast(message);
+ bool isFull = (msg.effectiveQuality_ == SliceImageQuality_FullPng || msg.effectiveQuality_ == SliceImageQuality_FullPam);
+ LayerSourceBase::NotifyLayerReady(FrameRenderer::CreateRenderer(msg.image_.release(), msg.slice_, isFull),
+ msg.slice_.GetGeometry(), false);
+
+ }; break;
+ case MessageType_SliceLoader_ImageError:
+ {
+ const OrthancSlicesLoader::SliceImageErrorMessage& msg = dynamic_cast(message);
+ LayerSourceBase::NotifyLayerReady(NULL, msg.slice_.GetGeometry(), true);
+ }; break;
+ default:
+ VLOG("unhandled message type" << message.GetType());
}
}
- void OrthancFrameLayerSource::NotifyGeometryError(const OrthancSlicesLoader& loader)
- {
- LayerSourceBase::NotifyGeometryError();
- }
- void OrthancFrameLayerSource::NotifySliceImageReady(const OrthancSlicesLoader& loader,
- unsigned int sliceIndex,
- const Slice& slice,
- std::auto_ptr& image,
- SliceImageQuality quality)
+ OrthancFrameLayerSource::OrthancFrameLayerSource(MessageBroker& broker, IWebService& orthanc) :
+ LayerSourceBase(broker),
+ IObserver(broker),
+ //OrthancSlicesLoader::ISliceLoaderObserver(broker),
+ loader_(broker, orthanc),
+ quality_(SliceImageQuality_FullPng)
{
- bool isFull = (quality == SliceImageQuality_Full);
- LayerSourceBase::NotifyLayerReady(FrameRenderer::CreateRenderer(image.release(), slice, isFull),
- slice.GetGeometry(), false);
- }
-
- void OrthancFrameLayerSource::NotifySliceImageError(const OrthancSlicesLoader& loader,
- unsigned int sliceIndex,
- const Slice& slice,
- SliceImageQuality quality)
- {
- LayerSourceBase::NotifyLayerReady(NULL, slice.GetGeometry(), true);
- }
-
-
- OrthancFrameLayerSource::OrthancFrameLayerSource(IWebService& orthanc) :
- loader_(*this, orthanc),
- quality_(SliceImageQuality_Full)
- {
+ DeclareHandledMessage(MessageType_SliceLoader_GeometryReady);
+ DeclareHandledMessage(MessageType_SliceLoader_GeometryError);
+ DeclareHandledMessage(MessageType_SliceLoader_ImageReady);
+ DeclareHandledMessage(MessageType_SliceLoader_ImageError);
+ loader_.RegisterObserver(*this);
}
diff -r 3a8bac805352 -r 36ebe6ec8fe8 Framework/Layers/OrthancFrameLayerSource.h
--- a/Framework/Layers/OrthancFrameLayerSource.h Tue Aug 28 21:00:35 2018 +0200
+++ b/Framework/Layers/OrthancFrameLayerSource.h Thu Aug 30 16:56:08 2018 +0200
@@ -27,31 +27,20 @@
namespace OrthancStone
{
+ // this class is in charge of loading a Frame.
+ // once it's been loaded (first the geometry and then the image),
+ // messages are sent to observers so they can use it
class OrthancFrameLayerSource :
public LayerSourceBase,
- private OrthancSlicesLoader::ICallback
+ public IObserver
+ //private OrthancSlicesLoader::ISliceLoaderObserver
{
private:
OrthancSlicesLoader loader_;
SliceImageQuality quality_;
- virtual void NotifyGeometryReady(const OrthancSlicesLoader& loader);
-
- virtual void NotifyGeometryError(const OrthancSlicesLoader& loader);
-
- virtual void NotifySliceImageReady(const OrthancSlicesLoader& loader,
- unsigned int sliceIndex,
- const Slice& slice,
- std::auto_ptr& image,
- SliceImageQuality quality);
-
- virtual void NotifySliceImageError(const OrthancSlicesLoader& loader,
- unsigned int sliceIndex,
- const Slice& slice,
- SliceImageQuality quality);
-
public:
- OrthancFrameLayerSource(IWebService& orthanc);
+ OrthancFrameLayerSource(MessageBroker& broker, IWebService& orthanc);
void LoadSeries(const std::string& seriesId);
@@ -79,5 +68,7 @@
const CoordinateSystem3D& viewportSlice);
virtual void ScheduleLayerCreation(const CoordinateSystem3D& viewportSlice);
+
+ virtual void HandleMessage(IObservable& from, const IMessage& message);
};
}
diff -r 3a8bac805352 -r 36ebe6ec8fe8 Framework/Messages/IMessage.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/Framework/Messages/IMessage.h Thu Aug 30 16:56:08 2018 +0200
@@ -0,0 +1,42 @@
+/**
+ * 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 .
+ **/
+
+
+#pragma once
+
+#include "MessageType.h"
+
+#include
+
+namespace OrthancStone {
+
+ struct IMessage : public boost::noncopyable
+ {
+ MessageType messageType_;
+ public:
+ IMessage(const MessageType& messageType)
+ : messageType_(messageType)
+ {}
+ virtual ~IMessage() {}
+
+ MessageType GetType() const {return messageType_;}
+ };
+
+}
diff -r 3a8bac805352 -r 36ebe6ec8fe8 Framework/Messages/IObservable.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/Framework/Messages/IObservable.h Thu Aug 30 16:56:08 2018 +0200
@@ -0,0 +1,111 @@
+/**
+ * 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 .
+ **/
+
+
+#pragma once
+
+#include
+#include
+#include
+#include
+
+#include "MessageBroker.h"
+#include "MessageType.h"
+#include "IObserver.h"
+
+namespace OrthancStone {
+
+ class MessageNotDeclaredException : public std::logic_error
+ {
+ MessageType messageType_;
+ public:
+ MessageNotDeclaredException(MessageType messageType)
+ : std::logic_error("Message not declared by observer."),
+ messageType_(messageType)
+ {
+ }
+ };
+
+ class IObservable : public boost::noncopyable
+ {
+ protected:
+ MessageBroker& broker_;
+
+ std::set observers_;
+ std::set emittableMessages_;
+
+ public:
+
+ IObservable(MessageBroker& broker)
+ : broker_(broker)
+ {
+ }
+ virtual ~IObservable()
+ {
+ }
+
+ void EmitMessage(const IMessage& message)
+ {
+ if (emittableMessages_.find(message.GetType()) == emittableMessages_.end())
+ {
+ throw MessageNotDeclaredException(message.GetType());
+ }
+
+ broker_.EmitMessage(*this, observers_, message);
+ }
+
+ void RegisterObserver(IObserver& observer)
+ {
+ CheckObserverDeclaredAllObservableMessages(observer);
+ observers_.insert(&observer);
+ }
+
+ void UnregisterObserver(IObserver& observer)
+ {
+ observers_.erase(&observer);
+ }
+
+ const std::set& GetEmittableMessages() const
+ {
+ return emittableMessages_;
+ }
+
+ protected:
+
+ void DeclareEmittableMessage(MessageType messageType)
+ {
+ emittableMessages_.insert(messageType);
+ }
+
+ void CheckObserverDeclaredAllObservableMessages(IObserver& observer)
+ {
+ for (std::set::const_iterator it = emittableMessages_.begin(); it != emittableMessages_.end(); it++)
+ {
+ // the observer must have "declared" all observable messages
+ if (observer.GetHandledMessages().find(*it) == observer.GetHandledMessages().end()
+ && observer.GetIgnoredMessages().find(*it) == observer.GetIgnoredMessages().end())
+ {
+ throw MessageNotDeclaredException(*it);
+ }
+ }
+ }
+ };
+
+}
diff -r 3a8bac805352 -r 36ebe6ec8fe8 Framework/Messages/IObserver.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/Framework/Messages/IObserver.h Thu Aug 30 16:56:08 2018 +0200
@@ -0,0 +1,88 @@
+/**
+ * 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 .
+ **/
+
+
+#pragma once
+
+#include "MessageBroker.h"
+#include "IMessage.h"
+#include
+#include
+
+namespace OrthancStone {
+
+ class IObservable;
+
+ class IObserver : public boost::noncopyable
+ {
+ protected:
+ MessageBroker& broker_;
+ std::set handledMessages_;
+ std::set ignoredMessages_;
+
+ public:
+ IObserver(MessageBroker& broker)
+ : broker_(broker)
+ {
+ broker_.Register(*this);
+ }
+
+ virtual ~IObserver()
+ {
+ broker_.Unregister(*this);
+ }
+
+ void HandleMessage_(IObservable &from, const IMessage &message)
+ {
+ assert(handledMessages_.find(message.GetType()) != handledMessages_.end()); // please declare the messages that you're handling
+
+ HandleMessage(from, message);
+ }
+
+ virtual void HandleMessage(IObservable& from, const IMessage& message) = 0;
+
+
+ const std::set& GetHandledMessages() const
+ {
+ return handledMessages_;
+ }
+
+ const std::set& GetIgnoredMessages() const
+ {
+ return ignoredMessages_;
+ }
+
+ protected:
+
+ // when you connect an IObserver to an IObservable, the observer must handle all observable messages (this is checked during the registration)
+ // so, all messages that may be emitted by the observable must be declared "handled" or "ignored" by the observer
+ void DeclareHandledMessage(MessageType messageType)
+ {
+ handledMessages_.insert(messageType);
+ }
+
+ void DeclareIgnoredMessage(MessageType messageType)
+ {
+ ignoredMessages_.insert(messageType);
+ }
+
+ };
+
+}
diff -r 3a8bac805352 -r 36ebe6ec8fe8 Framework/Messages/MessageBroker.cpp
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/Framework/Messages/MessageBroker.cpp Thu Aug 30 16:56:08 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 .
+ **/
+
+
+#include "MessageBroker.h"
+
+#include
+#include
+#include
+
+#include "IObserver.h"
+#include "MessageType.h"
+
+namespace OrthancStone {
+
+ void MessageBroker::EmitMessage(IObservable& from, std::set observers, const IMessage& message)
+ {
+ std::vector activeObservers;
+ std::set_intersection(observers.begin(),
+ observers.end(),
+ activeObservers_.begin(),
+ activeObservers_.end(),
+ std::back_inserter(activeObservers)
+ );
+
+ for (std::vector::iterator observer = activeObservers.begin(); observer != activeObservers.end(); observer++)
+ {
+ if ((*observer)->GetHandledMessages().find(message.GetType()) != (*observer)->GetHandledMessages().end())
+ {
+ (*observer)->HandleMessage_(from, message);
+ }
+ else
+ {
+ assert((*observer)->GetIgnoredMessages().find(message.GetType()) != (*observer)->GetIgnoredMessages().end()); // message has not been declared by Observer (this should already have been checked during registration)
+ }
+ }
+ }
+
+}
diff -r 3a8bac805352 -r 36ebe6ec8fe8 Framework/Messages/MessageBroker.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/Framework/Messages/MessageBroker.h Thu Aug 30 16:56:08 2018 +0200
@@ -0,0 +1,62 @@
+/**
+ * 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 .
+ **/
+
+
+#pragma once
+
+#include "../StoneEnumerations.h"
+
+#include "boost/noncopyable.hpp"
+#include