Mercurial > hg > orthanc-stone
changeset 1125:d7e06542304c broker
integration mainline->broker
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Tue, 05 Nov 2019 18:51:04 +0100 |
parents | a8bf81756839 (diff) 45df56448b2a (current diff) |
children | a8c3908ecba9 |
files | Framework/Radiography/RadiographyDicomLayer.cpp Framework/Radiography/RadiographyDicomLayer.h Framework/Radiography/RadiographyLayer.cpp Framework/Radiography/RadiographyLayer.h Framework/Radiography/RadiographyScene.h UnitTestsSources/TestStructureSet.cpp |
diffstat | 142 files changed, 2002 insertions(+), 1627 deletions(-) [+] |
line wrap: on
line diff
--- a/Applications/Generic/GuiAdapter.cpp Tue Nov 05 18:26:59 2019 +0100 +++ b/Applications/Generic/GuiAdapter.cpp Tue Nov 05 18:51:04 2019 +0100 @@ -792,7 +792,7 @@ while (!stop) { { - LockingEmitter::WriterLock lock(lockingEmitter_); + Deprecated::LockingEmitter::WriterLock lock(lockingEmitter_); if(func != NULL) (*func)(cookie); OnAnimationFrame(); // in SDL we must call it @@ -802,7 +802,7 @@ while (!stop && SDL_PollEvent(&event)) { - LockingEmitter::WriterLock lock(lockingEmitter_); + Deprecated::LockingEmitter::WriterLock lock(lockingEmitter_); if (event.type == SDL_QUIT) {
--- a/Applications/Generic/GuiAdapter.h Tue Nov 05 18:26:59 2019 +0100 +++ b/Applications/Generic/GuiAdapter.h Tue Nov 05 18:51:04 2019 +0100 @@ -95,7 +95,10 @@ struct GuiAdapterWheelEvent; struct GuiAdapterKeyboardEvent; - class LockingEmitter; + namespace Deprecated + { + class LockingEmitter; + } #if 1 typedef bool (*OnMouseEventFunc)(std::string canvasId, const GuiAdapterMouseEvent* mouseEvent, void* userData); @@ -225,7 +228,7 @@ { public: #if ORTHANC_ENABLE_THREADS == 1 - GuiAdapter(LockingEmitter& lockingEmitter) : lockingEmitter_(lockingEmitter) + GuiAdapter(Deprecated::LockingEmitter& lockingEmitter) : lockingEmitter_(lockingEmitter) #else GuiAdapter() #endif @@ -301,7 +304,7 @@ This object is used by the multithreaded Oracle to serialize access to shared data. We need to use it as soon as we access the state. */ - LockingEmitter& lockingEmitter_; + Deprecated::LockingEmitter& lockingEmitter_; #endif /**
--- a/Applications/Generic/NativeStoneApplicationContext.cpp Tue Nov 05 18:26:59 2019 +0100 +++ b/Applications/Generic/NativeStoneApplicationContext.cpp Tue Nov 05 18:51:04 2019 +0100 @@ -24,10 +24,10 @@ namespace OrthancStone { - Deprecated::IWidget& NativeStoneApplicationContext::GlobalMutexLocker::SetCentralWidget(Deprecated::IWidget* widget) + void NativeStoneApplicationContext::GlobalMutexLocker::SetCentralWidget( + boost::shared_ptr<Deprecated::IWidget> widget) { that_.centralViewport_.SetCentralWidget(widget); - return *widget; } @@ -45,9 +45,7 @@ } - NativeStoneApplicationContext::NativeStoneApplicationContext(MessageBroker& broker) : - StoneApplicationContext(broker), - centralViewport_(broker), + NativeStoneApplicationContext::NativeStoneApplicationContext() : stopped_(true), updateDelayInMs_(100) // By default, 100ms between each refresh of the content {
--- a/Applications/Generic/NativeStoneApplicationContext.h Tue Nov 05 18:26:59 2019 +0100 +++ b/Applications/Generic/NativeStoneApplicationContext.h Tue Nov 05 18:51:04 2019 +0100 @@ -56,7 +56,7 @@ { } - Deprecated::IWidget& SetCentralWidget(Deprecated::IWidget* widget); // Takes ownership + void SetCentralWidget(boost::shared_ptr<Deprecated::IWidget> widget); Deprecated::IViewport& GetCentralViewport() { @@ -67,14 +67,9 @@ { that_.updateDelayInMs_ = delayInMs; } - - MessageBroker& GetMessageBroker() - { - return that_.GetMessageBroker(); - } }; - NativeStoneApplicationContext(MessageBroker& broker); + NativeStoneApplicationContext(); void Start();
--- a/Applications/Generic/NativeStoneApplicationRunner.cpp Tue Nov 05 18:26:59 2019 +0100 +++ b/Applications/Generic/NativeStoneApplicationRunner.cpp Tue Nov 05 18:51:04 2019 +0100 @@ -97,7 +97,7 @@ DeclareCommandLineOptions(options); // application specific options - application_.DeclareStartupOptions(options); + application_->DeclareStartupOptions(options); boost::program_options::variables_map parameters; bool error = false; @@ -197,7 +197,7 @@ LogStatusBar statusBar; - NativeStoneApplicationContext context(broker_); + NativeStoneApplicationContext context; { // use multiple threads to execute asynchronous tasks like @@ -206,24 +206,23 @@ oracle.Start(); { - Deprecated::OracleWebService webService( - broker_, oracle, webServiceParameters, context); - + boost::shared_ptr<Deprecated::OracleWebService> webService + (new Deprecated::OracleWebService(oracle, webServiceParameters, context)); context.SetWebService(webService); context.SetOrthancBaseUrl(webServiceParameters.GetUrl()); - Deprecated::OracleDelayedCallExecutor delayedExecutor(broker_, oracle, context); + Deprecated::OracleDelayedCallExecutor delayedExecutor(oracle, context); context.SetDelayedCallExecutor(delayedExecutor); - application_.Initialize(&context, statusBar, parameters); + application_->Initialize(&context, statusBar, parameters); { NativeStoneApplicationContext::GlobalMutexLocker locker(context); - locker.SetCentralWidget(application_.GetCentralWidget()); + locker.SetCentralWidget(application_->GetCentralWidget()); locker.GetCentralViewport().SetStatusBar(statusBar); } - std::string title = application_.GetTitle(); + std::string title = application_->GetTitle(); if (title.empty()) { title = "Stone of Orthanc"; @@ -244,7 +243,7 @@ } LOG(WARNING) << "The application is stopping"; - application_.Finalize(); + application_->Finalize(); } catch (Orthanc::OrthancException& e) {
--- a/Applications/Generic/NativeStoneApplicationRunner.h Tue Nov 05 18:26:59 2019 +0100 +++ b/Applications/Generic/NativeStoneApplicationRunner.h Tue Nov 05 18:51:04 2019 +0100 @@ -34,14 +34,11 @@ class NativeStoneApplicationRunner { protected: - MessageBroker& broker_; - IStoneApplication& application_; + boost::shared_ptr<IStoneApplication> application_; + public: - - NativeStoneApplicationRunner(MessageBroker& broker, - IStoneApplication& application) - : broker_(broker), - application_(application) + NativeStoneApplicationRunner(boost::shared_ptr<IStoneApplication> application) + : application_(application) { } int Execute(int argc,
--- a/Applications/IStoneApplication.h Tue Nov 05 18:26:59 2019 +0100 +++ b/Applications/IStoneApplication.h Tue Nov 05 18:51:04 2019 +0100 @@ -64,7 +64,11 @@ #endif virtual std::string GetTitle() const = 0; - virtual Deprecated::IWidget* GetCentralWidget() = 0; + + virtual void SetCentralWidget(boost::shared_ptr<Deprecated::IWidget> widget) = 0; + + virtual boost::shared_ptr<Deprecated::IWidget> GetCentralWidget() = 0; + virtual void Finalize() = 0; }; }
--- a/Applications/Samples/SampleApplicationBase.h Tue Nov 05 18:26:59 2019 +0100 +++ b/Applications/Samples/SampleApplicationBase.h Tue Nov 05 18:51:04 2019 +0100 @@ -40,9 +40,8 @@ { class SampleApplicationBase : public IStoneApplication { - protected: - // ownership is transferred to the application context - Deprecated::WorldSceneWidget* mainWidget_; + private: + boost::shared_ptr<Deprecated::IWidget> mainWidget_; public: virtual void Initialize(StoneApplicationContext* context, @@ -64,7 +63,16 @@ virtual void Finalize() ORTHANC_OVERRIDE {} - virtual Deprecated::IWidget* GetCentralWidget() ORTHANC_OVERRIDE {return mainWidget_;} + + virtual void SetCentralWidget(boost::shared_ptr<Deprecated::IWidget> widget) ORTHANC_OVERRIDE + { + mainWidget_ = widget; + } + + virtual boost::shared_ptr<Deprecated::IWidget> GetCentralWidget() ORTHANC_OVERRIDE + { + return mainWidget_; + } #if ORTHANC_ENABLE_WASM==1 // default implementations for a single canvas named "canvas" in the HTML and an emtpy WasmApplicationAdapter
--- a/Applications/Samples/SampleMainNative.cpp Tue Nov 05 18:26:59 2019 +0100 +++ b/Applications/Samples/SampleMainNative.cpp Tue Nov 05 18:51:04 2019 +0100 @@ -26,19 +26,18 @@ #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); + boost::shared_ptr<SampleApplication> sampleStoneApplication(new SampleApplication); #if ORTHANC_ENABLE_SDL==1 - OrthancStone::SdlStoneApplicationRunner sdlApplicationRunner(broker, sampleStoneApplication); + OrthancStone::SdlStoneApplicationRunner sdlApplicationRunner(sampleStoneApplication); return sdlApplicationRunner.Execute(argc, argv); #endif + #if ORTHANC_ENABLE_QT==1 - OrthancStone::Samples::SampleQtApplicationRunner qtAppRunner(broker, sampleStoneApplication); + OrthancStone::Samples::SampleQtApplicationRunner qtAppRunner(sampleStoneApplication); return qtAppRunner.Execute(argc, argv); #endif }
--- a/Applications/Samples/SimpleViewerApplicationSingleFile.h Tue Nov 05 18:26:59 2019 +0100 +++ b/Applications/Samples/SimpleViewerApplicationSingleFile.h Tue Nov 05 18:51:04 2019 +0100 @@ -44,7 +44,7 @@ { class SimpleViewerApplication : public SampleSingleCanvasWithButtonsApplicationBase, - public IObserver + public ObserverBase<SimpleViewerApplication> { private: class ThumbnailInteractor : public Deprecated::IWorldSceneInteractor @@ -199,8 +199,8 @@ SimpleViewerApplication& viewerApplication_; public: - SimpleViewerApplicationAdapter(MessageBroker& broker, SimpleViewerApplication& application) - : WasmPlatformApplicationAdapter(broker, application), + SimpleViewerApplicationAdapter(SimpleViewerApplication& application) + : WasmPlatformApplicationAdapter(application), viewerApplication_(application) { } @@ -243,7 +243,7 @@ std::auto_ptr<ThumbnailInteractor> thumbnailInteractor_; Deprecated::LayoutWidget* mainLayout_; Deprecated::LayoutWidget* thumbnailsLayout_; - std::vector<Deprecated::SliceViewerWidget*> thumbnails_; + std::vector<boost::shared_ptr<Deprecated::SliceViewerWidget> > thumbnails_; std::map<std::string, std::vector<std::string> > instancesIdsPerSeriesId_; std::map<std::string, Json::Value> seriesTags_; @@ -258,8 +258,7 @@ Orthanc::Font font_; public: - SimpleViewerApplication(MessageBroker& broker) : - IObserver(broker), + SimpleViewerApplication() : currentTool_(Tool_LineMeasure), mainLayout_(NULL), currentInstanceIndex_(0), @@ -297,26 +296,28 @@ mainLayout_->SetBackgroundColor(0, 0, 0); mainLayout_->SetHorizontal(); - thumbnailsLayout_ = new Deprecated::LayoutWidget("thumbnail-layout"); + boost::shared_ptr<Deprecated::LayoutWidget> thumbnailsLayout_(new Deprecated::LayoutWidget("thumbnail-layout")); thumbnailsLayout_->SetPadding(10); thumbnailsLayout_->SetBackgroundCleared(true); thumbnailsLayout_->SetBackgroundColor(50, 50, 50); thumbnailsLayout_->SetVertical(); - mainWidget_ = new Deprecated::SliceViewerWidget(GetBroker(), "main-viewport"); + boost::shared_ptr<Deprecated::SliceViewerWidget> widget + (new Deprecated::SliceViewerWidget("main-viewport")); + SetCentralWidget(widget); //mainWidget_->RegisterObserver(*this); // hierarchy mainLayout_->AddWidget(thumbnailsLayout_); - mainLayout_->AddWidget(mainWidget_); + mainLayout_->AddWidget(widget); // sources - smartLoader_.reset(new Deprecated::SmartLoader(GetBroker(), context->GetOrthancApiClient())); + smartLoader_.reset(new Deprecated::SmartLoader(context->GetOrthancApiClient())); smartLoader_->SetImageQuality(Deprecated::SliceImageQuality_FullPam); mainLayout_->SetTransmitMouseOver(true); mainWidgetInteractor_.reset(new MainWidgetInteractor(*this)); - mainWidget_->SetInteractor(*mainWidgetInteractor_); + widget->SetInteractor(*mainWidgetInteractor_); thumbnailInteractor_.reset(new ThumbnailInteractor(*this)); } @@ -327,10 +328,10 @@ if (parameters.count("studyId") < 1) { LOG(WARNING) << "The study ID is missing, will take the first studyId found in Orthanc"; - context->GetOrthancApiClient().GetJsonAsync( + context->GetOrthancApiClient()->GetJsonAsync( "/studies", new Callable<SimpleViewerApplication, Deprecated::OrthancApiClient::JsonResponseReadyMessage> - (*this, &SimpleViewerApplication::OnStudyListReceived)); + (GetSharedObserver(), &SimpleViewerApplication::OnStudyListReceived)); } else { @@ -357,10 +358,10 @@ { for (size_t i=0; i < response["Series"].size(); i++) { - context_->GetOrthancApiClient().GetJsonAsync( + context_->GetOrthancApiClient()->GetJsonAsync( "/series/" + response["Series"][(int)i].asString(), new Callable<SimpleViewerApplication, Deprecated::OrthancApiClient::JsonResponseReadyMessage> - (*this, &SimpleViewerApplication::OnSeriesReceived)); + (GetSharedObserver(), &SimpleViewerApplication::OnSeriesReceived)); } } } @@ -387,7 +388,7 @@ LoadThumbnailForSeries(seriesId, instancesIdsPerSeriesId_[seriesId][0]); // if this is the first thumbnail loaded, load the first instance in the mainWidget - Deprecated::SliceViewerWidget& widget = *dynamic_cast<Deprecated::SliceViewerWidget*>(mainWidget_); + Deprecated::SliceViewerWidget& widget = dynamic_cast<Deprecated::SliceViewerWidget&>(*GetCentralWidget()); if (widget.GetLayerCount() == 0) { smartLoader_->SetFrameInWidget(widget, 0, instancesIdsPerSeriesId_[seriesId][0], 0); @@ -398,10 +399,10 @@ void LoadThumbnailForSeries(const std::string& seriesId, const std::string& instanceId) { LOG(INFO) << "Loading thumbnail for series " << seriesId; - Deprecated::SliceViewerWidget* thumbnailWidget = new Deprecated::SliceViewerWidget(GetBroker(), "thumbnail-series-" + seriesId); + boost::shared_ptr<Deprecated::SliceViewerWidget> thumbnailWidget(new Deprecated::SliceViewerWidget("thumbnail-series-" + seriesId)); thumbnails_.push_back(thumbnailWidget); thumbnailsLayout_->AddWidget(thumbnailWidget); - thumbnailWidget->RegisterObserverCallback(new Callable<SimpleViewerApplication, Deprecated::SliceViewerWidget::GeometryChangedMessage>(*this, &SimpleViewerApplication::OnWidgetGeometryChanged)); + Register<Deprecated::SliceViewerWidget::GeometryChangedMessage>(*thumbnailWidget, &SimpleViewerApplication::OnWidgetGeometryChanged); smartLoader_->SetFrameInWidget(*thumbnailWidget, 0, instanceId, 0); thumbnailWidget->SetInteractor(*thumbnailInteractor_); } @@ -409,9 +410,9 @@ void SelectStudy(const std::string& studyId) { LOG(INFO) << "Selecting study: " << studyId; - context_->GetOrthancApiClient().GetJsonAsync( + context_->GetOrthancApiClient()->GetJsonAsync( "/studies/" + studyId, new Callable<SimpleViewerApplication, Deprecated::OrthancApiClient::JsonResponseReadyMessage> - (*this, &SimpleViewerApplication::OnStudyReceived)); + (GetSharedObserver(), &SimpleViewerApplication::OnStudyReceived)); } void OnWidgetGeometryChanged(const Deprecated::SliceViewerWidget::GeometryChangedMessage& message) @@ -422,7 +423,7 @@ void SelectSeriesInMainViewport(const std::string& seriesId) { - Deprecated::SliceViewerWidget& widget = *dynamic_cast<Deprecated::SliceViewerWidget*>(mainWidget_); + Deprecated::SliceViewerWidget& widget = dynamic_cast<Deprecated::SliceViewerWidget&>(*GetCentralWidget()); smartLoader_->SetFrameInWidget(widget, 0, instancesIdsPerSeriesId_[seriesId][0], 0); } @@ -451,7 +452,7 @@ virtual void InitializeWasm() { AttachWidgetToWasmViewport("canvas", thumbnailsLayout_); - AttachWidgetToWasmViewport("canvas2", mainWidget_); + AttachWidgetToWasmViewport("canvas2", widget); } #endif
--- a/Applications/Samples/SingleFrameApplication.h Tue Nov 05 18:26:59 2019 +0100 +++ b/Applications/Samples/SingleFrameApplication.h Tue Nov 05 18:51:04 2019 +0100 @@ -38,7 +38,7 @@ { class SingleFrameApplication : public SampleSingleCanvasApplicationBase, - public IObserver + public ObserverBase<SingleFrameApplication> { private: class Interactor : public Deprecated::IWorldSceneInteractor @@ -127,7 +127,7 @@ void OffsetSlice(int offset) { - if (source_ != NULL) + if (source_) { int slice = static_cast<int>(slice_) + offset; @@ -149,21 +149,15 @@ } - Deprecated::SliceViewerWidget& GetMainWidget() - { - return *dynamic_cast<Deprecated::SliceViewerWidget*>(mainWidget_); - } - - void SetSlice(size_t index) { - if (source_ != NULL && + if (source_ && index < source_->GetSlicesCount()) { slice_ = static_cast<unsigned int>(index); #if 1 - GetMainWidget().SetSlice(source_->GetSlice(slice_).GetGeometry()); + widget_->SetSlice(source_->GetSlice(slice_).GetGeometry()); #else // TEST for scene extents - Rotate the axes double a = 15.0 / 180.0 * boost::math::constants::pi<double>(); @@ -189,22 +183,22 @@ // Once the geometry of the series is downloaded from Orthanc, // display its middle slice, and adapt the viewport to fit this // slice - if (source_ == &message.GetOrigin()) + if (source_ && + source_.get() == &message.GetOrigin()) { SetSlice(source_->GetSlicesCount() / 2); } - GetMainWidget().FitContent(); + widget_->FitContent(); } - + + boost::shared_ptr<Deprecated::SliceViewerWidget> widget_; std::auto_ptr<Interactor> mainWidgetInteractor_; - const Deprecated::DicomSeriesVolumeSlicer* source_; + boost::shared_ptr<Deprecated::DicomSeriesVolumeSlicer> source_; unsigned int slice_; public: - SingleFrameApplication(MessageBroker& broker) : - IObserver(broker), - source_(NULL), + SingleFrameApplication() : slice_(0) { } @@ -243,13 +237,15 @@ std::string instance = parameters["instance"].as<std::string>(); int frame = parameters["frame"].as<unsigned int>(); - mainWidget_ = new Deprecated::SliceViewerWidget(GetBroker(), "main-widget"); + widget_.reset(new Deprecated::SliceViewerWidget("main-widget")); + SetCentralWidget(widget_); - std::auto_ptr<Deprecated::DicomSeriesVolumeSlicer> layer(new Deprecated::DicomSeriesVolumeSlicer(GetBroker(), context->GetOrthancApiClient())); - source_ = layer.get(); + boost::shared_ptr<Deprecated::DicomSeriesVolumeSlicer> layer(new Deprecated::DicomSeriesVolumeSlicer); + layer->Connect(context->GetOrthancApiClient()); + source_ = layer; layer->LoadFrame(instance, frame); - layer->RegisterObserverCallback(new Callable<SingleFrameApplication, Deprecated::IVolumeSlicer::GeometryReadyMessage>(*this, &SingleFrameApplication::OnMainWidgetGeometryReady)); - GetMainWidget().AddLayer(layer.release()); + Register<Deprecated::IVolumeSlicer::GeometryReadyMessage>(*layer, &SingleFrameApplication::OnMainWidgetGeometryReady); + widget_->AddLayer(layer); Deprecated::RenderStyle s; @@ -258,11 +254,11 @@ s.interpolation_ = ImageInterpolation_Bilinear; } - GetMainWidget().SetLayerStyle(0, s); - GetMainWidget().SetTransmitMouseOver(true); + widget_->SetLayerStyle(0, s); + widget_->SetTransmitMouseOver(true); mainWidgetInteractor_.reset(new Interactor(*this)); - GetMainWidget().SetInteractor(*mainWidgetInteractor_); + widget_->SetInteractor(*mainWidgetInteractor_); } };
--- a/Applications/Samples/SingleFrameEditorApplication.h Tue Nov 05 18:26:59 2019 +0100 +++ b/Applications/Samples/SingleFrameEditorApplication.h Tue Nov 05 18:51:04 2019 +0100 @@ -28,13 +28,13 @@ #include "../../Framework/Radiography/RadiographyLayerMoveTracker.h" #include "../../Framework/Radiography/RadiographyLayerResizeTracker.h" #include "../../Framework/Radiography/RadiographyLayerRotateTracker.h" +#include "../../Framework/Radiography/RadiographyMaskLayer.h" #include "../../Framework/Radiography/RadiographyScene.h" #include "../../Framework/Radiography/RadiographySceneCommand.h" +#include "../../Framework/Radiography/RadiographySceneReader.h" +#include "../../Framework/Radiography/RadiographySceneWriter.h" #include "../../Framework/Radiography/RadiographyWidget.h" #include "../../Framework/Radiography/RadiographyWindowingTracker.h" -#include "../../Framework/Radiography/RadiographySceneWriter.h" -#include "../../Framework/Radiography/RadiographySceneReader.h" -#include "../../Framework/Radiography/RadiographyMaskLayer.h" #include "../../Framework/Toolbox/TextRenderer.h" #include <Core/HttpClient.h> @@ -56,7 +56,7 @@ { class RadiographyEditorInteractor : public Deprecated::IWorldSceneInteractor, - public IObserver + public ObserverBase<RadiographyEditorInteractor> { private: enum Tool @@ -83,8 +83,7 @@ public: - RadiographyEditorInteractor(MessageBroker& broker) : - IObserver(broker), + RadiographyEditorInteractor() : context_(NULL), tool_(Tool_Move), maskLayer_(NULL) @@ -316,7 +315,7 @@ LOG(INFO) << "JSON export was successful: " << snapshot.toStyledString(); - boost::shared_ptr<RadiographyScene> scene(new RadiographyScene(GetBroker())); + boost::shared_ptr<RadiographyScene> scene(new RadiographyScene); RadiographySceneReader reader(*scene, context_->GetOrthancApiClient()); Orthanc::FontRegistry fontRegistry; @@ -352,7 +351,7 @@ if (context_ != NULL) { - widget.GetScene().ExportDicom(context_->GetOrthancApiClient(), + widget.GetScene().ExportDicom(*context_->GetOrthancApiClient(), tags, std::string(), 0.1, 0.1, widget.IsInverted(), widget.GetInterpolation(), EXPORT_USING_PAM); } @@ -436,12 +435,6 @@ RadiographyMaskLayer* maskLayer_; public: - SingleFrameEditorApplication(MessageBroker& broker) : - IObserver(broker), - interactor_(broker) - { - } - virtual ~SingleFrameEditorApplication() { LOG(WARNING) << "Destroying the application"; @@ -495,9 +488,9 @@ fontRegistry_.AddFromResource(Orthanc::EmbeddedResources::FONT_UBUNTU_MONO_BOLD_16); - scene_.reset(new RadiographyScene(GetBroker())); + scene_.reset(new RadiographyScene); - RadiographyLayer& dicomLayer = scene_->LoadDicomFrame(context->GetOrthancApiClient(), instance, 0, false, NULL); + RadiographyLayer& dicomLayer = scene_->LoadDicomFrame(*context->GetOrthancApiClient(), instance, 0, false, NULL); //scene_->LoadDicomFrame(instance, frame, false); //.SetPan(200, 0); // = scene_->LoadDicomFrame(context->GetOrthancApiClient(), "61f3143e-96f34791-ad6bbb8d-62559e75-45943e1b", 0, false, NULL); @@ -534,10 +527,10 @@ layer.SetPan(0, 200); } - - mainWidget_ = new RadiographyWidget(GetBroker(), scene_, "main-widget"); - mainWidget_->SetTransmitMouseOver(true); - mainWidget_->SetInteractor(interactor_); + boost::shared_ptr<RadiographyWidget> widget(new RadiographyWidget(scene_, "main-widget")); + widget->SetTransmitMouseOver(true); + widget->SetInteractor(interactor_); + SetCentralWidget(widget); //scene_->SetWindowing(128, 256); }
--- a/Applications/Sdl/SdlEngine.cpp Tue Nov 05 18:26:59 2019 +0100 +++ b/Applications/Sdl/SdlEngine.cpp Tue Nov 05 18:51:04 2019 +0100 @@ -99,9 +99,7 @@ SdlEngine::SdlEngine(SdlWindow& window, - NativeStoneApplicationContext& context, - MessageBroker& broker) : - IObserver(broker), + NativeStoneApplicationContext& context) : window_(window), context_(context), surface_(window),
--- a/Applications/Sdl/SdlEngine.h Tue Nov 05 18:26:59 2019 +0100 +++ b/Applications/Sdl/SdlEngine.h Tue Nov 05 18:51:04 2019 +0100 @@ -23,12 +23,13 @@ #if ORTHANC_ENABLE_SDL == 1 +#include "../../Framework/Messages/ObserverBase.h" +#include "../Generic/NativeStoneApplicationContext.h" #include "SdlCairoSurface.h" -#include "../Generic/NativeStoneApplicationContext.h" namespace OrthancStone { - class SdlEngine : public IObserver + class SdlEngine : public ObserverBase<SdlEngine> { private: SdlWindow& window_; @@ -46,8 +47,7 @@ public: SdlEngine(SdlWindow& window, - NativeStoneApplicationContext& context, - MessageBroker& broker); + NativeStoneApplicationContext& context); void OnViewportChanged(const Deprecated::IViewport::ViewportChangedMessage& message) {
--- a/Applications/Sdl/SdlStoneApplicationRunner.cpp Tue Nov 05 18:26:59 2019 +0100 +++ b/Applications/Sdl/SdlStoneApplicationRunner.cpp Tue Nov 05 18:51:04 2019 +0100 @@ -103,20 +103,19 @@ LOG(WARNING) << "Starting the application"; SdlWindow window(title.c_str(), width_, height_, enableOpenGl_); - SdlEngine sdl(window, context, broker_); + boost::shared_ptr<SdlEngine> sdl(new SdlEngine(window, context)); { NativeStoneApplicationContext::GlobalMutexLocker locker(context); - locker.GetCentralViewport().RegisterObserverCallback( - new Callable<SdlEngine, Deprecated::IViewport::ViewportChangedMessage> - (sdl, &SdlEngine::OnViewportChanged)); + sdl->Register<Deprecated::IViewport::ViewportChangedMessage> + (locker.GetCentralViewport(), &SdlEngine::OnViewportChanged); //context.GetCentralViewport().Register(sdl); // (*) } context.Start(); - sdl.Run(); + sdl->Run(); LOG(WARNING) << "Stopping the application";
--- a/Applications/Sdl/SdlStoneApplicationRunner.h Tue Nov 05 18:26:59 2019 +0100 +++ b/Applications/Sdl/SdlStoneApplicationRunner.h Tue Nov 05 18:51:04 2019 +0100 @@ -39,9 +39,8 @@ bool enableOpenGl_; public: - SdlStoneApplicationRunner(MessageBroker& broker, - IStoneApplication& application) : - NativeStoneApplicationRunner(broker, application) + SdlStoneApplicationRunner(boost::shared_ptr<IStoneApplication> application) : + NativeStoneApplicationRunner(application) { }
--- a/Applications/StoneApplicationContext.cpp Tue Nov 05 18:26:59 2019 +0100 +++ b/Applications/StoneApplicationContext.cpp Tue Nov 05 18:51:04 2019 +0100 @@ -32,35 +32,35 @@ throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); } - orthanc_.reset(new Deprecated::OrthancApiClient(broker_, *webService_, orthancBaseUrl_)); + orthanc_.reset(new Deprecated::OrthancApiClient(*webService_, orthancBaseUrl_)); } - Deprecated::IWebService& StoneApplicationContext::GetWebService() + boost::shared_ptr<Deprecated::IWebService> StoneApplicationContext::GetWebService() { if (webService_ == NULL) { throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); } - return *webService_; + return webService_; } - Deprecated::OrthancApiClient& StoneApplicationContext::GetOrthancApiClient() + boost::shared_ptr<Deprecated::OrthancApiClient> StoneApplicationContext::GetOrthancApiClient() { if (orthanc_.get() == NULL) { throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); } - return *orthanc_; + return orthanc_; } - void StoneApplicationContext::SetWebService(Deprecated::IWebService& webService) + void StoneApplicationContext::SetWebService(boost::shared_ptr<Deprecated::IWebService> webService) { - webService_ = &webService; + webService_ = webService; InitializeOrthanc(); }
--- a/Applications/StoneApplicationContext.h Tue Nov 05 18:26:59 2019 +0100 +++ b/Applications/StoneApplicationContext.h Tue Nov 05 18:51:04 2019 +0100 @@ -59,18 +59,15 @@ class StoneApplicationContext : public boost::noncopyable { private: - MessageBroker& broker_; - Deprecated::IWebService* webService_; - Deprecated::IDelayedCallExecutor* delayedCallExecutor_; - std::auto_ptr<Deprecated::OrthancApiClient> orthanc_; + boost::shared_ptr<Deprecated::IWebService> webService_; + Deprecated::IDelayedCallExecutor* delayedCallExecutor_; // TODO => shared_ptr ?? + boost::shared_ptr<Deprecated::OrthancApiClient> orthanc_; std::string orthancBaseUrl_; void InitializeOrthanc(); public: - StoneApplicationContext(MessageBroker& broker) : - broker_(broker), - webService_(NULL), + StoneApplicationContext() : delayedCallExecutor_(NULL) { } @@ -79,21 +76,11 @@ { } - MessageBroker& GetMessageBroker() - { - return broker_; - } + boost::shared_ptr<Deprecated::IWebService> GetWebService(); - bool HasWebService() const - { - return webService_ != NULL; - } + boost::shared_ptr<Deprecated::OrthancApiClient> GetOrthancApiClient(); - Deprecated::IWebService& GetWebService(); - - Deprecated::OrthancApiClient& GetOrthancApiClient(); - - void SetWebService(Deprecated::IWebService& webService); + void SetWebService(boost::shared_ptr<Deprecated::IWebService> webService); void SetOrthancBaseUrl(const std::string& baseUrl);
--- a/Framework/Deprecated/Layers/DicomSeriesVolumeSlicer.cpp Tue Nov 05 18:26:59 2019 +0100 +++ b/Framework/Deprecated/Layers/DicomSeriesVolumeSlicer.cpp Tue Nov 05 18:51:04 2019 +0100 @@ -87,59 +87,73 @@ } - DicomSeriesVolumeSlicer::DicomSeriesVolumeSlicer(OrthancStone::MessageBroker& broker, - OrthancApiClient& orthanc) : - IVolumeSlicer(broker), - IObserver(broker), - loader_(broker, orthanc), + DicomSeriesVolumeSlicer::DicomSeriesVolumeSlicer() : quality_(SliceImageQuality_FullPng) { - loader_.RegisterObserverCallback( - new OrthancStone::Callable<DicomSeriesVolumeSlicer, OrthancSlicesLoader::SliceGeometryReadyMessage> - (*this, &DicomSeriesVolumeSlicer::OnSliceGeometryReady)); - - loader_.RegisterObserverCallback( - new OrthancStone::Callable<DicomSeriesVolumeSlicer, OrthancSlicesLoader::SliceGeometryErrorMessage> - (*this, &DicomSeriesVolumeSlicer::OnSliceGeometryError)); + } - loader_.RegisterObserverCallback( - new OrthancStone::Callable<DicomSeriesVolumeSlicer, OrthancSlicesLoader::SliceImageReadyMessage> - (*this, &DicomSeriesVolumeSlicer::OnSliceImageReady)); - - loader_.RegisterObserverCallback( - new OrthancStone::Callable<DicomSeriesVolumeSlicer, OrthancSlicesLoader::SliceImageErrorMessage> - (*this, &DicomSeriesVolumeSlicer::OnSliceImageError)); + void DicomSeriesVolumeSlicer::Connect(boost::shared_ptr<OrthancApiClient> orthanc) + { + loader_.reset(new OrthancSlicesLoader(orthanc)); + Register<OrthancSlicesLoader::SliceGeometryReadyMessage>(*loader_, &DicomSeriesVolumeSlicer::OnSliceGeometryReady); + Register<OrthancSlicesLoader::SliceGeometryErrorMessage>(*loader_, &DicomSeriesVolumeSlicer::OnSliceGeometryError); + Register<OrthancSlicesLoader::SliceImageReadyMessage>(*loader_, &DicomSeriesVolumeSlicer::OnSliceImageReady); + Register<OrthancSlicesLoader::SliceImageErrorMessage>(*loader_, &DicomSeriesVolumeSlicer::OnSliceImageError); } void DicomSeriesVolumeSlicer::LoadSeries(const std::string& seriesId) { - loader_.ScheduleLoadSeries(seriesId); + if (loader_.get() == NULL) + { + // Should have called "Connect()" + throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); + } + + loader_->ScheduleLoadSeries(seriesId); } void DicomSeriesVolumeSlicer::LoadInstance(const std::string& instanceId) { - loader_.ScheduleLoadInstance(instanceId); + if (loader_.get() == NULL) + { + // Should have called "Connect()" + throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); + } + + loader_->ScheduleLoadInstance(instanceId); } void DicomSeriesVolumeSlicer::LoadFrame(const std::string& instanceId, unsigned int frame) { - loader_.ScheduleLoadFrame(instanceId, frame); + if (loader_.get() == NULL) + { + // Should have called "Connect()" + throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); + } + + loader_->ScheduleLoadFrame(instanceId, frame); } bool DicomSeriesVolumeSlicer::GetExtent(std::vector<OrthancStone::Vector>& points, const OrthancStone::CoordinateSystem3D& viewportSlice) { + if (loader_.get() == NULL) + { + // Should have called "Connect()" + throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); + } + size_t index; - if (loader_.IsGeometryReady() && - loader_.LookupSlice(index, viewportSlice)) + if (loader_->IsGeometryReady() && + loader_->LookupSlice(index, viewportSlice)) { - loader_.GetSlice(index).GetExtent(points); + loader_->GetSlice(index).GetExtent(points); return true; } else @@ -151,12 +165,18 @@ void DicomSeriesVolumeSlicer::ScheduleLayerCreation(const OrthancStone::CoordinateSystem3D& viewportSlice) { + if (loader_.get() == NULL) + { + // Should have called "Connect()" + throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); + } + size_t index; - if (loader_.IsGeometryReady() && - loader_.LookupSlice(index, viewportSlice)) + if (loader_->IsGeometryReady() && + loader_->LookupSlice(index, viewportSlice)) { - loader_.ScheduleLoadSliceImage(index, quality_); + loader_->ScheduleLoadSliceImage(index, quality_); } } }
--- a/Framework/Deprecated/Layers/DicomSeriesVolumeSlicer.h Tue Nov 05 18:26:59 2019 +0100 +++ b/Framework/Deprecated/Layers/DicomSeriesVolumeSlicer.h Tue Nov 05 18:51:04 2019 +0100 @@ -22,6 +22,7 @@ #pragma once #include "IVolumeSlicer.h" +#include "../../Messages/ObserverBase.h" #include "../Toolbox/IWebService.h" #include "../Toolbox/OrthancSlicesLoader.h" #include "../Toolbox/OrthancApiClient.h" @@ -33,7 +34,7 @@ // messages are sent to observers so they can use it class DicomSeriesVolumeSlicer : public IVolumeSlicer, - public OrthancStone::IObserver + public OrthancStone::ObserverBase<DicomSeriesVolumeSlicer> //private OrthancSlicesLoader::ISliceLoaderObserver { public: @@ -79,13 +80,14 @@ private: class RendererFactory; - OrthancSlicesLoader loader_; + boost::shared_ptr<OrthancSlicesLoader> loader_; SliceImageQuality quality_; public: - DicomSeriesVolumeSlicer(OrthancStone::MessageBroker& broker, - OrthancApiClient& orthanc); + DicomSeriesVolumeSlicer(); + void Connect(boost::shared_ptr<OrthancApiClient> orthanc); + void LoadSeries(const std::string& seriesId); void LoadInstance(const std::string& instanceId); @@ -105,12 +107,12 @@ size_t GetSlicesCount() const { - return loader_.GetSlicesCount(); + return loader_->GetSlicesCount(); } const Slice& GetSlice(size_t slice) const { - return loader_.GetSlice(slice); + return loader_->GetSlice(slice); } virtual bool GetExtent(std::vector<OrthancStone::Vector>& points,
--- a/Framework/Deprecated/Layers/DicomStructureSetSlicer.cpp Tue Nov 05 18:26:59 2019 +0100 +++ b/Framework/Deprecated/Layers/DicomStructureSetSlicer.cpp Tue Nov 05 18:51:04 2019 +0100 @@ -140,15 +140,10 @@ }; - DicomStructureSetSlicer::DicomStructureSetSlicer(OrthancStone::MessageBroker& broker, - StructureSetLoader& loader) : - IVolumeSlicer(broker), - IObserver(broker), + DicomStructureSetSlicer::DicomStructureSetSlicer(StructureSetLoader& loader) : loader_(loader) { - loader_.RegisterObserverCallback( - new OrthancStone::Callable<DicomStructureSetSlicer, StructureSetLoader::ContentChangedMessage> - (*this, &DicomStructureSetSlicer::OnStructureSetLoaded)); + Register<StructureSetLoader::ContentChangedMessage>(loader_, &DicomStructureSetSlicer::OnStructureSetLoaded); }
--- a/Framework/Deprecated/Layers/DicomStructureSetSlicer.h Tue Nov 05 18:26:59 2019 +0100 +++ b/Framework/Deprecated/Layers/DicomStructureSetSlicer.h Tue Nov 05 18:51:04 2019 +0100 @@ -28,7 +28,7 @@ { class DicomStructureSetSlicer : public IVolumeSlicer, - public OrthancStone::IObserver + public OrthancStone::ObserverBase<DicomStructureSetSlicer> { private: class Renderer; @@ -42,8 +42,7 @@ } public: - DicomStructureSetSlicer(OrthancStone::MessageBroker& broker, - StructureSetLoader& loader); + DicomStructureSetSlicer(StructureSetLoader& loader); virtual bool GetExtent(std::vector<OrthancStone::Vector>& points, const OrthancStone::CoordinateSystem3D& viewportPlane)
--- a/Framework/Deprecated/Layers/IVolumeSlicer.h Tue Nov 05 18:26:59 2019 +0100 +++ b/Framework/Deprecated/Layers/IVolumeSlicer.h Tue Nov 05 18:51:04 2019 +0100 @@ -122,11 +122,6 @@ }; - IVolumeSlicer(OrthancStone::MessageBroker& broker) : - IObservable(broker) - { - } - virtual ~IVolumeSlicer() { }
--- a/Framework/Deprecated/SmartLoader.cpp Tue Nov 05 18:26:59 2019 +0100 +++ b/Framework/Deprecated/SmartLoader.cpp Tue Nov 05 18:51:04 2019 +0100 @@ -21,7 +21,6 @@ #include "SmartLoader.h" -#include "../Messages/MessageForwarder.h" #include "../StoneException.h" #include "Core/Images/Image.h" #include "Core/Logging.h" @@ -68,11 +67,6 @@ CachedSliceStatus status_; public: - CachedSlice(OrthancStone::MessageBroker& broker) : - IVolumeSlicer(broker) - { - } - virtual ~CachedSlice() { } @@ -106,7 +100,7 @@ CachedSlice* Clone() const { - CachedSlice* output = new CachedSlice(GetBroker()); + CachedSlice* output = new CachedSlice; output->sliceIndex_ = sliceIndex_; output->slice_.reset(slice_->Clone()); output->image_ = image_; @@ -119,10 +113,7 @@ }; - SmartLoader::SmartLoader(OrthancStone::MessageBroker& broker, - OrthancApiClient& orthancApiClient) : - IObservable(broker), - IObserver(broker), + SmartLoader::SmartLoader(boost::shared_ptr<OrthancApiClient> orthancApiClient) : imageQuality_(SliceImageQuality_FullPam), orthancApiClient_(orthancApiClient) { @@ -140,7 +131,7 @@ // the messages to its observables // in both cases, we must be carefull about objects lifecycle !!! - std::auto_ptr<IVolumeSlicer> layerSource; + boost::shared_ptr<IVolumeSlicer> layerSource; std::string sliceKeyId = instanceId + ":" + boost::lexical_cast<std::string>(frame); SmartLoader::CachedSlice* cachedSlice = NULL; @@ -151,22 +142,23 @@ } else { - layerSource.reset(new DicomSeriesVolumeSlicer(IObserver::GetBroker(), orthancApiClient_)); + layerSource.reset(new DicomSeriesVolumeSlicer); + dynamic_cast<DicomSeriesVolumeSlicer*>(layerSource.get())->Connect(orthancApiClient_); dynamic_cast<DicomSeriesVolumeSlicer*>(layerSource.get())->SetImageQuality(imageQuality_); - layerSource->RegisterObserverCallback(new OrthancStone::Callable<SmartLoader, IVolumeSlicer::GeometryReadyMessage>(*this, &SmartLoader::OnLayerGeometryReady)); - layerSource->RegisterObserverCallback(new OrthancStone::Callable<SmartLoader, DicomSeriesVolumeSlicer::FrameReadyMessage>(*this, &SmartLoader::OnFrameReady)); - layerSource->RegisterObserverCallback(new OrthancStone::Callable<SmartLoader, IVolumeSlicer::LayerReadyMessage>(*this, &SmartLoader::OnLayerReady)); + Register<IVolumeSlicer::GeometryReadyMessage>(*layerSource, &SmartLoader::OnLayerGeometryReady); + Register<DicomSeriesVolumeSlicer::FrameReadyMessage>(*layerSource, &SmartLoader::OnFrameReady); + Register<IVolumeSlicer::LayerReadyMessage>(*layerSource, &SmartLoader::OnLayerReady); dynamic_cast<DicomSeriesVolumeSlicer*>(layerSource.get())->LoadFrame(instanceId, frame); } // make sure that the widget registers the events before we trigger them if (sliceViewer.GetLayerCount() == layerIndex) { - sliceViewer.AddLayer(layerSource.release()); + sliceViewer.AddLayer(layerSource); } else if (sliceViewer.GetLayerCount() > layerIndex) { - sliceViewer.ReplaceLayer(layerIndex, layerSource.release()); + sliceViewer.ReplaceLayer(layerIndex, layerSource); } else { @@ -190,7 +182,7 @@ // create the slice in the cache with "empty" data - boost::shared_ptr<CachedSlice> cachedSlice(new CachedSlice(IObserver::GetBroker())); + boost::shared_ptr<CachedSlice> cachedSlice(new CachedSlice); cachedSlice->slice_.reset(new Slice(instanceId, frame)); cachedSlice->status_ = CachedSliceStatus_ScheduledToLoad; std::string sliceKeyId = instanceId + ":" + boost::lexical_cast<std::string>(frame); @@ -199,12 +191,12 @@ cachedSlices_[sliceKeyId] = boost::shared_ptr<CachedSlice>(cachedSlice); - std::auto_ptr<IVolumeSlicer> layerSource(new DicomSeriesVolumeSlicer(IObserver::GetBroker(), orthancApiClient_)); - + std::auto_ptr<IVolumeSlicer> layerSource(new DicomSeriesVolumeSlicer); + dynamic_cast<DicomSeriesVolumeSlicer*>(layerSource.get())->Connect(orthancApiClient_); dynamic_cast<DicomSeriesVolumeSlicer*>(layerSource.get())->SetImageQuality(imageQuality_); - layerSource->RegisterObserverCallback(new OrthancStone::Callable<SmartLoader, IVolumeSlicer::GeometryReadyMessage>(*this, &SmartLoader::OnLayerGeometryReady)); - layerSource->RegisterObserverCallback(new OrthancStone::Callable<SmartLoader, DicomSeriesVolumeSlicer::FrameReadyMessage>(*this, &SmartLoader::OnFrameReady)); - layerSource->RegisterObserverCallback(new OrthancStone::Callable<SmartLoader, IVolumeSlicer::LayerReadyMessage>(*this, &SmartLoader::OnLayerReady)); + Register<IVolumeSlicer::GeometryReadyMessage>(*layerSource, &SmartLoader::OnLayerGeometryReady); + Register<DicomSeriesVolumeSlicer::FrameReadyMessage>(*layerSource, &SmartLoader::OnFrameReady); + Register<IVolumeSlicer::LayerReadyMessage>(*layerSource, &SmartLoader::OnLayerReady); dynamic_cast<DicomSeriesVolumeSlicer*>(layerSource.get())->LoadFrame(instanceId, frame); // keep a ref to the VolumeSlicer until the slice is fully loaded and saved to cache @@ -235,7 +227,7 @@ LOG(WARNING) << "Geometry ready: " << sliceKeyId; - boost::shared_ptr<CachedSlice> cachedSlice(new CachedSlice(IObserver::GetBroker())); + boost::shared_ptr<CachedSlice> cachedSlice(new CachedSlice); cachedSlice->slice_.reset(slice.Clone()); cachedSlice->effectiveQuality_ = source.GetImageQuality(); cachedSlice->status_ = CachedSliceStatus_GeometryLoaded; @@ -256,7 +248,7 @@ LOG(WARNING) << "Image ready: " << sliceKeyId; - boost::shared_ptr<CachedSlice> cachedSlice(new CachedSlice(IObserver::GetBroker())); + boost::shared_ptr<CachedSlice> cachedSlice(new CachedSlice); cachedSlice->image_.reset(Orthanc::Image::Clone(message.GetFrame())); cachedSlice->effectiveQuality_ = message.GetImageQuality(); cachedSlice->slice_.reset(message.GetSlice().Clone());
--- a/Framework/Deprecated/SmartLoader.h Tue Nov 05 18:26:59 2019 +0100 +++ b/Framework/Deprecated/SmartLoader.h Tue Nov 05 18:51:04 2019 +0100 @@ -30,7 +30,7 @@ { class SliceViewerWidget; - class SmartLoader : public OrthancStone::IObservable, public OrthancStone::IObserver + class SmartLoader : public OrthancStone::IObservable, public OrthancStone::ObserverBase<SmartLoader> { class CachedSlice; @@ -42,10 +42,10 @@ PreloadingInstances preloadingInstances_; SliceImageQuality imageQuality_; - OrthancApiClient& orthancApiClient_; + boost::shared_ptr<OrthancApiClient> orthancApiClient_; public: - SmartLoader(OrthancStone::MessageBroker& broker, OrthancApiClient& orthancApiClient); // TODO: add maxPreloadStorageSizeInBytes + SmartLoader(boost::shared_ptr<OrthancApiClient> orthancApiClient); // TODO: add maxPreloadStorageSizeInBytes // void PreloadStudy(const std::string studyId); // void PreloadSeries(const std::string seriesId);
--- a/Framework/Deprecated/Toolbox/BaseWebService.cpp Tue Nov 05 18:26:59 2019 +0100 +++ b/Framework/Deprecated/Toolbox/BaseWebService.cpp Tue Nov 05 18:51:04 2019 +0100 @@ -97,9 +97,9 @@ GetAsyncInternal(uri, headers, new BaseWebService::BaseWebServicePayload(successCallback, failureCallback, payload), // ownership is transfered new OrthancStone::Callable<BaseWebService, IWebService::HttpRequestSuccessMessage> - (*this, &BaseWebService::CacheAndNotifyHttpSuccess), + (GetSharedObserver(), &BaseWebService::CacheAndNotifyHttpSuccess), new OrthancStone::Callable<BaseWebService, IWebService::HttpRequestErrorMessage> - (*this, &BaseWebService::NotifyHttpError), + (GetSharedObserver(), &BaseWebService::NotifyHttpError), timeoutInSeconds); } else
--- a/Framework/Deprecated/Toolbox/BaseWebService.h Tue Nov 05 18:26:59 2019 +0100 +++ b/Framework/Deprecated/Toolbox/BaseWebService.h Tue Nov 05 18:51:04 2019 +0100 @@ -22,6 +22,7 @@ #pragma once #include "IWebService.h" +#include "../../Messages/ObserverBase.h" #include <string> #include <map> @@ -31,7 +32,7 @@ { // This is an intermediate of IWebService that implements some caching on // the HTTP GET requests - class BaseWebService : public IWebService, public OrthancStone::IObserver + class BaseWebService : public IWebService, public OrthancStone::ObserverBase<BaseWebService> { public: class CachedHttpRequestSuccessMessage @@ -90,10 +91,7 @@ std::deque<std::string> orderedCacheKeys_; public: - - BaseWebService(OrthancStone::MessageBroker& broker) : - IWebService(broker), - IObserver(broker), + BaseWebService() : cacheEnabled_(false), cacheCurrentSize_(0), cacheMaxSize_(100*1024*1024)
--- a/Framework/Deprecated/Toolbox/IDelayedCallExecutor.h Tue Nov 05 18:26:59 2019 +0100 +++ b/Framework/Deprecated/Toolbox/IDelayedCallExecutor.h Tue Nov 05 18:51:04 2019 +0100 @@ -35,22 +35,12 @@ // The IDelayedCall executes a callback after a delay (equivalent to timeout() function in javascript). class IDelayedCallExecutor : public boost::noncopyable { - protected: - OrthancStone::MessageBroker& broker_; - public: ORTHANC_STONE_DEFINE_EMPTY_MESSAGE(__FILE__, __LINE__, TimeoutMessage); - IDelayedCallExecutor(OrthancStone::MessageBroker& broker) : - broker_(broker) - { - } - - virtual ~IDelayedCallExecutor() { } - virtual void Schedule(OrthancStone::MessageHandler<IDelayedCallExecutor::TimeoutMessage>* callback, unsigned int timeoutInMs = 1000) = 0;
--- a/Framework/Deprecated/Toolbox/IWebService.h Tue Nov 05 18:26:59 2019 +0100 +++ b/Framework/Deprecated/Toolbox/IWebService.h Tue Nov 05 18:51:04 2019 +0100 @@ -40,9 +40,6 @@ // and you'll be notified when the response/error is ready. class IWebService : public boost::noncopyable { - protected: - OrthancStone::MessageBroker& broker_; - public: typedef std::map<std::string, std::string> HttpHeaders; @@ -138,12 +135,6 @@ }; - IWebService(OrthancStone::MessageBroker& broker) : - broker_(broker) - { - } - - virtual ~IWebService() { }
--- a/Framework/Deprecated/Toolbox/OrthancApiClient.cpp Tue Nov 05 18:26:59 2019 +0100 +++ b/Framework/Deprecated/Toolbox/OrthancApiClient.cpp Tue Nov 05 18:51:04 2019 +0100 @@ -73,7 +73,6 @@ std::auto_ptr< OrthancStone::MessageHandler<BinaryResponseReadyMessage> > binaryHandler_; std::auto_ptr< OrthancStone::MessageHandler<IWebService::HttpRequestErrorMessage> > failureHandler_; std::auto_ptr< Orthanc::IDynamicObject > userPayload_; - OrthancStone::MessageBroker& broker_; void NotifyConversionError(const IWebService::HttpRequestSuccessMessage& message) const { if (failureHandler_.get() != NULL) @@ -84,14 +83,12 @@ } public: - WebServicePayload(OrthancStone::MessageBroker& broker, - OrthancStone::MessageHandler<EmptyResponseReadyMessage>* handler, + WebServicePayload(OrthancStone::MessageHandler<EmptyResponseReadyMessage>* handler, OrthancStone::MessageHandler<IWebService::HttpRequestErrorMessage>* failureHandler, Orthanc::IDynamicObject* userPayload) : emptyHandler_(handler), failureHandler_(failureHandler), - userPayload_(userPayload), - broker_(broker) + userPayload_(userPayload) { if (handler == NULL) @@ -100,14 +97,12 @@ } } - WebServicePayload(OrthancStone::MessageBroker& broker, - OrthancStone::MessageHandler<BinaryResponseReadyMessage>* handler, + WebServicePayload(OrthancStone::MessageHandler<BinaryResponseReadyMessage>* handler, OrthancStone::MessageHandler<IWebService::HttpRequestErrorMessage>* failureHandler, Orthanc::IDynamicObject* userPayload) : binaryHandler_(handler), failureHandler_(failureHandler), - userPayload_(userPayload), - broker_(broker) + userPayload_(userPayload) { if (handler == NULL) { @@ -115,14 +110,12 @@ } } - WebServicePayload(OrthancStone::MessageBroker& broker, - OrthancStone::MessageHandler<JsonResponseReadyMessage>* handler, + WebServicePayload(OrthancStone::MessageHandler<JsonResponseReadyMessage>* handler, OrthancStone::MessageHandler<IWebService::HttpRequestErrorMessage>* failureHandler, Orthanc::IDynamicObject* userPayload) : jsonHandler_(handler), failureHandler_(failureHandler), - userPayload_(userPayload), - broker_(broker) + userPayload_(userPayload) { if (handler == NULL) { @@ -134,35 +127,26 @@ { if (emptyHandler_.get() != NULL) { - if (broker_.IsActive(*(emptyHandler_->GetObserver()))) - { - emptyHandler_->Apply(OrthancApiClient::EmptyResponseReadyMessage - (message.GetUri(), userPayload_.get())); - } + emptyHandler_->Apply(OrthancApiClient::EmptyResponseReadyMessage + (message.GetUri(), userPayload_.get())); } else if (binaryHandler_.get() != NULL) { - if (broker_.IsActive(*(binaryHandler_->GetObserver()))) - { - binaryHandler_->Apply(OrthancApiClient::BinaryResponseReadyMessage - (message.GetUri(), message.GetAnswer(), - message.GetAnswerSize(), userPayload_.get())); - } + binaryHandler_->Apply(OrthancApiClient::BinaryResponseReadyMessage + (message.GetUri(), message.GetAnswer(), + message.GetAnswerSize(), userPayload_.get())); } else if (jsonHandler_.get() != NULL) { - if (broker_.IsActive(*(jsonHandler_->GetObserver()))) + Json::Value response; + if (MessagingToolbox::ParseJson(response, message.GetAnswer(), message.GetAnswerSize())) { - Json::Value response; - if (MessagingToolbox::ParseJson(response, message.GetAnswer(), message.GetAnswerSize())) - { - jsonHandler_->Apply(OrthancApiClient::JsonResponseReadyMessage - (message.GetUri(), response, userPayload_.get())); - } - else - { - NotifyConversionError(message); - } + jsonHandler_->Apply(OrthancApiClient::JsonResponseReadyMessage + (message.GetUri(), response, userPayload_.get())); + } + else + { + NotifyConversionError(message); } } else @@ -182,11 +166,8 @@ }; - OrthancApiClient::OrthancApiClient(OrthancStone::MessageBroker& broker, - IWebService& web, + OrthancApiClient::OrthancApiClient(IWebService& web, const std::string& baseUrl) : - IObservable(broker), - IObserver(broker), web_(web), baseUrl_(baseUrl) { @@ -202,11 +183,11 @@ IWebService::HttpHeaders emptyHeaders; web_.GetAsync(baseUrl_ + uri, emptyHeaders, - new WebServicePayload(IObservable::GetBroker(), successCallback, failureCallback, payload), + new WebServicePayload(successCallback, failureCallback, payload), new OrthancStone::Callable<OrthancApiClient, IWebService::HttpRequestSuccessMessage> - (*this, &OrthancApiClient::NotifyHttpSuccess), + (GetSharedObserver(), &OrthancApiClient::NotifyHttpSuccess), new OrthancStone::Callable<OrthancApiClient, IWebService::HttpRequestErrorMessage> - (*this, &OrthancApiClient::NotifyHttpError)); + (GetSharedObserver(), &OrthancApiClient::NotifyHttpError)); } @@ -232,11 +213,11 @@ // printf("GET [%s] [%s]\n", baseUrl_.c_str(), uri.c_str()); web_.GetAsync(baseUrl_ + uri, headers, - new WebServicePayload(IObservable::GetBroker(), successCallback, failureCallback, payload), + new WebServicePayload(successCallback, failureCallback, payload), new OrthancStone::Callable<OrthancApiClient, IWebService::HttpRequestSuccessMessage> - (*this, &OrthancApiClient::NotifyHttpSuccess), + (GetSharedObserver(), &OrthancApiClient::NotifyHttpSuccess), new OrthancStone::Callable<OrthancApiClient, IWebService::HttpRequestErrorMessage> - (*this, &OrthancApiClient::NotifyHttpError)); + (GetSharedObserver(), &OrthancApiClient::NotifyHttpError)); } @@ -248,11 +229,11 @@ Orthanc::IDynamicObject* payload) { web_.PostAsync(baseUrl_ + uri, IWebService::HttpHeaders(), body, - new WebServicePayload(IObservable::GetBroker(), successCallback, failureCallback, payload), + new WebServicePayload(successCallback, failureCallback, payload), new OrthancStone::Callable<OrthancApiClient, IWebService::HttpRequestSuccessMessage> - (*this, &OrthancApiClient::NotifyHttpSuccess), + (GetSharedObserver(), &OrthancApiClient::NotifyHttpSuccess), new OrthancStone::Callable<OrthancApiClient, IWebService::HttpRequestErrorMessage> - (*this, &OrthancApiClient::NotifyHttpError)); + (GetSharedObserver(), &OrthancApiClient::NotifyHttpError)); } @@ -271,11 +252,11 @@ Orthanc::IDynamicObject* payload /* takes ownership */) { web_.PostAsync(baseUrl_ + uri, IWebService::HttpHeaders(), body, - new WebServicePayload(IObservable::GetBroker(), successCallback, failureCallback, payload), + new WebServicePayload(successCallback, failureCallback, payload), new OrthancStone::Callable<OrthancApiClient, IWebService::HttpRequestSuccessMessage> - (*this, &OrthancApiClient::NotifyHttpSuccess), + (GetSharedObserver(), &OrthancApiClient::NotifyHttpSuccess), new OrthancStone::Callable<OrthancApiClient, IWebService::HttpRequestErrorMessage> - (*this, &OrthancApiClient::NotifyHttpError)); + (GetSharedObserver(), &OrthancApiClient::NotifyHttpError)); } void OrthancApiClient::PostJsonAsyncExpectJson( @@ -318,11 +299,11 @@ Orthanc::IDynamicObject* payload) { web_.DeleteAsync(baseUrl_ + uri, IWebService::HttpHeaders(), - new WebServicePayload(IObservable::GetBroker(), successCallback, failureCallback, payload), + new WebServicePayload(successCallback, failureCallback, payload), new OrthancStone::Callable<OrthancApiClient, IWebService::HttpRequestSuccessMessage> - (*this, &OrthancApiClient::NotifyHttpSuccess), + (GetSharedObserver(), &OrthancApiClient::NotifyHttpSuccess), new OrthancStone::Callable<OrthancApiClient, IWebService::HttpRequestErrorMessage> - (*this, &OrthancApiClient::NotifyHttpError)); + (GetSharedObserver(), &OrthancApiClient::NotifyHttpError)); }
--- a/Framework/Deprecated/Toolbox/OrthancApiClient.h Tue Nov 05 18:26:59 2019 +0100 +++ b/Framework/Deprecated/Toolbox/OrthancApiClient.h Tue Nov 05 18:51:04 2019 +0100 @@ -25,13 +25,13 @@ #include <json/json.h> #include "IWebService.h" -#include "../../Messages/IObservable.h" +#include "../../Messages/ObserverBase.h" namespace Deprecated { class OrthancApiClient : public OrthancStone::IObservable, - public OrthancStone::IObserver + public OrthancStone::ObserverBase<OrthancApiClient> { public: class JsonResponseReadyMessage : public OrthancStone::IMessage @@ -157,8 +157,7 @@ std::string baseUrl_; public: - OrthancApiClient(OrthancStone::MessageBroker& broker, - IWebService& web, + OrthancApiClient(IWebService& web, const std::string& baseUrl); virtual ~OrthancApiClient()
--- a/Framework/Deprecated/Toolbox/OrthancSlicesLoader.cpp Tue Nov 05 18:26:59 2019 +0100 +++ b/Framework/Deprecated/Toolbox/OrthancSlicesLoader.cpp Tue Nov 05 18:51:04 2019 +0100 @@ -639,10 +639,7 @@ } - OrthancSlicesLoader::OrthancSlicesLoader(OrthancStone::MessageBroker& broker, - OrthancApiClient& orthanc) : - OrthancStone::IObservable(broker), - OrthancStone::IObserver(broker), + OrthancSlicesLoader::OrthancSlicesLoader(boost::shared_ptr<OrthancApiClient> orthanc) : orthanc_(orthanc), state_(State_Initialization) { @@ -658,10 +655,10 @@ else { state_ = State_LoadingGeometry; - orthanc_.GetJsonAsync("/series/" + seriesId + "/instances-tags", - new OrthancStone::Callable<OrthancSlicesLoader, OrthancApiClient::JsonResponseReadyMessage>(*this, &OrthancSlicesLoader::ParseSeriesGeometry), - new OrthancStone::Callable<OrthancSlicesLoader, IWebService::HttpRequestErrorMessage>(*this, &OrthancSlicesLoader::OnGeometryError), - NULL); + orthanc_->GetJsonAsync("/series/" + seriesId + "/instances-tags", + new OrthancStone::Callable<OrthancSlicesLoader, OrthancApiClient::JsonResponseReadyMessage>(GetSharedObserver(), &OrthancSlicesLoader::ParseSeriesGeometry), + new OrthancStone::Callable<OrthancSlicesLoader, IWebService::HttpRequestErrorMessage>(GetSharedObserver(), &OrthancSlicesLoader::OnGeometryError), + NULL); } } @@ -677,10 +674,10 @@ // Tag "3004-000c" is "Grid Frame Offset Vector", which is // mandatory to read RT DOSE, but is too long to be returned by default - orthanc_.GetJsonAsync("/instances/" + instanceId + "/tags?ignore-length=3004-000c", - new OrthancStone::Callable<OrthancSlicesLoader, OrthancApiClient::JsonResponseReadyMessage>(*this, &OrthancSlicesLoader::ParseInstanceGeometry), - new OrthancStone::Callable<OrthancSlicesLoader, IWebService::HttpRequestErrorMessage>(*this, &OrthancSlicesLoader::OnGeometryError), - Operation::DownloadInstanceGeometry(instanceId)); + orthanc_->GetJsonAsync("/instances/" + instanceId + "/tags?ignore-length=3004-000c", + new OrthancStone::Callable<OrthancSlicesLoader, OrthancApiClient::JsonResponseReadyMessage>(GetSharedObserver(), &OrthancSlicesLoader::ParseInstanceGeometry), + new OrthancStone::Callable<OrthancSlicesLoader, IWebService::HttpRequestErrorMessage>(GetSharedObserver(), &OrthancSlicesLoader::OnGeometryError), + Operation::DownloadInstanceGeometry(instanceId)); } } @@ -696,10 +693,10 @@ { state_ = State_LoadingGeometry; - orthanc_.GetJsonAsync("/instances/" + instanceId + "/tags", - new OrthancStone::Callable<OrthancSlicesLoader, OrthancApiClient::JsonResponseReadyMessage>(*this, &OrthancSlicesLoader::ParseFrameGeometry), - new OrthancStone::Callable<OrthancSlicesLoader, IWebService::HttpRequestErrorMessage>(*this, &OrthancSlicesLoader::OnGeometryError), - Operation::DownloadFrameGeometry(instanceId, frame)); + orthanc_->GetJsonAsync("/instances/" + instanceId + "/tags", + new OrthancStone::Callable<OrthancSlicesLoader, OrthancApiClient::JsonResponseReadyMessage>(GetSharedObserver(), &OrthancSlicesLoader::ParseFrameGeometry), + new OrthancStone::Callable<OrthancSlicesLoader, IWebService::HttpRequestErrorMessage>(GetSharedObserver(), &OrthancSlicesLoader::OnGeometryError), + Operation::DownloadFrameGeometry(instanceId, frame)); } } @@ -770,23 +767,23 @@ throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); } - orthanc_.GetBinaryAsync(uri, "image/png", - new OrthancStone::Callable<OrthancSlicesLoader, - OrthancApiClient::BinaryResponseReadyMessage> - (*this, &OrthancSlicesLoader::ParseSliceImagePng), - new OrthancStone::Callable<OrthancSlicesLoader, - IWebService::HttpRequestErrorMessage> - (*this, &OrthancSlicesLoader::OnSliceImageError), - Operation::DownloadSliceImage( - static_cast<unsigned int>(index), slice, SliceImageQuality_FullPng)); -} + orthanc_->GetBinaryAsync(uri, "image/png", + new OrthancStone::Callable<OrthancSlicesLoader, + OrthancApiClient::BinaryResponseReadyMessage> + (GetSharedObserver(), &OrthancSlicesLoader::ParseSliceImagePng), + new OrthancStone::Callable<OrthancSlicesLoader, + IWebService::HttpRequestErrorMessage> + (GetSharedObserver(), &OrthancSlicesLoader::OnSliceImageError), + Operation::DownloadSliceImage( + static_cast<unsigned int>(index), slice, SliceImageQuality_FullPng)); + } void OrthancSlicesLoader::ScheduleSliceImagePam(const Slice& slice, size_t index) { std::string uri = ("/instances/" + slice.GetOrthancInstanceId() + "/frames/" + - boost::lexical_cast<std::string>(slice.GetFrame())); + boost::lexical_cast<std::string>(slice.GetFrame())); switch (slice.GetConverter().GetExpectedPixelFormat()) { @@ -806,15 +803,15 @@ throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); } - orthanc_.GetBinaryAsync(uri, "image/x-portable-arbitrarymap", - new OrthancStone::Callable<OrthancSlicesLoader, - OrthancApiClient::BinaryResponseReadyMessage> - (*this, &OrthancSlicesLoader::ParseSliceImagePam), - new OrthancStone::Callable<OrthancSlicesLoader, - IWebService::HttpRequestErrorMessage> - (*this, &OrthancSlicesLoader::OnSliceImageError), - Operation::DownloadSliceImage(static_cast<unsigned int>(index), - slice, SliceImageQuality_FullPam)); + orthanc_->GetBinaryAsync(uri, "image/x-portable-arbitrarymap", + new OrthancStone::Callable<OrthancSlicesLoader, + OrthancApiClient::BinaryResponseReadyMessage> + (GetSharedObserver(), &OrthancSlicesLoader::ParseSliceImagePam), + new OrthancStone::Callable<OrthancSlicesLoader, + IWebService::HttpRequestErrorMessage> + (GetSharedObserver(), &OrthancSlicesLoader::OnSliceImageError), + Operation::DownloadSliceImage(static_cast<unsigned int>(index), + slice, SliceImageQuality_FullPam)); } @@ -849,15 +846,15 @@ "-" + slice.GetOrthancInstanceId() + "_" + boost::lexical_cast<std::string>(slice.GetFrame())); - orthanc_.GetJsonAsync(uri, - new OrthancStone::Callable<OrthancSlicesLoader, - OrthancApiClient::JsonResponseReadyMessage> - (*this, &OrthancSlicesLoader::ParseSliceImageJpeg), - new OrthancStone::Callable<OrthancSlicesLoader, - IWebService::HttpRequestErrorMessage> - (*this, &OrthancSlicesLoader::OnSliceImageError), - Operation::DownloadSliceImage( - static_cast<unsigned int>(index), slice, quality)); + orthanc_->GetJsonAsync(uri, + new OrthancStone::Callable<OrthancSlicesLoader, + OrthancApiClient::JsonResponseReadyMessage> + (GetSharedObserver(), &OrthancSlicesLoader::ParseSliceImageJpeg), + new OrthancStone::Callable<OrthancSlicesLoader, + IWebService::HttpRequestErrorMessage> + (GetSharedObserver(), &OrthancSlicesLoader::OnSliceImageError), + Operation::DownloadSliceImage( + static_cast<unsigned int>(index), slice, quality)); } @@ -890,15 +887,15 @@ { std::string uri = ("/instances/" + slice.GetOrthancInstanceId() + "/frames/" + boost::lexical_cast<std::string>(slice.GetFrame()) + "/raw.gz"); - orthanc_.GetBinaryAsync(uri, IWebService::HttpHeaders(), - new OrthancStone::Callable<OrthancSlicesLoader, - OrthancApiClient::BinaryResponseReadyMessage> - (*this, &OrthancSlicesLoader::ParseSliceRawImage), - new OrthancStone::Callable<OrthancSlicesLoader, - IWebService::HttpRequestErrorMessage> - (*this, &OrthancSlicesLoader::OnSliceImageError), - Operation::DownloadSliceRawImage( - static_cast<unsigned int>(index), slice)); + orthanc_->GetBinaryAsync(uri, IWebService::HttpHeaders(), + new OrthancStone::Callable<OrthancSlicesLoader, + OrthancApiClient::BinaryResponseReadyMessage> + (GetSharedObserver(), &OrthancSlicesLoader::ParseSliceRawImage), + new OrthancStone::Callable<OrthancSlicesLoader, + IWebService::HttpRequestErrorMessage> + (GetSharedObserver(), &OrthancSlicesLoader::OnSliceImageError), + Operation::DownloadSliceRawImage( + static_cast<unsigned int>(index), slice)); } } }
--- a/Framework/Deprecated/Toolbox/OrthancSlicesLoader.h Tue Nov 05 18:26:59 2019 +0100 +++ b/Framework/Deprecated/Toolbox/OrthancSlicesLoader.h Tue Nov 05 18:51:04 2019 +0100 @@ -22,6 +22,7 @@ #pragma once #include "../../Messages/IObservable.h" +#include "../../Messages/ObserverBase.h" #include "../../StoneEnumerations.h" #include "../../Toolbox/SlicesSorter.h" #include "IWebService.h" @@ -33,7 +34,9 @@ namespace Deprecated { - class OrthancSlicesLoader : public OrthancStone::IObservable, public OrthancStone::IObserver + class OrthancSlicesLoader : + public OrthancStone::IObservable, + public OrthancStone::ObserverBase<OrthancSlicesLoader> { public: ORTHANC_STONE_DEFINE_ORIGIN_MESSAGE(__FILE__, __LINE__, SliceGeometryReadyMessage, OrthancSlicesLoader); @@ -143,7 +146,7 @@ class Operation; - OrthancApiClient& orthanc_; + boost::shared_ptr<OrthancApiClient> orthanc_; State state_; OrthancStone::SlicesSorter slices_; @@ -183,9 +186,8 @@ void SortAndFinalizeSlices(); public: - OrthancSlicesLoader(OrthancStone::MessageBroker& broker, - //ISliceLoaderObserver& callback, - OrthancApiClient& orthancApi); + OrthancSlicesLoader(//ISliceLoaderObserver& callback, + boost::shared_ptr<OrthancApiClient> orthancApi); void ScheduleLoadSeries(const std::string& seriesId);
--- a/Framework/Deprecated/Viewport/IViewport.h Tue Nov 05 18:26:59 2019 +0100 +++ b/Framework/Deprecated/Viewport/IViewport.h Tue Nov 05 18:51:04 2019 +0100 @@ -37,15 +37,6 @@ public: ORTHANC_STONE_DEFINE_ORIGIN_MESSAGE(__FILE__, __LINE__, ViewportChangedMessage, IViewport); - IViewport(OrthancStone::MessageBroker& broker) : - IObservable(broker) - { - } - - virtual ~IViewport() - { - } - virtual void FitContent() = 0; virtual void SetStatusBar(IStatusBar& statusBar) = 0;
--- a/Framework/Deprecated/Viewport/WidgetViewport.cpp Tue Nov 05 18:26:59 2019 +0100 +++ b/Framework/Deprecated/Viewport/WidgetViewport.cpp Tue Nov 05 18:51:04 2019 +0100 @@ -26,8 +26,7 @@ namespace Deprecated { - WidgetViewport::WidgetViewport(OrthancStone::MessageBroker& broker) : - IViewport(broker), + WidgetViewport::WidgetViewport() : statusBar_(NULL), isMouseOver_(false), lastMouseX_(0), @@ -57,7 +56,7 @@ } - IWidget& WidgetViewport::SetCentralWidget(IWidget* widget) + void WidgetViewport::SetCentralWidget(boost::shared_ptr<IWidget> widget) { if (widget == NULL) { @@ -66,7 +65,7 @@ mouseTracker_.reset(NULL); - centralWidget_.reset(widget); + centralWidget_ = widget; centralWidget_->SetViewport(*this); if (statusBar_ != NULL) @@ -75,8 +74,6 @@ } NotifyBackgroundChanged(); - - return *widget; }
--- a/Framework/Deprecated/Viewport/WidgetViewport.h Tue Nov 05 18:26:59 2019 +0100 +++ b/Framework/Deprecated/Viewport/WidgetViewport.h Tue Nov 05 18:51:04 2019 +0100 @@ -31,7 +31,7 @@ class WidgetViewport : public IViewport { private: - std::auto_ptr<IWidget> centralWidget_; + boost::shared_ptr<IWidget> centralWidget_; IStatusBar* statusBar_; std::auto_ptr<IMouseTracker> mouseTracker_; bool isMouseOver_; @@ -41,13 +41,13 @@ bool backgroundChanged_; public: - WidgetViewport(OrthancStone::MessageBroker& broker); + WidgetViewport(); virtual void FitContent(); virtual void SetStatusBar(IStatusBar& statusBar); - IWidget& SetCentralWidget(IWidget* widget); // Takes ownership + void SetCentralWidget(boost::shared_ptr<IWidget> widget); virtual void NotifyBackgroundChanged();
--- a/Framework/Deprecated/Volumes/ISlicedVolume.h Tue Nov 05 18:26:59 2019 +0100 +++ b/Framework/Deprecated/Volumes/ISlicedVolume.h Tue Nov 05 18:51:04 2019 +0100 @@ -65,11 +65,6 @@ }; - ISlicedVolume(OrthancStone::MessageBroker& broker) : - IObservable(broker) - { - } - virtual size_t GetSliceCount() const = 0; virtual const Slice& GetSlice(size_t slice) const = 0;
--- a/Framework/Deprecated/Volumes/IVolumeLoader.h Tue Nov 05 18:26:59 2019 +0100 +++ b/Framework/Deprecated/Volumes/IVolumeLoader.h Tue Nov 05 18:51:04 2019 +0100 @@ -31,10 +31,5 @@ ORTHANC_STONE_DEFINE_ORIGIN_MESSAGE(__FILE__, __LINE__, GeometryReadyMessage, IVolumeLoader); ORTHANC_STONE_DEFINE_ORIGIN_MESSAGE(__FILE__, __LINE__, GeometryErrorMessage, IVolumeLoader); ORTHANC_STONE_DEFINE_ORIGIN_MESSAGE(__FILE__, __LINE__, ContentChangedMessage, IVolumeLoader); - - IVolumeLoader(OrthancStone::MessageBroker& broker) : - IObservable(broker) - { - } }; }
--- a/Framework/Deprecated/Volumes/StructureSetLoader.cpp Tue Nov 05 18:26:59 2019 +0100 +++ b/Framework/Deprecated/Volumes/StructureSetLoader.cpp Tue Nov 05 18:51:04 2019 +0100 @@ -27,10 +27,7 @@ namespace Deprecated { - StructureSetLoader::StructureSetLoader(OrthancStone::MessageBroker& broker, - OrthancApiClient& orthanc) : - IVolumeLoader(broker), - IObserver(broker), + StructureSetLoader::StructureSetLoader(OrthancApiClient& orthanc) : orthanc_(orthanc) { } @@ -60,7 +57,7 @@ it != instances.end(); ++it) { orthanc_.PostBinaryAsyncExpectJson("/tools/lookup", *it, - new OrthancStone::Callable<StructureSetLoader, OrthancApiClient::JsonResponseReadyMessage>(*this, &StructureSetLoader::OnLookupCompleted)); + new OrthancStone::Callable<StructureSetLoader, OrthancApiClient::JsonResponseReadyMessage>(GetSharedObserver(), &StructureSetLoader::OnLookupCompleted)); } BroadcastMessage(GeometryReadyMessage(*this)); @@ -84,7 +81,7 @@ const std::string& instance = lookup[0]["ID"].asString(); orthanc_.GetJsonAsync("/instances/" + instance + "/tags", - new OrthancStone::Callable<StructureSetLoader, OrthancApiClient::JsonResponseReadyMessage>(*this, &StructureSetLoader::OnReferencedSliceLoaded)); + new OrthancStone::Callable<StructureSetLoader, OrthancApiClient::JsonResponseReadyMessage>(GetSharedObserver(), &StructureSetLoader::OnReferencedSliceLoaded)); } @@ -97,7 +94,7 @@ else { orthanc_.GetJsonAsync("/instances/" + instance + "/tags?ignore-length=3006-0050", - new OrthancStone::Callable<StructureSetLoader, OrthancApiClient::JsonResponseReadyMessage>(*this, &StructureSetLoader::OnStructureSetLoaded)); + new OrthancStone::Callable<StructureSetLoader, OrthancApiClient::JsonResponseReadyMessage>(GetSharedObserver(), &StructureSetLoader::OnStructureSetLoaded)); } }
--- a/Framework/Deprecated/Volumes/StructureSetLoader.h Tue Nov 05 18:26:59 2019 +0100 +++ b/Framework/Deprecated/Volumes/StructureSetLoader.h Tue Nov 05 18:51:04 2019 +0100 @@ -21,6 +21,7 @@ #pragma once +#include "../../Messages/ObserverBase.h" #include "../../Toolbox/DicomStructureSet.h" #include "../Toolbox/OrthancApiClient.h" #include "IVolumeLoader.h" @@ -29,7 +30,7 @@ { class StructureSetLoader : public IVolumeLoader, - public OrthancStone::IObserver + public OrthancStone::ObserverBase<StructureSetLoader> { private: OrthancApiClient& orthanc_; @@ -42,8 +43,7 @@ void OnLookupCompleted(const OrthancApiClient::JsonResponseReadyMessage& message); public: - StructureSetLoader(OrthancStone::MessageBroker& broker, - OrthancApiClient& orthanc); + StructureSetLoader(OrthancApiClient& orthanc); void ScheduleLoadInstance(const std::string& instance);
--- a/Framework/Deprecated/Widgets/LayoutWidget.cpp Tue Nov 05 18:26:59 2019 +0100 +++ b/Framework/Deprecated/Widgets/LayoutWidget.cpp Tue Nov 05 18:51:04 2019 +0100 @@ -85,14 +85,14 @@ class LayoutWidget::ChildWidget : public boost::noncopyable { private: - std::auto_ptr<IWidget> widget_; + boost::shared_ptr<IWidget> widget_; int left_; int top_; unsigned int width_; unsigned int height_; public: - ChildWidget(IWidget* widget) : + ChildWidget(boost::shared_ptr<IWidget> widget) : widget_(widget) { assert(widget != NULL); @@ -354,7 +354,7 @@ } - IWidget& LayoutWidget::AddWidget(IWidget* widget) // Takes ownership + void LayoutWidget::AddWidget(boost::shared_ptr<IWidget> widget) // Takes ownership { if (widget == NULL) { @@ -375,8 +375,6 @@ { hasAnimation_ = true; } - - return *widget; }
--- a/Framework/Deprecated/Widgets/LayoutWidget.h Tue Nov 05 18:26:59 2019 +0100 +++ b/Framework/Deprecated/Widgets/LayoutWidget.h Tue Nov 05 18:51:04 2019 +0100 @@ -94,7 +94,7 @@ return paddingInternal_; } - IWidget& AddWidget(IWidget* widget); // Takes ownership + void AddWidget(boost::shared_ptr<IWidget> widget); virtual void SetStatusBar(IStatusBar& statusBar);
--- a/Framework/Deprecated/Widgets/SliceViewerWidget.cpp Tue Nov 05 18:26:59 2019 +0100 +++ b/Framework/Deprecated/Widgets/SliceViewerWidget.cpp Tue Nov 05 18:51:04 2019 +0100 @@ -250,7 +250,7 @@ { index = found->second; assert(index < layers_.size() && - layers_[index] == &layer); + layers_[index].get() == &layer); return true; } } @@ -364,42 +364,27 @@ } - SliceViewerWidget::SliceViewerWidget(OrthancStone::MessageBroker& broker, - const std::string& name) : + SliceViewerWidget::SliceViewerWidget(const std::string& name) : WorldSceneWidget(name), - IObserver(broker), - IObservable(broker), started_(false) { SetBackgroundCleared(true); } - SliceViewerWidget::~SliceViewerWidget() - { - for (size_t i = 0; i < layers_.size(); i++) - { - delete layers_[i]; - } - } - void SliceViewerWidget::ObserveLayer(IVolumeSlicer& layer) { - layer.RegisterObserverCallback(new OrthancStone::Callable<SliceViewerWidget, IVolumeSlicer::GeometryReadyMessage> - (*this, &SliceViewerWidget::OnGeometryReady)); - // currently ignore errors layer->RegisterObserverCallback(new Callable<SliceViewerWidget, IVolumeSlicer::GeometryErrorMessage>(*this, &SliceViewerWidget::...)); - layer.RegisterObserverCallback(new OrthancStone::Callable<SliceViewerWidget, IVolumeSlicer::SliceContentChangedMessage> - (*this, &SliceViewerWidget::OnSliceChanged)); - layer.RegisterObserverCallback(new OrthancStone::Callable<SliceViewerWidget, IVolumeSlicer::ContentChangedMessage> - (*this, &SliceViewerWidget::OnContentChanged)); - layer.RegisterObserverCallback(new OrthancStone::Callable<SliceViewerWidget, IVolumeSlicer::LayerReadyMessage> - (*this, &SliceViewerWidget::OnLayerReady)); - layer.RegisterObserverCallback(new OrthancStone::Callable<SliceViewerWidget, IVolumeSlicer::LayerErrorMessage> - (*this, &SliceViewerWidget::OnLayerError)); + // currently ignoring errors of type IVolumeSlicer::GeometryErrorMessage + + Register<IVolumeSlicer::GeometryReadyMessage>(layer, &SliceViewerWidget::OnGeometryReady); + Register<IVolumeSlicer::SliceContentChangedMessage>(layer, &SliceViewerWidget::OnSliceChanged); + Register<IVolumeSlicer::ContentChangedMessage>(layer, &SliceViewerWidget::OnContentChanged); + Register<IVolumeSlicer::LayerReadyMessage>(layer, &SliceViewerWidget::OnLayerReady); + Register<IVolumeSlicer::LayerErrorMessage>(layer, &SliceViewerWidget::OnLayerError); } - size_t SliceViewerWidget::AddLayer(IVolumeSlicer* layer) // Takes ownership + size_t SliceViewerWidget::AddLayer(boost::shared_ptr<IVolumeSlicer> layer) { if (layer == NULL) { @@ -409,7 +394,7 @@ size_t index = layers_.size(); layers_.push_back(layer); styles_.push_back(RenderStyle()); - layersIndex_[layer] = index; + layersIndex_[layer.get()] = index; ResetPendingScene(); @@ -421,7 +406,8 @@ } - void SliceViewerWidget::ReplaceLayer(size_t index, IVolumeSlicer* layer) // Takes ownership + void SliceViewerWidget::ReplaceLayer(size_t index, + boost::shared_ptr<IVolumeSlicer> layer) { if (layer == NULL) { @@ -433,9 +419,8 @@ throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); } - delete layers_[index]; layers_[index] = layer; - layersIndex_[layer] = index; + layersIndex_[layer.get()] = index; ResetPendingScene(); @@ -452,13 +437,13 @@ throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); } - IVolumeSlicer* previousLayer = layers_[index]; + IVolumeSlicer* previousLayer = layers_[index].get(); layersIndex_.erase(layersIndex_.find(previousLayer)); layers_.erase(layers_.begin() + index); changedLayers_.erase(changedLayers_.begin() + index); styles_.erase(styles_.begin() + index); - delete layers_[index]; + layers_[index].reset(); currentScene_->DeleteLayer(index); ResetPendingScene();
--- a/Framework/Deprecated/Widgets/SliceViewerWidget.h Tue Nov 05 18:26:59 2019 +0100 +++ b/Framework/Deprecated/Widgets/SliceViewerWidget.h Tue Nov 05 18:51:04 2019 +0100 @@ -24,7 +24,7 @@ #include "WorldSceneWidget.h" #include "../Layers/IVolumeSlicer.h" #include "../../Toolbox/Extent2D.h" -#include "../../Messages/IObserver.h" +#include "../../Messages/ObserverBase.h" #include <map> @@ -32,7 +32,7 @@ { class SliceViewerWidget : public WorldSceneWidget, - public OrthancStone::IObserver, + public OrthancStone::ObserverBase<SliceViewerWidget>, public OrthancStone::IObservable { public: @@ -72,7 +72,7 @@ bool started_; LayersIndex layersIndex_; - std::vector<IVolumeSlicer*> layers_; + std::vector<boost::shared_ptr<IVolumeSlicer> > layers_; std::vector<RenderStyle> styles_; OrthancStone::CoordinateSystem3D plane_; std::auto_ptr<Scene> currentScene_; @@ -100,8 +100,7 @@ void ResetChangedLayers(); public: - SliceViewerWidget(OrthancStone::MessageBroker& broker, - const std::string& name); + SliceViewerWidget(const std::string& name); virtual OrthancStone::Extent2D GetSceneExtent(); @@ -120,11 +119,13 @@ void InvalidateLayer(size_t layer); public: - virtual ~SliceViewerWidget(); + virtual ~SliceViewerWidget() + { + } - size_t AddLayer(IVolumeSlicer* layer); // Takes ownership + size_t AddLayer(boost::shared_ptr<IVolumeSlicer> layer); - void ReplaceLayer(size_t layerIndex, IVolumeSlicer* layer); // Takes ownership + void ReplaceLayer(size_t layerIndex, boost::shared_ptr<IVolumeSlicer> layer); // Takes ownership void RemoveLayer(size_t layerIndex);
--- a/Framework/Loaders/DicomStructureSetLoader.cpp Tue Nov 05 18:26:59 2019 +0100 +++ b/Framework/Loaders/DicomStructureSetLoader.cpp Tue Nov 05 18:51:04 2019 +0100 @@ -347,7 +347,6 @@ DicomStructureSetLoader::DicomStructureSetLoader(IOracle& oracle, IObservable& oracleObservable) : LoaderStateMachine(oracle, oracleObservable), - IObservable(oracleObservable.GetBroker()), revision_(0), countProcessedInstances_(0), countReferencedInstances_(0),
--- a/Framework/Loaders/LoaderCache.cpp Tue Nov 05 18:26:59 2019 +0100 +++ b/Framework/Loaders/LoaderCache.cpp Tue Nov 05 18:51:04 2019 +0100 @@ -65,7 +65,7 @@ } #else - LoaderCache::LoaderCache(ThreadedOracle& oracle, LockingEmitter& lockingEmitter) + LoaderCache::LoaderCache(ThreadedOracle& oracle, Deprecated::LockingEmitter& lockingEmitter) : oracle_(oracle) , lockingEmitter_(lockingEmitter) { @@ -98,7 +98,7 @@ #if ORTHANC_ENABLE_WASM == 1 loader.reset(new OrthancSeriesVolumeProgressiveLoader(volumeImage, oracle_, oracle_)); #else - LockingEmitter::WriterLock lock(lockingEmitter_); + Deprecated::LockingEmitter::WriterLock lock(lockingEmitter_); loader.reset(new OrthancSeriesVolumeProgressiveLoader(volumeImage, oracle_, lock.GetOracleObservable())); #endif // LOG(TRACE) << "LoaderCache::GetSeriesVolumeProgressiveLoader : loader = " << loader.get(); @@ -167,10 +167,8 @@ #if ORTHANC_ENABLE_WASM == 1 loader.reset(new OrthancMultiframeVolumeLoader(volumeImage, oracle_, oracle_)); #else - LockingEmitter::WriterLock lock(lockingEmitter_); - loader.reset(new OrthancMultiframeVolumeLoader(volumeImage, - oracle_, - lock.GetOracleObservable())); + Deprecated::LockingEmitter::WriterLock lock(lockingEmitter_); + loader.reset(new OrthancMultiframeVolumeLoader(volumeImage, oracle_, lock.GetOracleObservable())); #endif loader->LoadInstance(instanceUuid); } @@ -270,7 +268,7 @@ #if ORTHANC_ENABLE_WASM == 1 loader.reset(new DicomStructureSetLoader(oracle_, oracle_)); #else - LockingEmitter::WriterLock lock(lockingEmitter_); + Deprecated::LockingEmitter::WriterLock lock(lockingEmitter_); loader.reset(new DicomStructureSetLoader(oracle_, lock.GetOracleObservable())); #endif loader->LoadInstance(inInstanceUuid, initiallyVisibleStructures); @@ -366,7 +364,7 @@ void LoaderCache::ClearCache() { #if ORTHANC_ENABLE_WASM != 1 - LockingEmitter::WriterLock lock(lockingEmitter_); + Deprecated::LockingEmitter::WriterLock lock(lockingEmitter_); #endif //#ifndef NDEBUG
--- a/Framework/Loaders/LoaderCache.h Tue Nov 05 18:26:59 2019 +0100 +++ b/Framework/Loaders/LoaderCache.h Tue Nov 05 18:51:04 2019 +0100 @@ -43,7 +43,10 @@ class WebAssemblyOracle; #else class ThreadedOracle; - class LockingEmitter; + namespace Deprecated + { + class LockingEmitter; + } #endif class LoaderCache @@ -52,7 +55,7 @@ #if ORTHANC_ENABLE_WASM == 1 LoaderCache(WebAssemblyOracle& oracle); #else - LoaderCache(ThreadedOracle& oracle, LockingEmitter& lockingEmitter); + LoaderCache(ThreadedOracle& oracle, Deprecated::LockingEmitter& lockingEmitter); #endif boost::shared_ptr<OrthancSeriesVolumeProgressiveLoader> @@ -87,7 +90,7 @@ WebAssemblyOracle& oracle_; #else ThreadedOracle& oracle_; - LockingEmitter& lockingEmitter_; + Deprecated::LockingEmitter& lockingEmitter_; #endif std::map<std::string, boost::shared_ptr<OrthancSeriesVolumeProgressiveLoader> >
--- a/Framework/Loaders/LoaderStateMachine.cpp Tue Nov 05 18:26:59 2019 +0100 +++ b/Framework/Loaders/LoaderStateMachine.cpp Tue Nov 05 18:51:04 2019 +0100 @@ -97,7 +97,8 @@ ") < simultaneousDownloads_ (" << simultaneousDownloads_ << ") --> will Schedule command addr " << std::hex << nextCommand << std::dec; - oracle_.Schedule(*this, nextCommand); + boost::shared_ptr<IObserver> observer(GetSharedObserver()); + oracle_.Schedule(observer, nextCommand); pendingCommands_.pop_front(); activeCommands_++; @@ -136,7 +137,6 @@ template <typename T> void LoaderStateMachine::HandleSuccessMessage(const T& message) { - LOG(TRACE) << "LoaderStateMachine(" << std::hex << this << std::dec << ")::HandleSuccessMessage(). Receiver fingerprint = " << GetFingerprint(); if (activeCommands_ <= 0) { LOG(ERROR) << "LoaderStateMachine(" << std::hex << this << std::dec << ")::HandleSuccessMessage : activeCommands_ should be > 0 but is: " << activeCommands_; } @@ -159,35 +159,22 @@ LoaderStateMachine::LoaderStateMachine(IOracle& oracle, IObservable& oracleObservable) : - IObserver(oracleObservable.GetBroker()), oracle_(oracle), - oracleObservable_(oracleObservable), active_(false), simultaneousDownloads_(4), activeCommands_(0) { LOG(TRACE) << "LoaderStateMachine(" << std::hex << this << std::dec << ")::LoaderStateMachine()"; - oracleObservable.RegisterObserverCallback( - new Callable<LoaderStateMachine, OrthancRestApiCommand::SuccessMessage> - (*this, &LoaderStateMachine::HandleSuccessMessage)); - - oracleObservable.RegisterObserverCallback( - new Callable<LoaderStateMachine, GetOrthancImageCommand::SuccessMessage> - (*this, &LoaderStateMachine::HandleSuccessMessage)); - - oracleObservable.RegisterObserverCallback( - new Callable<LoaderStateMachine, GetOrthancWebViewerJpegCommand::SuccessMessage> - (*this, &LoaderStateMachine::HandleSuccessMessage)); - - oracleObservable.RegisterObserverCallback( - new Callable<LoaderStateMachine, OracleCommandExceptionMessage> - (*this, &LoaderStateMachine::HandleExceptionMessage)); + // TODO => Move this out of constructor + Register<OrthancRestApiCommand::SuccessMessage>(oracleObservable, &LoaderStateMachine::HandleSuccessMessage); + Register<GetOrthancImageCommand::SuccessMessage>(oracleObservable, &LoaderStateMachine::HandleSuccessMessage); + Register<GetOrthancWebViewerJpegCommand::SuccessMessage>(oracleObservable, &LoaderStateMachine::HandleSuccessMessage); + Register<OracleCommandExceptionMessage>(oracleObservable, &LoaderStateMachine::HandleExceptionMessage); } LoaderStateMachine::~LoaderStateMachine() { - oracleObservable_.Unregister(this); LOG(TRACE) << "LoaderStateMachine(" << std::hex << this << std::dec << ")::~LoaderStateMachine()"; Clear(); }
--- a/Framework/Loaders/LoaderStateMachine.h Tue Nov 05 18:26:59 2019 +0100 +++ b/Framework/Loaders/LoaderStateMachine.h Tue Nov 05 18:51:04 2019 +0100 @@ -22,7 +22,7 @@ #pragma once #include "../Messages/IObservable.h" -#include "../Messages/IObserver.h" +#include "../Messages/ObserverBase.h" #include "../Oracle/GetOrthancImageCommand.h" #include "../Oracle/GetOrthancWebViewerJpegCommand.h" #include "../Oracle/IOracle.h" @@ -41,7 +41,7 @@ rest once slots become available. It is used, a.o., by the OrtancMultiframeVolumeLoader class. */ - class LoaderStateMachine : public IObserver + class LoaderStateMachine : public ObserverBase<LoaderStateMachine> { protected: class State : public Orthanc::IDynamicObject @@ -95,7 +95,6 @@ typedef std::list<IOracleCommand*> PendingCommands; IOracle& oracle_; - IObservable& oracleObservable_; bool active_; unsigned int simultaneousDownloads_; PendingCommands pendingCommands_;
--- a/Framework/Loaders/OrthancMultiframeVolumeLoader.cpp Tue Nov 05 18:26:59 2019 +0100 +++ b/Framework/Loaders/OrthancMultiframeVolumeLoader.cpp Tue Nov 05 18:51:04 2019 +0100 @@ -345,7 +345,6 @@ IOracle& oracle, IObservable& oracleObservable) : LoaderStateMachine(oracle, oracleObservable), - IObservable(oracleObservable.GetBroker()), volume_(volume), pixelDataLoaded_(false) {
--- a/Framework/Loaders/OrthancSeriesVolumeProgressiveLoader.cpp Tue Nov 05 18:26:59 2019 +0100 +++ b/Framework/Loaders/OrthancSeriesVolumeProgressiveLoader.cpp Tue Nov 05 18:51:04 2019 +0100 @@ -292,7 +292,9 @@ } command->SetPayload(new Orthanc::SingleValueObject<unsigned int>(sliceIndex)); - oracle_.Schedule(*this, command.release()); + + boost::shared_ptr<IObserver> observer(GetSharedObserver()); + oracle_.Schedule(observer, command.release()); } else { @@ -421,32 +423,26 @@ OrthancSeriesVolumeProgressiveLoader::OrthancSeriesVolumeProgressiveLoader(const boost::shared_ptr<DicomVolumeImage>& volume, IOracle& oracle, IObservable& oracleObservable) : - IObserver(oracleObservable.GetBroker()), - IObservable(oracleObservable.GetBroker()), oracle_(oracle), - oracleObservable_(oracleObservable), active_(false), simultaneousDownloads_(4), volume_(volume), sorter_(new BasicFetchingItemsSorter::Factory), volumeImageReadyInHighQuality_(false) { - oracleObservable.RegisterObserverCallback( - new Callable<OrthancSeriesVolumeProgressiveLoader, OrthancRestApiCommand::SuccessMessage> - (*this, &OrthancSeriesVolumeProgressiveLoader::LoadGeometry)); + // TODO => Move this out of constructor + Register<OrthancRestApiCommand::SuccessMessage> + (oracleObservable, &OrthancSeriesVolumeProgressiveLoader::LoadGeometry); - oracleObservable.RegisterObserverCallback( - new Callable<OrthancSeriesVolumeProgressiveLoader, GetOrthancImageCommand::SuccessMessage> - (*this, &OrthancSeriesVolumeProgressiveLoader::LoadBestQualitySliceContent)); + Register<GetOrthancImageCommand::SuccessMessage> + (oracleObservable, &OrthancSeriesVolumeProgressiveLoader::LoadBestQualitySliceContent); - oracleObservable.RegisterObserverCallback( - new Callable<OrthancSeriesVolumeProgressiveLoader, GetOrthancWebViewerJpegCommand::SuccessMessage> - (*this, &OrthancSeriesVolumeProgressiveLoader::LoadJpegSliceContent)); + Register<GetOrthancWebViewerJpegCommand::SuccessMessage> + (oracleObservable, &OrthancSeriesVolumeProgressiveLoader::LoadJpegSliceContent); } OrthancSeriesVolumeProgressiveLoader::~OrthancSeriesVolumeProgressiveLoader() { - oracleObservable_.Unregister(this); LOG(TRACE) << "OrthancSeriesVolumeProgressiveLoader::~OrthancSeriesVolumeProgressiveLoader()"; } @@ -485,7 +481,8 @@ command->SetUri("/series/" + seriesId + "/instances-tags"); // LOG(TRACE) << "OrthancSeriesVolumeProgressiveLoader::LoadSeries about to call oracle_.Schedule"; - oracle_.Schedule(*this, command.release()); + boost::shared_ptr<IObserver> observer(GetSharedObserver()); + oracle_.Schedule(observer, command.release()); // LOG(TRACE) << "OrthancSeriesVolumeProgressiveLoader::LoadSeries called oracle_.Schedule"; } }
--- a/Framework/Loaders/OrthancSeriesVolumeProgressiveLoader.h Tue Nov 05 18:26:59 2019 +0100 +++ b/Framework/Loaders/OrthancSeriesVolumeProgressiveLoader.h Tue Nov 05 18:51:04 2019 +0100 @@ -22,7 +22,7 @@ #pragma once #include "../Messages/IObservable.h" -#include "../Messages/IObserver.h" +#include "../Messages/ObserverBase.h" #include "../Oracle/GetOrthancImageCommand.h" #include "../Oracle/GetOrthancWebViewerJpegCommand.h" #include "../Oracle/IOracle.h" @@ -42,7 +42,7 @@ is stored in a Dicom series. */ class OrthancSeriesVolumeProgressiveLoader : - public IObserver, + public ObserverBase<OrthancSeriesVolumeProgressiveLoader>, public IObservable, public IVolumeSlicer, public IGeometryProvider @@ -106,7 +106,6 @@ void LoadJpegSliceContent(const GetOrthancWebViewerJpegCommand::SuccessMessage& message); IOracle& oracle_; - IObservable& oracleObservable_; bool active_; unsigned int simultaneousDownloads_; SeriesGeometry seriesGeometry_;
--- a/Framework/Messages/ICallable.h Tue Nov 05 18:26:59 2019 +0100 +++ b/Framework/Messages/ICallable.h Tue Nov 05 18:51:04 2019 +0100 @@ -22,20 +22,20 @@ #pragma once #include "IMessage.h" +#include "IObserver.h" #include <Core/Logging.h> #include <boost/noncopyable.hpp> +#include <boost/weak_ptr.hpp> #include <string> -namespace OrthancStone { - - class IObserver; - +namespace OrthancStone +{ // This is referencing an object and member function that can be notified // by an IObservable. The object must derive from IO - // The member functions must be of type "void Function(const IMessage& message)" or reference a derived class of IMessage + // The member functions must be of type "void Method(const IMessage& message)" or reference a derived class of IMessage class ICallable : public boost::noncopyable { public: @@ -47,11 +47,14 @@ virtual const MessageIdentifier& GetMessageIdentifier() = 0; - virtual IObserver* GetObserver() const = 0; + // TODO - Is this needed? + virtual boost::weak_ptr<IObserver> GetObserver() const = 0; }; + + // TODO - Remove this class template <typename TMessage> - class MessageHandler: public ICallable + class MessageHandler : public ICallable { }; @@ -61,47 +64,28 @@ class Callable : public MessageHandler<TMessage> { private: - typedef void (TObserver::* MemberFunction) (const TMessage&); + typedef void (TObserver::* MemberMethod) (const TMessage&); - TObserver& observer_; - MemberFunction function_; - std::string observerFingerprint_; + boost::weak_ptr<IObserver> observer_; + MemberMethod function_; public: - Callable(TObserver& observer, - MemberFunction function) : + Callable(boost::shared_ptr<TObserver> observer, + MemberMethod function) : observer_(observer), - function_(function), - observerFingerprint_(observer.GetFingerprint()) - { - } - - void ApplyInternal(const TMessage& message) + function_(function) { - std::string currentFingerprint(observer_.GetFingerprint()); - if (observerFingerprint_ != currentFingerprint) - { - LOG(TRACE) << "The observer at address " << - std::hex << &observer_ << std::dec << - ") has a different fingerprint than the one recorded at callback " << - "registration time. This means that it is not the same object as " << - "the one recorded, even though their addresses are the same. " << - "Callback will NOT be sent!"; - LOG(TRACE) << " recorded fingerprint = " << observerFingerprint_ << - " current fingerprint = " << currentFingerprint; - } - else - { - LOG(TRACE) << "The recorded fingerprint is " << observerFingerprint_ - << " and the current fingerprint is " << currentFingerprint - << " -- callable will be called."; - (observer_.*function_) (message); - } } virtual void Apply(const IMessage& message) { - ApplyInternal(dynamic_cast<const TMessage&>(message)); + boost::shared_ptr<IObserver> lock(observer_); + if (lock) + { + TObserver& observer = dynamic_cast<TObserver&>(*lock); + const TMessage& typedMessage = dynamic_cast<const TMessage&>(message); + (observer.*function_) (typedMessage); + } } virtual const MessageIdentifier& GetMessageIdentifier() @@ -109,41 +93,9 @@ return TMessage::GetStaticIdentifier(); } - virtual IObserver* GetObserver() const + virtual boost::weak_ptr<IObserver> GetObserver() const { - return &observer_; + return observer_; } }; - -#if 0 /* __cplusplus >= 201103L*/ - -#include <functional> - - template <typename TMessage> - class LambdaCallable : public MessageHandler<TMessage> - { - private: - - IObserver& observer_; - std::function<void (const TMessage&)> lambda_; - - public: - LambdaCallable(IObserver& observer, - std::function<void (const TMessage&)> lambdaFunction) : - observer_(observer), - lambda_(lambdaFunction) - { - } - - virtual void Apply(const IMessage& message) - { - lambda_(dynamic_cast<const TMessage&>(message)); - } - - virtual IObserver* GetObserver() const - { - return &observer_; - } - }; -#endif //__cplusplus >= 201103L }
--- a/Framework/Messages/IMessage.h Tue Nov 05 18:26:59 2019 +0100 +++ b/Framework/Messages/IMessage.h Tue Nov 05 18:51:04 2019 +0100 @@ -21,6 +21,7 @@ #pragma once +#include <boost/lexical_cast.hpp> #include <boost/noncopyable.hpp> #include <string.h> @@ -33,6 +34,12 @@ const char* file_; int line_; + bool IsEqual(const MessageIdentifier& other) const + { + return (line_ == other.line_ && + strcmp(file_, other.file_) == 0); + } + public: MessageIdentifier(const char* file, int line) : @@ -47,6 +54,11 @@ { } + std::string AsString() const + { + return std::string(file_) + ":" + boost::lexical_cast<std::string>(line_); + } + bool operator< (const MessageIdentifier& other) const { if (file_ == NULL) @@ -62,6 +74,16 @@ return strcmp(file_, other.file_) < 0; } } + + bool operator== (const MessageIdentifier& other) const + { + return IsEqual(other); + } + + bool operator!= (const MessageIdentifier& other) const + { + return !IsEqual(other); + } };
--- a/Framework/Messages/IMessageEmitter.h Tue Nov 05 18:26:59 2019 +0100 +++ b/Framework/Messages/IMessageEmitter.h Tue Nov 05 18:51:04 2019 +0100 @@ -24,6 +24,8 @@ #include "IObserver.h" #include "IMessage.h" +#include <boost/weak_ptr.hpp> + namespace OrthancStone { /** @@ -39,7 +41,7 @@ { } - virtual void EmitMessage(const IObserver& observer, + virtual void EmitMessage(boost::weak_ptr<IObserver> observer, const IMessage& message) = 0; }; }
--- a/Framework/Messages/IObservable.cpp Tue Nov 05 18:26:59 2019 +0100 +++ b/Framework/Messages/IObservable.cpp Tue Nov 05 18:51:04 2019 +0100 @@ -21,8 +21,9 @@ #include "IObservable.h" +#include "../StoneException.h" + #include <Core/Logging.h> -#include <Core/OrthancException.h> #include <cassert> @@ -40,20 +41,10 @@ delete *it2; } } - - // unregister the forwarders but don't delete them (they'll be - // deleted by the observable they are observing as any other - // callable) - for (Forwarders::iterator it = forwarders_.begin(); - it != forwarders_.end(); ++it) - { - IMessageForwarder* fw = *it; - broker_.Unregister(dynamic_cast<IObserver&>(*fw)); - } } - void IObservable::RegisterObserverCallback(ICallable* callable) + void IObservable::RegisterCallable(ICallable* callable) { if (callable == NULL) { @@ -64,30 +55,6 @@ callables_[id].insert(callable); } - void IObservable::Unregister(IObserver *observer) - { - LOG(TRACE) << "IObservable::Unregister for IObserver at addr: " - << std::hex << observer << std::dec; - // delete all callables from this observer - for (Callables::iterator itCallableSet = callables_.begin(); - itCallableSet != callables_.end(); ++itCallableSet) - { - for (std::set<ICallable*>::const_iterator - itCallable = itCallableSet->second.begin(); itCallable != itCallableSet->second.end(); ) - { - if ((*itCallable)->GetObserver() == observer) - { - LOG(TRACE) << " ** IObservable::Unregister : deleting callable: " - << std::hex << (*itCallable) << std::dec; - delete *itCallable; - itCallableSet->second.erase(itCallable++); - } - else - ++itCallable; - } - } - } - void IObservable::EmitMessageInternal(const IObserver* receiver, const IMessage& message) { @@ -102,15 +69,36 @@ { assert(*it != NULL); - const IObserver* observer = (*it)->GetObserver(); - if (broker_.IsActive(*observer)) + boost::shared_ptr<IObserver> observer((*it)->GetObserver().lock()); + + if (observer) { if (receiver == NULL || // Are we broadcasting? - observer == receiver) // Not broadcasting, but this is the receiver + observer.get() == receiver) // Not broadcasting, but this is the receiver { - (*it)->Apply(message); + try + { + (*it)->Apply(message); + } + catch (Orthanc::OrthancException& e) + { + LOG(ERROR) << "Exception on callable: " << e.What(); + } + catch (StoneException& e) + { + LOG(ERROR) << "Exception on callable: " << e.What(); + } + catch (...) + { + LOG(ERROR) << "Native exception on callable"; + } } } + else + { + // TODO => Remove "it" from the list of callables => This + // allows to suppress the need for "Unregister()" + } } } } @@ -122,21 +110,16 @@ } - void IObservable::EmitMessage(const IObserver& observer, + void IObservable::EmitMessage(boost::weak_ptr<IObserver> observer, const IMessage& message) { LOG(TRACE) << "IObservable::EmitMessage observer = " << std::hex << &observer << std::dec; - EmitMessageInternal(&observer, message); - } - - void IObservable::RegisterForwarder(IMessageForwarder* forwarder) - { - if (forwarder == NULL) + + boost::shared_ptr<IObserver> lock(observer.lock()); + if (lock) { - throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer); + EmitMessageInternal(lock.get(), message); } - - forwarders_.insert(forwarder); } }
--- a/Framework/Messages/IObservable.h Tue Nov 05 18:26:59 2019 +0100 +++ b/Framework/Messages/IObservable.h Tue Nov 05 18:51:04 2019 +0100 @@ -24,8 +24,6 @@ #include "../StoneEnumerations.h" #include "ICallable.h" #include "IObserver.h" -#include "MessageBroker.h" -#include "MessageForwarder.h" #include <set> #include <map> @@ -37,39 +35,20 @@ private: typedef std::map<MessageIdentifier, std::set<ICallable*> > Callables; - typedef std::set<IMessageForwarder*> Forwarders; - - MessageBroker& broker_; Callables callables_; - Forwarders forwarders_; void EmitMessageInternal(const IObserver* receiver, const IMessage& message); public: - IObservable(MessageBroker& broker) : - broker_(broker) - { - } - virtual ~IObservable(); - MessageBroker& GetBroker() const - { - return broker_; - } - - // Takes ownsership - void RegisterObserverCallback(ICallable* callable); - - void Unregister(IObserver* observer); + // Takes ownsership of the callable + void RegisterCallable(ICallable* callable); void BroadcastMessage(const IMessage& message); - void EmitMessage(const IObserver& observer, + void EmitMessage(boost::weak_ptr<IObserver> observer, const IMessage& message); - - // Takes ownsership - void RegisterForwarder(IMessageForwarder* forwarder); }; }
--- a/Framework/Messages/IObserver.cpp Tue Nov 05 18:26:59 2019 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,93 +0,0 @@ -/** - * Stone of Orthanc - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2019 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU Affero General Public License - * as published by the Free Software Foundation, either version 3 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - **/ - - -#include "IObserver.h" - -#include "IMessage.h" -#include "../StoneException.h" - -#include <Core/Logging.h> -#include <Core/Toolbox.h> - -namespace OrthancStone -{ - IObserver::IObserver(MessageBroker& broker) - : broker_(broker) - , fingerprint_() - { - // we store the fingerprint_ as a char array to avoid problems when - // reading it in a deceased object. - // remember this is panic-level code to track zombie object usage - std::string fingerprint = Orthanc::Toolbox::GenerateUuid(); - const char* fingerprintRaw = fingerprint.c_str(); - memcpy(fingerprint_, fingerprintRaw, 37); - broker_.Register(*this); - } - - - IObserver::~IObserver() - { - try - { - LOG(TRACE) << "IObserver(" << std::hex << this << std::dec << ")::~IObserver : fingerprint_ == " << fingerprint_; - const char* deadMarker = "deadbeef-dead-dead-0000-0000deadbeef"; - ORTHANC_ASSERT(strlen(deadMarker) == 36); - memcpy(fingerprint_, deadMarker, 37); - broker_.Unregister(*this); - } - catch (const Orthanc::OrthancException& e) - { - if (e.HasDetails()) - { - LOG(ERROR) << "OrthancException in ~IObserver: " << e.What() << " Details: " << e.GetDetails(); - } - else - { - LOG(ERROR) << "OrthancException in ~IObserver: " << e.What(); - } - } - catch (const std::exception& e) - { - LOG(ERROR) << "std::exception in ~IObserver: " << e.what(); - } - catch (...) - { - LOG(ERROR) << "Unknown exception in ~IObserver"; - } - } - - - bool IObserver::DoesFingerprintLookGood() const - { - for (size_t i = 0; i < 36; ++i) { - bool ok = false; - if (fingerprint_[i] >= 'a' && fingerprint_[i] <= 'f') - ok = true; - if (fingerprint_[i] >= '0' && fingerprint_[i] <= '9') - ok = true; - if (fingerprint_[i] == '-') - ok = true; - if (!ok) - return false; - } - return fingerprint_[36] == 0; - } -}
--- a/Framework/Messages/IObserver.h Tue Nov 05 18:26:59 2019 +0100 +++ b/Framework/Messages/IObserver.h Tue Nov 05 18:51:04 2019 +0100 @@ -21,33 +21,19 @@ #pragma once -#include "MessageBroker.h" +#include <boost/noncopyable.hpp> namespace OrthancStone { class IObserver : public boost::noncopyable { - private: - MessageBroker& broker_; - // the following is a UUID that is used to disambiguate different observers - // that may have the same address - char fingerprint_[37]; - public: - IObserver(MessageBroker& broker); - - virtual ~IObserver(); - - const char* GetFingerprint() const + IObserver() { - return fingerprint_; } - bool DoesFingerprintLookGood() const; - - MessageBroker& GetBroker() const + virtual ~IObserver() { - return broker_; } }; }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Framework/Messages/LockingEmitter.cpp Tue Nov 05 18:51:04 2019 +0100 @@ -0,0 +1,43 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2019 Osimis S.A., Belgium + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU Affero General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + **/ + +#include "LockingEmitter.h" + +#include <Core/OrthancException.h> + +namespace OrthancStone +{ + namespace Deprecated + { + void LockingEmitter::EmitMessage(boost::weak_ptr<IObserver> observer, + const IMessage& message) + { + try + { + boost::unique_lock<boost::shared_mutex> lock(mutex_); + oracleObservable_.EmitMessage(observer, message); + } + catch (Orthanc::OrthancException& e) + { + LOG(ERROR) << "Exception while emitting a message: " << e.What(); + } + } + } +}
--- a/Framework/Messages/LockingEmitter.h Tue Nov 05 18:26:59 2019 +0100 +++ b/Framework/Messages/LockingEmitter.h Tue Nov 05 18:51:04 2019 +0100 @@ -26,89 +26,67 @@ #include "IMessageEmitter.h" #include "IObservable.h" -#include <boost/thread.hpp> +#include <Core/Enumerations.h> // For ORTHANC_OVERRIDE + +#include <boost/thread/shared_mutex.hpp> namespace OrthancStone { - /** - * This class is used when using the ThreadedOracle : since messages - * can be sent from multiple Oracle threads, this IMessageEmitter - * implementation serializes the callbacks. - * - * The internal mutex used in Oracle messaging can also be used to - * protect the application data. Thus, this class can be used as a single - * application-wide mutex. - */ - class LockingEmitter : public IMessageEmitter + namespace Deprecated { - private: - boost::shared_mutex mutex_; - MessageBroker broker_; - IObservable oracleObservable_; - - public: - LockingEmitter() : - oracleObservable_(broker_) + /** + * This class is used when using the ThreadedOracle : since messages + * can be sent from multiple Oracle threads, this IMessageEmitter + * implementation serializes the callbacks. + * + * The internal mutex used in Oracle messaging can also be used to + * protect the application data. Thus, this class can be used as a single + * application-wide mutex. + */ + class LockingEmitter : public IMessageEmitter { - } - - MessageBroker& GetBroker() - { - return broker_; - } + private: + boost::shared_mutex mutex_; + IObservable oracleObservable_; - virtual void EmitMessage(const IObserver& observer, - const IMessage& message) ORTHANC_OVERRIDE - { - try - { - boost::unique_lock<boost::shared_mutex> lock(mutex_); - oracleObservable_.EmitMessage(observer, message); - } - catch (Orthanc::OrthancException& e) - { - LOG(ERROR) << "Exception while emitting a message: " << e.What(); - } - } + public: + virtual void EmitMessage(boost::weak_ptr<IObserver> observer, + const IMessage& message) ORTHANC_OVERRIDE; - class ReaderLock : public boost::noncopyable - { - private: - LockingEmitter& that_; - boost::shared_lock<boost::shared_mutex> lock_; + class ReaderLock : public boost::noncopyable + { + private: + LockingEmitter& that_; + boost::shared_lock<boost::shared_mutex> lock_; - public: - ReaderLock(LockingEmitter& that) : + public: + ReaderLock(LockingEmitter& that) : that_(that), lock_(that.mutex_) - { - } - }; + { + } + }; - class WriterLock : public boost::noncopyable - { - private: - LockingEmitter& that_; - boost::unique_lock<boost::shared_mutex> lock_; + class WriterLock : public boost::noncopyable + { + private: + LockingEmitter& that_; + boost::unique_lock<boost::shared_mutex> lock_; - public: - WriterLock(LockingEmitter& that) : + public: + WriterLock(LockingEmitter& that) : that_(that), lock_(that.mutex_) - { - } - - MessageBroker& GetBroker() - { - return that_.broker_; - } + { + } - IObservable& GetOracleObservable() - { - return that_.oracleObservable_; - } + IObservable& GetOracleObservable() + { + return that_.oracleObservable_; + } + }; }; - }; + } }
--- a/Framework/Messages/MessageBroker.h Tue Nov 05 18:26:59 2019 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,61 +0,0 @@ -/** - * Stone of Orthanc - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2019 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU Affero General Public License - * as published by the Free Software Foundation, either version 3 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - **/ - -#pragma once - -#include "boost/noncopyable.hpp" - -#include <set> - -namespace OrthancStone -{ - class IObserver; - - /* - * This is a central message broker. It keeps track of all observers and knows - * when an observer is deleted. - * This way, it can prevent an observable to send a message to a deleted observer. - */ - class MessageBroker : public boost::noncopyable - { - private: - std::set<const IObserver*> activeObservers_; // the list of observers that are currently alive (that have not been deleted) - - public: - MessageBroker() - { - } - - void Register(const IObserver& observer) - { - activeObservers_.insert(&observer); - } - - void Unregister(const IObserver& observer) - { - activeObservers_.erase(&observer); - } - - bool IsActive(const IObserver& observer) - { - return activeObservers_.find(&observer) != activeObservers_.end(); - } - }; -}
--- a/Framework/Messages/MessageForwarder.cpp Tue Nov 05 18:26:59 2019 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,38 +0,0 @@ -/** - * Stone of Orthanc - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2019 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU Affero General Public License - * as published by the Free Software Foundation, either version 3 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - **/ - - -#include "MessageForwarder.h" - -#include "IObservable.h" - -namespace OrthancStone -{ - - void IMessageForwarder::ForwardMessageInternal(const IMessage& message) - { - emitter_.BroadcastMessage(message); - } - - void IMessageForwarder::RegisterForwarderInEmitter() - { - emitter_.RegisterForwarder(this); - } -}
--- a/Framework/Messages/MessageForwarder.h Tue Nov 05 18:26:59 2019 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,87 +0,0 @@ -/** - * Stone of Orthanc - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2019 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU Affero General Public License - * as published by the Free Software Foundation, either version 3 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - **/ - - -#pragma once - -#include "ICallable.h" -#include "IObserver.h" - -#include <boost/noncopyable.hpp> - -namespace OrthancStone -{ - - class IObservable; - - class IMessageForwarder : public IObserver - { - IObservable& emitter_; - public: - IMessageForwarder(MessageBroker& broker, IObservable& emitter) - : IObserver(broker), - emitter_(emitter) - {} - virtual ~IMessageForwarder() {} - - protected: - void ForwardMessageInternal(const IMessage& message); - void RegisterForwarderInEmitter(); - - }; - - /* When an Observer (B) simply needs to re-emit a message it has received, instead of implementing - * a specific member function to forward the message, it can create a MessageForwarder. - * The MessageForwarder will re-emit the message "in the name of (B)" - * - * Consider the chain where - * A is an observable - * | - * B is an observer of A and observable - * | - * C is an observer of B and knows that B is re-emitting many messages from A - * - * instead of implementing a callback, B will create a MessageForwarder that will emit the messages in his name: - * A.RegisterObserverCallback(new MessageForwarder<A::MessageType>(broker, *this) // where "this" is B - * - * in C: - * B.RegisterObserverCallback(new Callable<C, A:MessageTyper>(*this, &B::MyCallback)) // where "this" is C - */ - template<typename TMessage> - class MessageForwarder : public IMessageForwarder, public Callable<MessageForwarder<TMessage>, TMessage> - { - public: - MessageForwarder(MessageBroker& broker, - IObservable& emitter // the object that will emit the messages to forward - ) - : IMessageForwarder(broker, emitter), - Callable<MessageForwarder<TMessage>, TMessage>(*this, &MessageForwarder::ForwardMessage) - { - RegisterForwarderInEmitter(); - } - -protected: - void ForwardMessage(const TMessage& message) - { - ForwardMessageInternal(message); - } - - }; -}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Framework/Messages/ObserverBase.h Tue Nov 05 18:51:04 2019 +0100 @@ -0,0 +1,68 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2019 Osimis S.A., Belgium + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU Affero General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + **/ + + +#pragma once + +#include "ICallable.h" +#include "IObserver.h" +#include "IObservable.h" + +#include <Core/OrthancException.h> + +#include <boost/enable_shared_from_this.hpp> + +namespace OrthancStone +{ + template <typename TObserver> + class ObserverBase : + public IObserver, + public boost::enable_shared_from_this<TObserver> + { + public: + boost::shared_ptr<TObserver> GetSharedObserver() + { + try + { + return this->shared_from_this(); + } + catch (boost::bad_weak_ptr&) + { + throw Orthanc::OrthancException( + Orthanc::ErrorCode_InternalError, + "Cannot get a shared pointer to an observer from its constructor, " + "or the observer is not created as a shared pointer"); + } + } + + template <typename TMessage> + ICallable* CreateCallable(void (TObserver::* MemberMethod) (const TMessage&)) + { + return new Callable<TObserver, TMessage>(GetSharedObserver(), MemberMethod); + } + + template <typename TMessage> + void Register(IObservable& observable, + void (TObserver::* MemberMethod) (const TMessage&)) + { + observable.RegisterCallable(CreateCallable(MemberMethod)); + } + }; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Framework/Oracle/CustomOracleCommand.h Tue Nov 05 18:51:04 2019 +0100 @@ -0,0 +1,38 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2019 Osimis S.A., Belgium + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU Affero General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + **/ + + +#pragma once + +#include "IOracleRunner.h" + +namespace OrthancStone +{ + class CustomOracleCommand : public IOracleCommand + { + public: + virtual Type GetType() const + { + return Type_Custom; + } + + virtual IMessage* Execute(IOracleRunner& runner) = 0; + }; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Framework/Oracle/GenericOracleRunner.cpp Tue Nov 05 18:51:04 2019 +0100 @@ -0,0 +1,381 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2019 Osimis S.A., Belgium + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU Affero General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + **/ + + +#include "GenericOracleRunner.h" + +#if !defined(ORTHANC_ENABLE_DCMTK) +# error The macro ORTHANC_ENABLE_DCMTK must be defined +#endif + +#include "CustomOracleCommand.h" +#include "GetOrthancImageCommand.h" +#include "GetOrthancWebViewerJpegCommand.h" +#include "HttpCommand.h" +#include "OracleCommandExceptionMessage.h" +#include "OrthancRestApiCommand.h" +#include "ReadFileCommand.h" + +#if ORTHANC_ENABLE_DCMTK == 1 +# include "ParseDicomFileCommand.h" +# include <dcmtk/dcmdata/dcdeftag.h> +#endif + +#include <Core/Compression/GzipCompressor.h> +#include <Core/HttpClient.h> +#include <Core/OrthancException.h> +#include <Core/Toolbox.h> +#include <Core/SystemToolbox.h> + +#include <boost/filesystem.hpp> + + +namespace OrthancStone +{ + static void CopyHttpHeaders(Orthanc::HttpClient& client, + const Orthanc::HttpClient::HttpHeaders& headers) + { + for (Orthanc::HttpClient::HttpHeaders::const_iterator + it = headers.begin(); it != headers.end(); it++ ) + { + client.AddHeader(it->first, it->second); + } + } + + + static void DecodeAnswer(std::string& answer, + const Orthanc::HttpClient::HttpHeaders& headers) + { + Orthanc::HttpCompression contentEncoding = Orthanc::HttpCompression_None; + + for (Orthanc::HttpClient::HttpHeaders::const_iterator it = headers.begin(); + it != headers.end(); ++it) + { + std::string s; + Orthanc::Toolbox::ToLowerCase(s, it->first); + + if (s == "content-encoding") + { + if (it->second == "gzip") + { + contentEncoding = Orthanc::HttpCompression_Gzip; + } + else + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_NetworkProtocol, + "Unsupported HTTP Content-Encoding: " + it->second); + } + + break; + } + } + + if (contentEncoding == Orthanc::HttpCompression_Gzip) + { + std::string compressed; + answer.swap(compressed); + + Orthanc::GzipCompressor compressor; + compressor.Uncompress(answer, compressed.c_str(), compressed.size()); + + LOG(INFO) << "Uncompressing gzip Encoding: from " << compressed.size() + << " to " << answer.size() << " bytes"; + } + } + + + static IMessage* Execute(const HttpCommand& command) + { + Orthanc::HttpClient client; + client.SetUrl(command.GetUrl()); + client.SetMethod(command.GetMethod()); + client.SetTimeout(command.GetTimeout()); + + CopyHttpHeaders(client, command.GetHttpHeaders()); + + if (command.HasCredentials()) + { + client.SetCredentials(command.GetUsername().c_str(), command.GetPassword().c_str()); + } + + if (command.GetMethod() == Orthanc::HttpMethod_Post || + command.GetMethod() == Orthanc::HttpMethod_Put) + { + client.SetBody(command.GetBody()); + } + + std::string answer; + Orthanc::HttpClient::HttpHeaders answerHeaders; + client.ApplyAndThrowException(answer, answerHeaders); + + DecodeAnswer(answer, answerHeaders); + + return new HttpCommand::SuccessMessage(command, answerHeaders, answer); + } + + + static IMessage* Execute(const Orthanc::WebServiceParameters& orthanc, + const OrthancRestApiCommand& command) + { + Orthanc::HttpClient client(orthanc, command.GetUri()); + client.SetMethod(command.GetMethod()); + client.SetTimeout(command.GetTimeout()); + + CopyHttpHeaders(client, command.GetHttpHeaders()); + + if (command.GetMethod() == Orthanc::HttpMethod_Post || + command.GetMethod() == Orthanc::HttpMethod_Put) + { + client.SetBody(command.GetBody()); + } + + std::string answer; + Orthanc::HttpClient::HttpHeaders answerHeaders; + client.ApplyAndThrowException(answer, answerHeaders); + + DecodeAnswer(answer, answerHeaders); + + return new OrthancRestApiCommand::SuccessMessage(command, answerHeaders, answer); + } + + + static IMessage* Execute(const Orthanc::WebServiceParameters& orthanc, + const GetOrthancImageCommand& command) + { + Orthanc::HttpClient client(orthanc, command.GetUri()); + client.SetTimeout(command.GetTimeout()); + + CopyHttpHeaders(client, command.GetHttpHeaders()); + + std::string answer; + Orthanc::HttpClient::HttpHeaders answerHeaders; + client.ApplyAndThrowException(answer, answerHeaders); + + DecodeAnswer(answer, answerHeaders); + + return command.ProcessHttpAnswer(answer, answerHeaders); + } + + + static IMessage* Execute(const Orthanc::WebServiceParameters& orthanc, + const GetOrthancWebViewerJpegCommand& command) + { + Orthanc::HttpClient client(orthanc, command.GetUri()); + client.SetTimeout(command.GetTimeout()); + + CopyHttpHeaders(client, command.GetHttpHeaders()); + + std::string answer; + Orthanc::HttpClient::HttpHeaders answerHeaders; + client.ApplyAndThrowException(answer, answerHeaders); + + DecodeAnswer(answer, answerHeaders); + + return command.ProcessHttpAnswer(answer); + } + + + static std::string GetPath(const std::string& root, + const std::string& file) + { + boost::filesystem::path a(root); + boost::filesystem::path b(file); + + boost::filesystem::path c; + if (b.is_absolute()) + { + c = b; + } + else + { + c = a / b; + } + + LOG(TRACE) << "Oracle reading file: " << c.string(); + return c.string(); + } + + + static IMessage* Execute(const std::string& root, + const ReadFileCommand& command) + { + std::string path = GetPath(root, command.GetPath()); + + std::string content; + Orthanc::SystemToolbox::ReadFile(content, path, true /* log */); + + return new ReadFileCommand::SuccessMessage(command, content); + } + + +#if ORTHANC_ENABLE_DCMTK == 1 + static ParseDicomFileCommand::SuccessMessage* Execute(const std::string& root, + const ParseDicomFileCommand& command) + { + std::string path = GetPath(root, command.GetPath()); + + if (!Orthanc::SystemToolbox::IsRegularFile(path)) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_InexistentFile); + } + + uint64_t fileSize = Orthanc::SystemToolbox::GetFileSize(path); + + // Check for 32bit systems + if (fileSize != static_cast<uint64_t>(static_cast<size_t>(fileSize))) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_NotEnoughMemory); + } + + DcmFileFormat dicom; + bool ok; + + if (command.IsPixelDataIncluded()) + { + ok = dicom.loadFile(path.c_str()).good(); + } + else + { +#if DCMTK_VERSION_NUMBER >= 362 + // NB : We could stop at (0x3007, 0x0000) instead of + // DCM_PixelData, cf. the Orthanc::DICOM_TAG_* constants + + static const DcmTagKey STOP = DCM_PixelData; + //static const DcmTagKey STOP(0x3007, 0x0000); + + ok = dicom.loadFileUntilTag(path.c_str(), EXS_Unknown, EGL_noChange, + DCM_MaxReadLength, ERM_autoDetect, STOP).good(); +#else + // The primitive "loadFileUntilTag" was introduced in DCMTK 3.6.2 + ok = dicom.loadFile(path.c_str()).good(); +#endif + } + + printf("Reading %s\n", path.c_str()); + + if (ok) + { + return new ParseDicomFileCommand::SuccessMessage + (command, dicom, static_cast<size_t>(fileSize), command.IsPixelDataIncluded()); + } + else + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat, + "Cannot parse file: " + path); + } + } + + + static ParseDicomFileCommand::SuccessMessage* Execute(boost::shared_ptr<ParsedDicomFileCache> cache, + const std::string& root, + const ParseDicomFileCommand& command) + { +#if 0 + // The code to use the cache is buggy in multithreaded environments => TODO FIX + if (cache.get()) + { + { + ParsedDicomFileCache::Reader reader(*cache, command.GetPath()); + if (reader.IsValid() && + (!command.IsPixelDataIncluded() || + reader.HasPixelData())) + { + // Reuse the DICOM file from the cache + return new ParseDicomFileCommand::SuccessMessage( + command, reader.GetDicom(), reader.GetFileSize(), reader.HasPixelData()); + } + } + + // Not in the cache, first read and parse the DICOM file + std::auto_ptr<ParseDicomFileCommand::SuccessMessage> message(Execute(root, command)); + + // Secondly, store it into the cache for future use + assert(&message->GetOrigin() == &command); + cache->Acquire(message->GetOrigin().GetPath(), message->GetDicom(), + message->GetFileSize(), message->HasPixelData()); + + return message.release(); + } + else + { + // No cache available + return Execute(root, command); + } +#else + return Execute(root, command); +#endif + } + +#endif + + + IMessage* GenericOracleRunner::Run(IOracleCommand& command) + { + try + { + switch (command.GetType()) + { + case IOracleCommand::Type_Sleep: + throw Orthanc::OrthancException(Orthanc::ErrorCode_BadParameterType, + "Sleep command cannot be executed by the runner"); + + case IOracleCommand::Type_Http: + return Execute(dynamic_cast<const HttpCommand&>(command)); + + case IOracleCommand::Type_OrthancRestApi: + return Execute(orthanc_, dynamic_cast<const OrthancRestApiCommand&>(command)); + + case IOracleCommand::Type_GetOrthancImage: + return Execute(orthanc_, dynamic_cast<const GetOrthancImageCommand&>(command)); + + case IOracleCommand::Type_GetOrthancWebViewerJpeg: + return Execute(orthanc_, dynamic_cast<const GetOrthancWebViewerJpegCommand&>(command)); + + case IOracleCommand::Type_Custom: + return dynamic_cast<CustomOracleCommand&>(command).Execute(*this); + + case IOracleCommand::Type_ReadFile: + return Execute(rootDirectory_, dynamic_cast<const ReadFileCommand&>(command)); + + case IOracleCommand::Type_ParseDicomFile: +#if ORTHANC_ENABLE_DCMTK == 1 + return Execute(dicomCache_, rootDirectory_, + dynamic_cast<const ParseDicomFileCommand&>(command)); +#else + throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented, + "DCMTK must be enabled to parse DICOM files"); +#endif + + default: + throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented); + } + } + catch (Orthanc::OrthancException& e) + { + LOG(ERROR) << "Exception within the oracle: " << e.What(); + return new OracleCommandExceptionMessage(command, e); + } + catch (...) + { + LOG(ERROR) << "Threaded exception within the oracle"; + return new OracleCommandExceptionMessage(command, Orthanc::ErrorCode_InternalError); + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Framework/Oracle/GenericOracleRunner.h Tue Nov 05 18:51:04 2019 +0100 @@ -0,0 +1,88 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2019 Osimis S.A., Belgium + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU Affero General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + **/ + + +#pragma once + +#include "IOracleRunner.h" + +#if !defined(ORTHANC_ENABLE_DCMTK) +# error The macro ORTHANC_ENABLE_DCMTK must be defined +#endif + +#if ORTHANC_ENABLE_DCMTK == 1 +# include "../Toolbox/ParsedDicomFileCache.h" +#endif + + +#include <Core/Enumerations.h> // For ORTHANC_OVERRIDE +#include <Core/WebServiceParameters.h> + +namespace OrthancStone +{ + class GenericOracleRunner : public IOracleRunner + { + private: + Orthanc::WebServiceParameters orthanc_; + std::string rootDirectory_; + +#if ORTHANC_ENABLE_DCMTK == 1 + boost::shared_ptr<ParsedDicomFileCache> dicomCache_; +#endif + + public: + GenericOracleRunner() + : rootDirectory_(".") +#if ORTHANC_ENABLE_DCMTK == 1 + , dicomCache_(NULL) +#endif + { + } + + void SetOrthanc(const Orthanc::WebServiceParameters& orthanc) + { + orthanc_ = orthanc; + } + + const Orthanc::WebServiceParameters& GetOrthanc() const + { + return orthanc_; + } + + void SetRootDirectory(const std::string& rootDirectory) + { + rootDirectory_ = rootDirectory; + } + + const std::string GetRootDirectory() const + { + return rootDirectory_; + } + +#if ORTHANC_ENABLE_DCMTK == 1 + void SetDicomCache(boost::shared_ptr<ParsedDicomFileCache> cache) + { + dicomCache_ = cache; + } +#endif + + virtual IMessage* Run(IOracleCommand& command) ORTHANC_OVERRIDE; + }; +}
--- a/Framework/Oracle/GetOrthancImageCommand.cpp Tue Nov 05 18:26:59 2019 +0100 +++ b/Framework/Oracle/GetOrthancImageCommand.cpp Tue Nov 05 18:51:04 2019 +0100 @@ -82,10 +82,8 @@ } } - void GetOrthancImageCommand::ProcessHttpAnswer(IMessageEmitter& emitter, - const IObserver& receiver, - const std::string& answer, - const HttpHeaders& answerHeaders) const + IMessage* GetOrthancImageCommand::ProcessHttpAnswer(const std::string& answer, + const HttpHeaders& answerHeaders) const { Orthanc::MimeType contentType = Orthanc::MimeType_Binary; @@ -147,7 +145,6 @@ } } - SuccessMessage message(*this, image.release(), contentType); - emitter.EmitMessage(receiver, message); + return new SuccessMessage(*this, image.release(), contentType); } }
--- a/Framework/Oracle/GetOrthancImageCommand.h Tue Nov 05 18:26:59 2019 +0100 +++ b/Framework/Oracle/GetOrthancImageCommand.h Tue Nov 05 18:51:04 2019 +0100 @@ -21,7 +21,7 @@ #pragma once -#include "../Messages/IMessageEmitter.h" +#include "../Messages/IMessage.h" #include "OracleCommandWithPayload.h" #include <Core/Images/ImageAccessor.h> @@ -111,9 +111,7 @@ return timeout_; } - void ProcessHttpAnswer(IMessageEmitter& emitter, - const IObserver& receiver, - const std::string& answer, - const HttpHeaders& answerHeaders) const; + IMessage* ProcessHttpAnswer(const std::string& answer, + const HttpHeaders& answerHeaders) const; }; }
--- a/Framework/Oracle/GetOrthancWebViewerJpegCommand.cpp Tue Nov 05 18:26:59 2019 +0100 +++ b/Framework/Oracle/GetOrthancWebViewerJpegCommand.cpp Tue Nov 05 18:51:04 2019 +0100 @@ -76,9 +76,7 @@ } - void GetOrthancWebViewerJpegCommand::ProcessHttpAnswer(IMessageEmitter& emitter, - const IObserver& receiver, - const std::string& answer) const + IMessage* GetOrthancWebViewerJpegCommand::ProcessHttpAnswer(const std::string& answer) const { // This code comes from older "OrthancSlicesLoader::ParseSliceImageJpeg()" @@ -149,9 +147,7 @@ } else { - SuccessMessage message(*this, reader.release()); - emitter.EmitMessage(receiver, message); - return; + return new SuccessMessage(*this, reader.release()); } } @@ -168,9 +164,7 @@ } else { - SuccessMessage message(*this, reader.release()); - emitter.EmitMessage(receiver, message); - return; + return new SuccessMessage(*this, reader.release()); } } @@ -210,8 +204,7 @@ float offset = static_cast<float>(stretchLow) / scaling; Orthanc::ImageProcessing::ShiftScale(*image, offset, scaling, true); } - - SuccessMessage message(*this, image.release()); - emitter.EmitMessage(receiver, message); + + return new SuccessMessage(*this, image.release()); } }
--- a/Framework/Oracle/GetOrthancWebViewerJpegCommand.h Tue Nov 05 18:26:59 2019 +0100 +++ b/Framework/Oracle/GetOrthancWebViewerJpegCommand.h Tue Nov 05 18:51:04 2019 +0100 @@ -21,7 +21,7 @@ #pragma once -#include "../Messages/IMessageEmitter.h" +#include "../Messages/IMessage.h" #include "OracleCommandWithPayload.h" #include <Core/Images/ImageAccessor.h> @@ -128,8 +128,6 @@ std::string GetUri() const; - void ProcessHttpAnswer(IMessageEmitter& emitter, - const IObserver& receiver, - const std::string& answer) const; + IMessage* ProcessHttpAnswer(const std::string& answer) const; }; }
--- a/Framework/Oracle/HttpCommand.cpp Tue Nov 05 18:26:59 2019 +0100 +++ b/Framework/Oracle/HttpCommand.cpp Tue Nov 05 18:51:04 2019 +0100 @@ -76,4 +76,30 @@ throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); } } + + + const std::string& HttpCommand::GetUsername() const + { + if (HasCredentials()) + { + return username_; + } + else + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); + } + } + + + const std::string& HttpCommand::GetPassword() const + { + if (HasCredentials()) + { + return password_; + } + else + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); + } + } }
--- a/Framework/Oracle/HttpCommand.h Tue Nov 05 18:26:59 2019 +0100 +++ b/Framework/Oracle/HttpCommand.h Tue Nov 05 18:51:04 2019 +0100 @@ -69,6 +69,8 @@ std::string body_; HttpHeaders headers_; unsigned int timeout_; + std::string username_; + std::string password_; public: HttpCommand(); @@ -137,5 +139,27 @@ { return timeout_; } + + void SetCredentials(const std::string& username, + const std::string& password) + { + username_ = username; + password_ = password; + } + + void ClearCredentials() + { + username_.clear(); + password_.clear(); + } + + bool HasCredentials() const + { + return !username_.empty(); + } + + const std::string& GetUsername() const; + + const std::string& GetPassword() const; }; }
--- a/Framework/Oracle/IOracle.h Tue Nov 05 18:26:59 2019 +0100 +++ b/Framework/Oracle/IOracle.h Tue Nov 05 18:51:04 2019 +0100 @@ -22,7 +22,9 @@ #pragma once #include "../Messages/IObserver.h" -#include "IOracleCommand.h" +#include "IOracleRunner.h" + +#include <boost/shared_ptr.hpp> namespace OrthancStone { @@ -33,7 +35,12 @@ { } - virtual void Schedule(const IObserver& receiver, + /** + * Returns "true" iff the command has actually been queued. If + * "false" is returned, the command has been freed, and it won't + * be processed (this is the case if the oracle is stopped). + **/ + virtual bool Schedule(boost::shared_ptr<IObserver> receiver, IOracleCommand* command) = 0; // Takes ownership }; }
--- a/Framework/Oracle/IOracleCommand.h Tue Nov 05 18:26:59 2019 +0100 +++ b/Framework/Oracle/IOracleCommand.h Tue Nov 05 18:51:04 2019 +0100 @@ -30,11 +30,14 @@ public: enum Type { + Type_Custom, + Type_GetOrthancImage, + Type_GetOrthancWebViewerJpeg, Type_Http, - Type_Sleep, Type_OrthancRestApi, - Type_GetOrthancImage, - Type_GetOrthancWebViewerJpeg + Type_ParseDicomFile, + Type_ReadFile, + Type_Sleep }; virtual ~IOracleCommand()
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Framework/Oracle/IOracleRunner.h Tue Nov 05 18:51:04 2019 +0100 @@ -0,0 +1,38 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2019 Osimis S.A., Belgium + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU Affero General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + **/ + + +#pragma once + +#include "IOracleCommand.h" +#include "../Messages/IMessage.h" + +namespace OrthancStone +{ + class IOracleRunner : public boost::noncopyable + { + public: + virtual ~IOracleRunner() + { + } + + virtual IMessage* Run(IOracleCommand& command) = 0; + }; +}
--- a/Framework/Oracle/OrthancRestApiCommand.cpp Tue Nov 05 18:26:59 2019 +0100 +++ b/Framework/Oracle/OrthancRestApiCommand.cpp Tue Nov 05 18:51:04 2019 +0100 @@ -51,7 +51,8 @@ OrthancRestApiCommand::OrthancRestApiCommand() : method_(Orthanc::HttpMethod_Get), uri_("/"), - timeout_(600) + timeout_(600), + applyPlugins_(false) { }
--- a/Framework/Oracle/OrthancRestApiCommand.h Tue Nov 05 18:26:59 2019 +0100 +++ b/Framework/Oracle/OrthancRestApiCommand.h Tue Nov 05 18:51:04 2019 +0100 @@ -69,6 +69,7 @@ std::string body_; HttpHeaders headers_; unsigned int timeout_; + bool applyPlugins_; // Only makes sense for Stone as an Orthanc plugin public: OrthancRestApiCommand(); @@ -137,5 +138,15 @@ { return timeout_; } + + void SetApplyPlugins(bool applyPlugins) + { + applyPlugins_ = applyPlugins; + } + + bool IsApplyPlugins() const + { + return applyPlugins_; + } }; }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Framework/Oracle/ParseDicomFileCommand.cpp Tue Nov 05 18:51:04 2019 +0100 @@ -0,0 +1,79 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2019 Osimis S.A., Belgium + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU Affero General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + **/ + + +#include "ParseDicomFileCommand.h" + +#include <Core/OrthancException.h> + +#include <boost/filesystem/path.hpp> + +namespace OrthancStone +{ + void ParseDicomFileCommand::SuccessMessage::Setup() + { + if (!dicom_->GetTagValue(sopInstanceUid_, Orthanc::DICOM_TAG_SOP_INSTANCE_UID)) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat, + "DICOM instance missing tag SOPInstanceUID"); + } + } + + + ParseDicomFileCommand::SuccessMessage::SuccessMessage(const ParseDicomFileCommand& command, + DcmFileFormat& dicom, + size_t fileSize, + bool hasPixelData) : + OriginMessage(command), + fileSize_(fileSize), + hasPixelData_(hasPixelData) + { + dicom_.reset(new Orthanc::ParsedDicomFile(dicom)); + Setup(); + } + + + ParseDicomFileCommand::SuccessMessage::SuccessMessage(const ParseDicomFileCommand& command, + boost::shared_ptr<Orthanc::ParsedDicomFile> dicom, + size_t fileSize, + bool hasPixelData) : + OriginMessage(command), + dicom_(dicom), + fileSize_(fileSize), + hasPixelData_(hasPixelData) + { + Setup(); + } + + + std::string ParseDicomFileCommand::GetDicomDirPath(const std::string& dicomDirPath, + const std::string& file) + { + std::string tmp = file; + +#if !defined(_WIN32) + std::replace(tmp.begin(), tmp.end(), '\\', '/'); +#endif + + boost::filesystem::path base = boost::filesystem::path(dicomDirPath).parent_path(); + + return (base / tmp).string(); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Framework/Oracle/ParseDicomFileCommand.h Tue Nov 05 18:51:04 2019 +0100 @@ -0,0 +1,129 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2019 Osimis S.A., Belgium + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU Affero General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + **/ + + +#pragma once + +#if !defined(ORTHANC_ENABLE_DCMTK) +# error The macro ORTHANC_ENABLE_DCMTK must be defined +#endif + +#if ORTHANC_ENABLE_DCMTK != 1 +# error Support for DCMTK must be enabled to use ParseDicomFileCommand +#endif + +#include "../Messages/IMessage.h" +#include "OracleCommandWithPayload.h" + +#include <Core/DicomParsing/ParsedDicomFile.h> + +#include <dcmtk/dcmdata/dcfilefo.h> + +namespace OrthancStone +{ + class ParseDicomFileCommand : public OracleCommandWithPayload + { + public: + class SuccessMessage : public OriginMessage<ParseDicomFileCommand> + { + ORTHANC_STONE_MESSAGE(__FILE__, __LINE__); + + private: + boost::shared_ptr<Orthanc::ParsedDicomFile> dicom_; + size_t fileSize_; + bool hasPixelData_; + std::string sopInstanceUid_; + + void Setup(); + + public: + SuccessMessage(const ParseDicomFileCommand& command, + DcmFileFormat& dicom, + size_t fileSize, + bool hasPixelData); + + SuccessMessage(const ParseDicomFileCommand& command, + boost::shared_ptr<Orthanc::ParsedDicomFile> dicom, + size_t fileSize, + bool hasPixelData); + + boost::shared_ptr<Orthanc::ParsedDicomFile> GetDicom() const + { + return dicom_; + } + + size_t GetFileSize() const + { + return fileSize_; + } + + bool HasPixelData() const + { + return hasPixelData_; + } + + const std::string& GetSopInstanceUid() const + { + return sopInstanceUid_; + } + }; + + private: + std::string path_; + bool pixelDataIncluded_; + + public: + ParseDicomFileCommand(const std::string& path) : + path_(path), + pixelDataIncluded_(true) + { + } + + ParseDicomFileCommand(const std::string& dicomDirPath, + const std::string& file) : + path_(GetDicomDirPath(dicomDirPath, file)), + pixelDataIncluded_(true) + { + } + + static std::string GetDicomDirPath(const std::string& dicomDirPath, + const std::string& file); + + virtual Type GetType() const + { + return Type_ParseDicomFile; + } + + const std::string& GetPath() const + { + return path_; + } + + bool IsPixelDataIncluded() const + { + return pixelDataIncluded_; + } + + void SetPixelDataIncluded(bool included) + { + pixelDataIncluded_ = included; + } + }; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Framework/Oracle/ReadFileCommand.h Tue Nov 05 18:51:04 2019 +0100 @@ -0,0 +1,73 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2019 Osimis S.A., Belgium + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU Affero General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + **/ + + +#pragma once + +#include "../Messages/IMessage.h" +#include "OracleCommandWithPayload.h" + +namespace OrthancStone +{ + class ReadFileCommand : public OracleCommandWithPayload + { + public: + class SuccessMessage : public OriginMessage<ReadFileCommand> + { + ORTHANC_STONE_MESSAGE(__FILE__, __LINE__); + + private: + std::string content_; + + public: + SuccessMessage(const ReadFileCommand& command, + std::string& content /* will be swapped to avoid a memcpy() */) : + OriginMessage(command) + { + content_.swap(content); + } + + const std::string& GetContent() const + { + return content_; + } + }; + + + private: + std::string path_; + + public: + ReadFileCommand(const std::string& path) : + path_(path) + { + } + + virtual Type GetType() const + { + return Type_ReadFile; + } + + const std::string& GetPath() const + { + return path_; + } + }; +}
--- a/Framework/Oracle/ThreadedOracle.cpp Tue Nov 05 18:26:59 2019 +0100 +++ b/Framework/Oracle/ThreadedOracle.cpp Tue Nov 05 18:51:04 2019 +0100 @@ -21,29 +21,21 @@ #include "ThreadedOracle.h" -#include "GetOrthancImageCommand.h" -#include "GetOrthancWebViewerJpegCommand.h" -#include "HttpCommand.h" -#include "OrthancRestApiCommand.h" #include "SleepOracleCommand.h" -#include "OracleCommandExceptionMessage.h" -#include <Core/Compression/GzipCompressor.h> -#include <Core/HttpClient.h> +#include <Core/Logging.h> #include <Core/OrthancException.h> -#include <Core/Toolbox.h> - namespace OrthancStone { class ThreadedOracle::Item : public Orthanc::IDynamicObject { private: - const IObserver& receiver_; + boost::weak_ptr<IObserver> receiver_; std::auto_ptr<IOracleCommand> command_; public: - Item(const IObserver& receiver, + Item(boost::weak_ptr<IObserver> receiver, IOracleCommand* command) : receiver_(receiver), command_(command) @@ -54,7 +46,7 @@ } } - const IObserver& GetReceiver() const + boost::weak_ptr<IObserver> GetReceiver() { return receiver_; } @@ -73,12 +65,12 @@ class Item { private: - const IObserver& receiver_; + boost::weak_ptr<IObserver> receiver_; std::auto_ptr<SleepOracleCommand> command_; boost::posix_time::ptime expiration_; public: - Item(const IObserver& receiver, + Item(boost::weak_ptr<IObserver> receiver, SleepOracleCommand* command) : receiver_(receiver), command_(command) @@ -123,7 +115,7 @@ } } - void Add(const IObserver& receiver, + void Add(boost::weak_ptr<IObserver> receiver, SleepOracleCommand* command) // Takes ownership { boost::mutex::scoped_lock lock(mutex_); @@ -160,154 +152,6 @@ }; - static void CopyHttpHeaders(Orthanc::HttpClient& client, - const Orthanc::HttpClient::HttpHeaders& headers) - { - for (Orthanc::HttpClient::HttpHeaders::const_iterator - it = headers.begin(); it != headers.end(); it++ ) - { - client.AddHeader(it->first, it->second); - } - } - - - static void DecodeAnswer(std::string& answer, - const Orthanc::HttpClient::HttpHeaders& headers) - { - Orthanc::HttpCompression contentEncoding = Orthanc::HttpCompression_None; - - for (Orthanc::HttpClient::HttpHeaders::const_iterator it = headers.begin(); - it != headers.end(); ++it) - { - std::string s; - Orthanc::Toolbox::ToLowerCase(s, it->first); - - if (s == "content-encoding") - { - if (it->second == "gzip") - { - contentEncoding = Orthanc::HttpCompression_Gzip; - } - else - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_NetworkProtocol, - "Unsupported HTTP Content-Encoding: " + it->second); - } - - break; - } - } - - if (contentEncoding == Orthanc::HttpCompression_Gzip) - { - std::string compressed; - answer.swap(compressed); - - Orthanc::GzipCompressor compressor; - compressor.Uncompress(answer, compressed.c_str(), compressed.size()); - - LOG(INFO) << "Uncompressing gzip Encoding: from " << compressed.size() - << " to " << answer.size() << " bytes"; - } - } - - - static void Execute(IMessageEmitter& emitter, - const IObserver& receiver, - const HttpCommand& command) - { - Orthanc::HttpClient client; - client.SetUrl(command.GetUrl()); - client.SetMethod(command.GetMethod()); - client.SetTimeout(command.GetTimeout()); - - CopyHttpHeaders(client, command.GetHttpHeaders()); - - if (command.GetMethod() == Orthanc::HttpMethod_Post || - command.GetMethod() == Orthanc::HttpMethod_Put) - { - client.SetBody(command.GetBody()); - } - - std::string answer; - Orthanc::HttpClient::HttpHeaders answerHeaders; - client.ApplyAndThrowException(answer, answerHeaders); - - DecodeAnswer(answer, answerHeaders); - - HttpCommand::SuccessMessage message(command, answerHeaders, answer); - emitter.EmitMessage(receiver, message); - } - - - static void Execute(IMessageEmitter& emitter, - const Orthanc::WebServiceParameters& orthanc, - const IObserver& receiver, - const OrthancRestApiCommand& command) - { - Orthanc::HttpClient client(orthanc, command.GetUri()); - client.SetMethod(command.GetMethod()); - client.SetTimeout(command.GetTimeout()); - - CopyHttpHeaders(client, command.GetHttpHeaders()); - - if (command.GetMethod() == Orthanc::HttpMethod_Post || - command.GetMethod() == Orthanc::HttpMethod_Put) - { - client.SetBody(command.GetBody()); - } - - std::string answer; - Orthanc::HttpClient::HttpHeaders answerHeaders; - client.ApplyAndThrowException(answer, answerHeaders); - - DecodeAnswer(answer, answerHeaders); - - OrthancRestApiCommand::SuccessMessage message(command, answerHeaders, answer); - emitter.EmitMessage(receiver, message); - } - - - static void Execute(IMessageEmitter& emitter, - const Orthanc::WebServiceParameters& orthanc, - const IObserver& receiver, - const GetOrthancImageCommand& command) - { - Orthanc::HttpClient client(orthanc, command.GetUri()); - client.SetTimeout(command.GetTimeout()); - - CopyHttpHeaders(client, command.GetHttpHeaders()); - - std::string answer; - Orthanc::HttpClient::HttpHeaders answerHeaders; - client.ApplyAndThrowException(answer, answerHeaders); - - DecodeAnswer(answer, answerHeaders); - - command.ProcessHttpAnswer(emitter, receiver, answer, answerHeaders); - } - - - static void Execute(IMessageEmitter& emitter, - const Orthanc::WebServiceParameters& orthanc, - const IObserver& receiver, - const GetOrthancWebViewerJpegCommand& command) - { - Orthanc::HttpClient client(orthanc, command.GetUri()); - client.SetTimeout(command.GetTimeout()); - - CopyHttpHeaders(client, command.GetHttpHeaders()); - - std::string answer; - Orthanc::HttpClient::HttpHeaders answerHeaders; - client.ApplyAndThrowException(answer, answerHeaders); - - DecodeAnswer(answer, answerHeaders); - - command.ProcessHttpAnswer(emitter, receiver, answer); - } - - void ThreadedOracle::Step() { std::auto_ptr<Orthanc::IDynamicObject> object(queue_.Dequeue(100)); @@ -316,60 +160,37 @@ { Item& item = dynamic_cast<Item&>(*object); - try + if (item.GetCommand().GetType() == IOracleCommand::Type_Sleep) { - switch (item.GetCommand().GetType()) + SleepOracleCommand& command = dynamic_cast<SleepOracleCommand&>(item.GetCommand()); + + std::auto_ptr<SleepOracleCommand> copy(new SleepOracleCommand(command.GetDelay())); + + if (command.HasPayload()) { - case IOracleCommand::Type_Sleep: - { - SleepOracleCommand& command = dynamic_cast<SleepOracleCommand&>(item.GetCommand()); - - std::auto_ptr<SleepOracleCommand> copy(new SleepOracleCommand(command.GetDelay())); - - if (command.HasPayload()) - { - copy->SetPayload(command.ReleasePayload()); - } - - sleepingCommands_->Add(item.GetReceiver(), copy.release()); - - break; - } - - case IOracleCommand::Type_Http: - Execute(emitter_, item.GetReceiver(), - dynamic_cast<const HttpCommand&>(item.GetCommand())); - break; + copy->SetPayload(command.ReleasePayload()); + } + + sleepingCommands_->Add(item.GetReceiver(), copy.release()); + } + else + { + GenericOracleRunner runner; - case IOracleCommand::Type_OrthancRestApi: - Execute(emitter_, orthanc_, item.GetReceiver(), - dynamic_cast<const OrthancRestApiCommand&>(item.GetCommand())); - break; - - case IOracleCommand::Type_GetOrthancImage: - Execute(emitter_, orthanc_, item.GetReceiver(), - dynamic_cast<const GetOrthancImageCommand&>(item.GetCommand())); - break; - - case IOracleCommand::Type_GetOrthancWebViewerJpeg: - Execute(emitter_, orthanc_, item.GetReceiver(), - dynamic_cast<const GetOrthancWebViewerJpegCommand&>(item.GetCommand())); - break; + { + boost::mutex::scoped_lock lock(mutex_); + runner.SetOrthanc(orthanc_); + runner.SetRootDirectory(rootDirectory_); - default: - throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented); + if (dicomCache_) + { + runner.SetDicomCache(dicomCache_); + } } - } - catch (Orthanc::OrthancException& e) - { - LOG(ERROR) << "Exception within the oracle: " << e.What(); - emitter_.EmitMessage(item.GetReceiver(), OracleCommandExceptionMessage(item.GetCommand(), e)); - } - catch (...) - { - LOG(ERROR) << "Threaded exception within the oracle"; - emitter_.EmitMessage(item.GetReceiver(), OracleCommandExceptionMessage - (item.GetCommand(), Orthanc::ErrorCode_InternalError)); + + std::auto_ptr<IMessage> message(runner.Run(item.GetCommand())); + + emitter_.EmitMessage(item.GetReceiver(), *message); } } } @@ -453,6 +274,7 @@ ThreadedOracle::ThreadedOracle(IMessageEmitter& emitter) : emitter_(emitter), + rootDirectory_("."), state_(State_Setup), workers_(4), sleepingCommands_(new SleepingCommands), @@ -480,23 +302,21 @@ catch (...) { LOG(ERROR) << "Native exception while stopping the threaded oracle"; - } + } } void ThreadedOracle::SetOrthancParameters(const Orthanc::WebServiceParameters& orthanc) { boost::mutex::scoped_lock lock(mutex_); + orthanc_ = orthanc; + } - if (state_ != State_Setup) - { - LOG(ERROR) << "ThreadedOracle::SetOrthancParameters(): (state_ != State_Setup)"; - throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); - } - else - { - orthanc_ = orthanc; - } + + void ThreadedOracle::SetRootDirectory(const std::string& rootDirectory) + { + boost::mutex::scoped_lock lock(mutex_); + rootDirectory_ = rootDirectory; } @@ -540,6 +360,31 @@ } + void ThreadedOracle::SetDicomCacheSize(size_t size) + { +#if ORTHANC_ENABLE_DCMTK == 1 + boost::mutex::scoped_lock lock(mutex_); + + if (state_ != State_Setup) + { + LOG(ERROR) << "ThreadedOracle::SetDicomCacheSize(): (state_ != State_Setup)"; + throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); + } + else + { + if (size == 0) + { + dicomCache_.reset(); + } + else + { + dicomCache_.reset(new ParsedDicomFileCache(size)); + } + } +#endif + } + + void ThreadedOracle::Start() { boost::mutex::scoped_lock lock(mutex_); @@ -563,9 +408,25 @@ } - void ThreadedOracle::Schedule(const IObserver& receiver, + bool ThreadedOracle::Schedule(boost::shared_ptr<IObserver> receiver, IOracleCommand* command) { - queue_.Enqueue(new Item(receiver, command)); + std::auto_ptr<Item> item(new Item(receiver, command)); + + { + boost::mutex::scoped_lock lock(mutex_); + + if (state_ == State_Running) + { + //LOG(INFO) << "New oracle command queued"; + queue_.Enqueue(item.release()); + return true; + } + else + { + LOG(INFO) << "Command not enqueued, as the oracle is stopped"; + return false; + } + } } }
--- a/Framework/Oracle/ThreadedOracle.h Tue Nov 05 18:26:59 2019 +0100 +++ b/Framework/Oracle/ThreadedOracle.h Tue Nov 05 18:51:04 2019 +0100 @@ -25,14 +25,22 @@ # error The macro ORTHANC_ENABLE_THREADS must be defined #endif +#if !defined(ORTHANC_ENABLE_DCMTK) +# error The macro ORTHANC_ENABLE_DCMTK must be defined +#endif + #if ORTHANC_ENABLE_THREADS != 1 # error This file can only compiled for native targets #endif -#include "../Messages/IMessageEmitter.h" +#if ORTHANC_ENABLE_DCMTK == 1 +# include "../Toolbox/ParsedDicomFileCache.h" +#endif + #include "IOracle.h" +#include "GenericOracleRunner.h" +#include "../Messages/IMessageEmitter.h" -#include <Core/WebServiceParameters.h> #include <Core/MultiThreading/SharedMessageQueue.h> @@ -53,6 +61,7 @@ IMessageEmitter& emitter_; Orthanc::WebServiceParameters orthanc_; + std::string rootDirectory_; Orthanc::SharedMessageQueue queue_; State state_; boost::mutex mutex_; @@ -61,6 +70,10 @@ boost::thread sleepingWorker_; unsigned int sleepingTimeResolution_; +#if ORTHANC_ENABLE_DCMTK == 1 + boost::shared_ptr<ParsedDicomFileCache> dicomCache_; +#endif + void Step(); static void Worker(ThreadedOracle* that); @@ -74,13 +87,16 @@ virtual ~ThreadedOracle(); - // The reference is not stored. void SetOrthancParameters(const Orthanc::WebServiceParameters& orthanc); + void SetRootDirectory(const std::string& rootDirectory); + void SetThreadsCount(unsigned int count); void SetSleepingTimeResolution(unsigned int milliseconds); + void SetDicomCacheSize(size_t size); + void Start(); void Stop() @@ -88,7 +104,7 @@ StopInternal(); } - virtual void Schedule(const IObserver& receiver, - IOracleCommand* command); + virtual bool Schedule(boost::shared_ptr<IObserver> receiver, + IOracleCommand* command) ORTHANC_OVERRIDE; }; }
--- a/Framework/Oracle/WebAssemblyOracle.cpp Tue Nov 05 18:26:59 2019 +0100 +++ b/Framework/Oracle/WebAssemblyOracle.cpp Tue Nov 05 18:51:04 2019 +0100 @@ -695,7 +695,7 @@ - void WebAssemblyOracle::Schedule(const IObserver& receiver, + void WebAssemblyOracle::Schedule(boost::shared_ptr<IObserver>& receiver, IOracleCommand* command) { LOG(TRACE) << "WebAssemblyOracle::Schedule : receiver = "
--- a/Framework/Oracle/WebAssemblyOracle.h Tue Nov 05 18:26:59 2019 +0100 +++ b/Framework/Oracle/WebAssemblyOracle.h Tue Nov 05 18:51:04 2019 +0100 @@ -76,7 +76,7 @@ orthancRoot_ = root; } - virtual void Schedule(const IObserver& receiver, - IOracleCommand* command); + virtual void Schedule(boost::shared_ptr<IObserver>& receiver, + IOracleCommand* command) ORTHANC_OVERRIDE; }; }
--- a/Framework/Radiography/RadiographyAlphaLayer.h Tue Nov 05 18:26:59 2019 +0100 +++ b/Framework/Radiography/RadiographyAlphaLayer.h Tue Nov 05 18:51:04 2019 +0100 @@ -38,8 +38,8 @@ float foreground_; public: - RadiographyAlphaLayer(MessageBroker& broker, const RadiographyScene& scene) : - RadiographyLayer(broker, scene), + RadiographyAlphaLayer(const RadiographyScene& scene) : + RadiographyLayer(scene), useWindowing_(true), foreground_(0) {
--- a/Framework/Radiography/RadiographyDicomLayer.cpp Tue Nov 05 18:26:59 2019 +0100 +++ b/Framework/Radiography/RadiographyDicomLayer.cpp Tue Nov 05 18:51:04 2019 +0100 @@ -47,7 +47,8 @@ } - RadiographyDicomLayer::RadiographyDicomLayer(MessageBroker& broker, const RadiographyScene& scene) : RadiographyLayer(broker, scene) + RadiographyDicomLayer::RadiographyDicomLayer(const RadiographyScene& scene) : + RadiographyLayer(scene) { }
--- a/Framework/Radiography/RadiographyDicomLayer.h Tue Nov 05 18:26:59 2019 +0100 +++ b/Framework/Radiography/RadiographyDicomLayer.h Tue Nov 05 18:51:04 2019 +0100 @@ -42,7 +42,7 @@ void ApplyConverter(); public: - RadiographyDicomLayer(MessageBroker& broker, const RadiographyScene& scene); + RadiographyDicomLayer(const RadiographyScene& scene); void SetInstance(const std::string& instanceId, unsigned int frame) {
--- a/Framework/Radiography/RadiographyLayer.cpp Tue Nov 05 18:26:59 2019 +0100 +++ b/Framework/Radiography/RadiographyLayer.cpp Tue Nov 05 18:51:04 2019 +0100 @@ -119,8 +119,7 @@ } - RadiographyLayer::RadiographyLayer(MessageBroker& broker, const RadiographyScene& scene) : - IObservable(broker), + RadiographyLayer::RadiographyLayer(const RadiographyScene& scene) : index_(0), hasSize_(false), width_(0),
--- a/Framework/Radiography/RadiographyLayer.h Tue Nov 05 18:26:59 2019 +0100 +++ b/Framework/Radiography/RadiographyLayer.h Tue Nov 05 18:51:04 2019 +0100 @@ -248,7 +248,7 @@ double zoom); public: - RadiographyLayer(MessageBroker& broker, const RadiographyScene& scene); + RadiographyLayer(const RadiographyScene& scene); virtual ~RadiographyLayer() {
--- a/Framework/Radiography/RadiographyMaskLayer.h Tue Nov 05 18:26:59 2019 +0100 +++ b/Framework/Radiography/RadiographyMaskLayer.h Tue Nov 05 18:51:04 2019 +0100 @@ -40,9 +40,9 @@ mutable std::auto_ptr<Orthanc::ImageAccessor> mask_; public: - RadiographyMaskLayer(MessageBroker& broker, const RadiographyScene& scene, const RadiographyDicomLayer& dicomLayer, + RadiographyMaskLayer(const RadiographyScene& scene, const RadiographyDicomLayer& dicomLayer, float foreground) : - RadiographyLayer(broker, scene), + RadiographyLayer(scene), dicomLayer_(dicomLayer), invalidated_(true), foreground_(foreground)
--- a/Framework/Radiography/RadiographyScene.cpp Tue Nov 05 18:26:59 2019 +0100 +++ b/Framework/Radiography/RadiographyScene.cpp Tue Nov 05 18:51:04 2019 +0100 @@ -142,7 +142,7 @@ BroadcastMessage(GeometryChangedMessage(*this, *layer)); BroadcastMessage(ContentChangedMessage(*this, *layer)); - layer->RegisterObserverCallback(new Callable<RadiographyScene, RadiographyLayer::LayerEditedMessage>(*this, &RadiographyScene::OnLayerEdited)); + Register<RadiographyLayer::LayerEditedMessage>(*layer, &RadiographyScene::OnLayerEdited); return *layer; } @@ -162,9 +162,7 @@ BroadcastMessage(RadiographyScene::LayerEditedMessage(*this, message.GetOrigin())); } - RadiographyScene::RadiographyScene(MessageBroker& broker) : - IObserver(broker), - IObservable(broker), + RadiographyScene::RadiographyScene() : countLayers_(0), hasWindowing_(false), windowingCenter_(0), // Dummy initialization @@ -284,7 +282,7 @@ const std::string& utf8, RadiographyLayer::Geometry* geometry) { - std::auto_ptr<RadiographyTextLayer> alpha(new RadiographyTextLayer(IObservable::GetBroker(), *this)); + std::auto_ptr<RadiographyTextLayer> alpha(new RadiographyTextLayer(*this)); alpha->LoadText(font, utf8); if (geometry != NULL) { @@ -328,7 +326,7 @@ float foreground, RadiographyLayer::Geometry* geometry) { - std::auto_ptr<RadiographyMaskLayer> mask(new RadiographyMaskLayer(IObservable::GetBroker(), *this, dicomLayer, foreground)); + std::auto_ptr<RadiographyMaskLayer> mask(new RadiographyMaskLayer(*this, dicomLayer, foreground)); mask->SetCorners(corners); if (geometry != NULL) { @@ -341,7 +339,7 @@ RadiographyLayer& RadiographyScene::LoadAlphaBitmap(Orthanc::ImageAccessor* bitmap, RadiographyLayer::Geometry *geometry) { - std::auto_ptr<RadiographyAlphaLayer> alpha(new RadiographyAlphaLayer(IObservable::GetBroker(), *this)); + std::auto_ptr<RadiographyAlphaLayer> alpha(new RadiographyAlphaLayer(*this)); alpha->SetAlpha(bitmap); if (geometry != NULL) { @@ -358,7 +356,7 @@ RadiographyPhotometricDisplayMode preferredPhotometricDisplayMode, RadiographyLayer::Geometry* geometry) { - RadiographyDicomLayer& layer = dynamic_cast<RadiographyDicomLayer&>(RegisterLayer(new RadiographyDicomLayer(IObservable::GetBroker(), *this))); + RadiographyDicomLayer& layer = dynamic_cast<RadiographyDicomLayer&>(RegisterLayer(new RadiographyDicomLayer(*this))); layer.SetInstance(instance, frame); @@ -380,7 +378,7 @@ bool httpCompression, RadiographyLayer::Geometry* geometry) { - RadiographyDicomLayer& layer = dynamic_cast<RadiographyDicomLayer&>(RegisterLayer(new RadiographyDicomLayer(IObservable::GetBroker(), *this))); + RadiographyDicomLayer& layer = dynamic_cast<RadiographyDicomLayer&>(RegisterLayer(new RadiographyDicomLayer( *this))); layer.SetInstance(instance, frame); if (geometry != NULL) @@ -395,7 +393,7 @@ orthanc.GetBinaryAsync( uri, headers, new Callable<RadiographyScene, Deprecated::OrthancApiClient::BinaryResponseReadyMessage> - (*this, &RadiographyScene::OnTagsReceived), NULL, + (GetSharedObserver(), &RadiographyScene::OnTagsReceived), NULL, new Orthanc::SingleValueObject<size_t>(layer.GetIndex())); } @@ -414,7 +412,7 @@ orthanc.GetBinaryAsync( uri, headers, new Callable<RadiographyScene, Deprecated::OrthancApiClient::BinaryResponseReadyMessage> - (*this, &RadiographyScene::OnFrameReceived), NULL, + (GetSharedObserver(), &RadiographyScene::OnFrameReceived), NULL, new Orthanc::SingleValueObject<size_t>(layer.GetIndex())); } @@ -424,7 +422,7 @@ RadiographyLayer& RadiographyScene::LoadDicomWebFrame(Deprecated::IWebService& web) { - RadiographyLayer& layer = RegisterLayer(new RadiographyDicomLayer(IObservable::GetBroker(), *this)); + RadiographyLayer& layer = RegisterLayer(new RadiographyDicomLayer(*this)); return layer; @@ -752,7 +750,7 @@ orthanc.PostJsonAsyncExpectJson( "/tools/create-dicom", createDicomRequestContent, new Callable<RadiographyScene, Deprecated::OrthancApiClient::JsonResponseReadyMessage> - (*this, &RadiographyScene::OnDicomExported), + (GetSharedObserver(), &RadiographyScene::OnDicomExported), NULL, NULL); }
--- a/Framework/Radiography/RadiographyScene.h Tue Nov 05 18:26:59 2019 +0100 +++ b/Framework/Radiography/RadiographyScene.h Tue Nov 05 18:51:04 2019 +0100 @@ -22,6 +22,7 @@ #pragma once #include "RadiographyLayer.h" +#include "../Messages/ObserverBase.h" #include "../Deprecated/Toolbox/DicomFrameConverter.h" #include "../Deprecated/Toolbox/OrthancApiClient.h" #include "../StoneEnumerations.h" @@ -33,8 +34,8 @@ class RadiographyDicomLayer; class RadiographyScene : - public IObserver, - public IObservable + public ObserverBase<RadiographyScene>, + public IObservable { public: class GeometryChangedMessage : public OriginMessage<RadiographyScene> @@ -159,7 +160,7 @@ virtual void OnLayerEdited(const RadiographyLayer::LayerEditedMessage& message); public: - RadiographyScene(MessageBroker& broker); + RadiographyScene(); virtual ~RadiographyScene();
--- a/Framework/Radiography/RadiographySceneReader.cpp Tue Nov 05 18:26:59 2019 +0100 +++ b/Framework/Radiography/RadiographySceneReader.cpp Tue Nov 05 18:51:04 2019 +0100 @@ -50,7 +50,7 @@ RadiographyDicomLayer* RadiographySceneReader::LoadDicom(const std::string& instanceId, unsigned int frame, RadiographyLayer::Geometry* geometry) { - return dynamic_cast<RadiographyDicomLayer*>(&(scene_.LoadDicomFrame(orthancApiClient_, instanceId, frame, false, geometry))); + return dynamic_cast<RadiographyDicomLayer*>(&(scene_.LoadDicomFrame(*orthancApiClient_, instanceId, frame, false, geometry))); } void RadiographySceneBuilder::Read(const Json::Value& input) @@ -161,7 +161,7 @@ if (jsonLayer["type"].asString() == "dicom") { ReadLayerGeometry(geometry, jsonLayer); - dicomLayer = dynamic_cast<RadiographyDicomLayer*>(&(scene_.LoadDicomFrame(orthancApiClient_, jsonLayer["instanceId"].asString(), jsonLayer["frame"].asUInt(), false, &geometry))); + dicomLayer = dynamic_cast<RadiographyDicomLayer*>(&(scene_.LoadDicomFrame(*orthancApiClient_, jsonLayer["instanceId"].asString(), jsonLayer["frame"].asUInt(), false, &geometry))); } else if (jsonLayer["type"].asString() == "mask") {
--- a/Framework/Radiography/RadiographySceneReader.h Tue Nov 05 18:26:59 2019 +0100 +++ b/Framework/Radiography/RadiographySceneReader.h Tue Nov 05 18:51:04 2019 +0100 @@ -75,10 +75,12 @@ class RadiographySceneReader : public RadiographySceneBuilder { - Deprecated::OrthancApiClient& orthancApiClient_; + private: + boost::shared_ptr<Deprecated::OrthancApiClient> orthancApiClient_; public: - RadiographySceneReader(RadiographyScene& scene, Deprecated::OrthancApiClient& orthancApiClient) : + RadiographySceneReader(RadiographyScene& scene, + boost::shared_ptr<Deprecated::OrthancApiClient> orthancApiClient) : RadiographySceneBuilder(scene), orthancApiClient_(orthancApiClient) {
--- a/Framework/Radiography/RadiographyTextLayer.h Tue Nov 05 18:26:59 2019 +0100 +++ b/Framework/Radiography/RadiographyTextLayer.h Tue Nov 05 18:51:04 2019 +0100 @@ -34,8 +34,8 @@ std::string fontName_; public: - RadiographyTextLayer(MessageBroker& broker, const RadiographyScene& scene) : - RadiographyAlphaLayer(broker, scene) + RadiographyTextLayer(const RadiographyScene& scene) : + RadiographyAlphaLayer(scene) { }
--- a/Framework/Radiography/RadiographyWidget.cpp Tue Nov 05 18:26:59 2019 +0100 +++ b/Framework/Radiography/RadiographyWidget.cpp Tue Nov 05 18:51:04 2019 +0100 @@ -181,11 +181,9 @@ } - RadiographyWidget::RadiographyWidget(MessageBroker& broker, - boost::shared_ptr<RadiographyScene> scene, + RadiographyWidget::RadiographyWidget(boost::shared_ptr<RadiographyScene> scene, const std::string& name) : WorldSceneWidget(name), - IObserver(broker), invert_(false), interpolation_(ImageInterpolation_Nearest), hasSelection_(false), @@ -280,20 +278,10 @@ void RadiographyWidget::SetScene(boost::shared_ptr<RadiographyScene> scene) { - if (scene_ != NULL) - { - scene_->Unregister(this); - } - scene_ = scene; - scene_->RegisterObserverCallback( - new Callable<RadiographyWidget, RadiographyScene::GeometryChangedMessage> - (*this, &RadiographyWidget::OnGeometryChanged)); - - scene_->RegisterObserverCallback( - new Callable<RadiographyWidget, RadiographyScene::ContentChangedMessage> - (*this, &RadiographyWidget::OnContentChanged)); + Register<RadiographyScene::GeometryChangedMessage>(*scene_, &RadiographyWidget::OnGeometryChanged); + Register<RadiographyScene::ContentChangedMessage>(*scene_, &RadiographyWidget::OnContentChanged); NotifyContentChanged();
--- a/Framework/Radiography/RadiographyWidget.h Tue Nov 05 18:26:59 2019 +0100 +++ b/Framework/Radiography/RadiographyWidget.h Tue Nov 05 18:51:04 2019 +0100 @@ -22,6 +22,7 @@ #pragma once #include "../Deprecated/Widgets/WorldSceneWidget.h" +#include "../Messages/ObserverBase.h" #include "RadiographyScene.h" @@ -31,7 +32,7 @@ class RadiographyWidget : public Deprecated::WorldSceneWidget, - public IObserver + public ObserverBase<RadiographyWidget> { private: boost::shared_ptr<RadiographyScene> scene_; @@ -60,8 +61,7 @@ bool IsInvertedInternal() const; public: - RadiographyWidget(MessageBroker& broker, - boost::shared_ptr<RadiographyScene> scene, // TODO: check how we can avoid boost::shared_ptr here since we don't want them in the public API (app is keeping a boost::shared_ptr to this right now) + RadiographyWidget(boost::shared_ptr<RadiographyScene> scene, // TODO: check how we can avoid boost::shared_ptr here since we don't want them in the public API (app is keeping a boost::shared_ptr to this right now) const std::string& name); RadiographyScene& GetScene() const
--- a/Framework/Scene2DViewport/AngleMeasureTool.cpp Tue Nov 05 18:26:59 2019 +0100 +++ b/Framework/Scene2DViewport/AngleMeasureTool.cpp Tue Nov 05 18:51:04 2019 +0100 @@ -42,8 +42,8 @@ // the params in the LayerHolder ctor specify the number of polyline and text // layers AngleMeasureTool::AngleMeasureTool( - MessageBroker& broker, boost::weak_ptr<ViewportController> controllerW) - : MeasureTool(broker, controllerW) + boost::weak_ptr<ViewportController> controllerW) + : MeasureTool(controllerW) #if ORTHANC_STONE_ENABLE_OUTLINED_TEXT == 1 , layerHolder_(boost::make_shared<LayerHolder>(controllerW,1,5)) #else @@ -189,8 +189,9 @@ boost::weak_ptr<ViewportController> controllerW, const PointerEvent & e); */ + boost::shared_ptr<EditAngleMeasureTracker> editAngleMeasureTracker( - new EditAngleMeasureTracker(shared_from_this(), GetBroker(), GetController(), e)); + new EditAngleMeasureTracker(shared_from_this(), GetController(), e)); return editAngleMeasureTracker; }
--- a/Framework/Scene2DViewport/AngleMeasureTool.h Tue Nov 05 18:26:59 2019 +0100 +++ b/Framework/Scene2DViewport/AngleMeasureTool.h Tue Nov 05 18:51:04 2019 +0100 @@ -37,10 +37,10 @@ namespace OrthancStone { - class AngleMeasureTool : public MeasureTool, public boost::enable_shared_from_this<AngleMeasureTool> + class AngleMeasureTool : public MeasureTool { public: - AngleMeasureTool(MessageBroker& broker, boost::weak_ptr<ViewportController> controllerW); + AngleMeasureTool(boost::weak_ptr<ViewportController> controllerW); ~AngleMeasureTool();
--- a/Framework/Scene2DViewport/CreateAngleMeasureCommand.cpp Tue Nov 05 18:26:59 2019 +0100 +++ b/Framework/Scene2DViewport/CreateAngleMeasureCommand.cpp Tue Nov 05 18:51:04 2019 +0100 @@ -26,12 +26,11 @@ namespace OrthancStone { CreateAngleMeasureCommand::CreateAngleMeasureCommand( - MessageBroker& broker, boost::weak_ptr<ViewportController> controllerW, ScenePoint2D point) : CreateMeasureCommand(controllerW) , measureTool_( - boost::make_shared<AngleMeasureTool>(boost::ref(broker), controllerW)) + boost::make_shared<AngleMeasureTool>(controllerW)) { GetController()->AddMeasureTool(measureTool_); measureTool_->SetSide1End(point);
--- a/Framework/Scene2DViewport/CreateAngleMeasureCommand.h Tue Nov 05 18:26:59 2019 +0100 +++ b/Framework/Scene2DViewport/CreateAngleMeasureCommand.h Tue Nov 05 18:51:04 2019 +0100 @@ -28,7 +28,6 @@ public: /** Ctor sets end of side 1*/ CreateAngleMeasureCommand( - MessageBroker& broker, boost::weak_ptr<ViewportController> controllerW, ScenePoint2D point);
--- a/Framework/Scene2DViewport/CreateAngleMeasureTracker.cpp Tue Nov 05 18:26:59 2019 +0100 +++ b/Framework/Scene2DViewport/CreateAngleMeasureTracker.cpp Tue Nov 05 18:51:04 2019 +0100 @@ -26,7 +26,6 @@ namespace OrthancStone { CreateAngleMeasureTracker::CreateAngleMeasureTracker( - MessageBroker& broker, boost::weak_ptr<ViewportController> controllerW, const PointerEvent& e) : CreateMeasureTracker(controllerW) @@ -34,7 +33,6 @@ { command_.reset( new CreateAngleMeasureCommand( - broker, controllerW, e.GetMainPosition().Apply(GetScene().GetCanvasToSceneTransform()))); }
--- a/Framework/Scene2DViewport/CreateAngleMeasureTracker.h Tue Nov 05 18:26:59 2019 +0100 +++ b/Framework/Scene2DViewport/CreateAngleMeasureTracker.h Tue Nov 05 18:51:04 2019 +0100 @@ -38,7 +38,6 @@ must be supplied, too */ CreateAngleMeasureTracker( - MessageBroker& broker, boost::weak_ptr<ViewportController> controllerW, const PointerEvent& e);
--- a/Framework/Scene2DViewport/CreateLineMeasureCommand.cpp Tue Nov 05 18:26:59 2019 +0100 +++ b/Framework/Scene2DViewport/CreateLineMeasureCommand.cpp Tue Nov 05 18:51:04 2019 +0100 @@ -26,12 +26,11 @@ namespace OrthancStone { CreateLineMeasureCommand::CreateLineMeasureCommand( - MessageBroker& broker, boost::weak_ptr<ViewportController> controllerW, ScenePoint2D point) : CreateMeasureCommand(controllerW) , measureTool_( - boost::make_shared<LineMeasureTool>(boost::ref(broker), controllerW)) + boost::make_shared<LineMeasureTool>(controllerW)) { GetController()->AddMeasureTool(measureTool_); measureTool_->Set(point, point);
--- a/Framework/Scene2DViewport/CreateLineMeasureCommand.h Tue Nov 05 18:26:59 2019 +0100 +++ b/Framework/Scene2DViewport/CreateLineMeasureCommand.h Tue Nov 05 18:51:04 2019 +0100 @@ -27,7 +27,6 @@ { public: CreateLineMeasureCommand( - MessageBroker& broker, boost::weak_ptr<ViewportController> controllerW, ScenePoint2D point);
--- a/Framework/Scene2DViewport/CreateLineMeasureTracker.cpp Tue Nov 05 18:26:59 2019 +0100 +++ b/Framework/Scene2DViewport/CreateLineMeasureTracker.cpp Tue Nov 05 18:51:04 2019 +0100 @@ -26,14 +26,12 @@ namespace OrthancStone { CreateLineMeasureTracker::CreateLineMeasureTracker( - MessageBroker& broker, boost::weak_ptr<ViewportController> controllerW, const PointerEvent& e) : CreateMeasureTracker(controllerW) { command_.reset( new CreateLineMeasureCommand( - broker, controllerW, e.GetMainPosition().Apply(GetScene().GetCanvasToSceneTransform()))); }
--- a/Framework/Scene2DViewport/CreateLineMeasureTracker.h Tue Nov 05 18:26:59 2019 +0100 +++ b/Framework/Scene2DViewport/CreateLineMeasureTracker.h Tue Nov 05 18:51:04 2019 +0100 @@ -38,7 +38,6 @@ must be supplied, too */ CreateLineMeasureTracker( - MessageBroker& broker, boost::weak_ptr<ViewportController> controllerW, const PointerEvent& e);
--- a/Framework/Scene2DViewport/EditAngleMeasureCommand.cpp Tue Nov 05 18:26:59 2019 +0100 +++ b/Framework/Scene2DViewport/EditAngleMeasureCommand.cpp Tue Nov 05 18:51:04 2019 +0100 @@ -23,8 +23,7 @@ namespace OrthancStone { EditAngleMeasureCommand::EditAngleMeasureCommand( - boost::shared_ptr<AngleMeasureTool> measureTool, - MessageBroker& broker, + boost::shared_ptr<MeasureTool> measureTool, boost::weak_ptr<ViewportController> controllerW) : EditMeasureCommand(measureTool, controllerW) , measureTool_(measureTool) @@ -33,21 +32,21 @@ void EditAngleMeasureCommand::SetCenter(ScenePoint2D scenePos) { - measureTool_->SetCenter(scenePos); + dynamic_cast<AngleMeasureTool&>(*measureTool_).SetCenter(scenePos); mementoModified_ = measureTool_->GetMemento(); } void EditAngleMeasureCommand::SetSide1End(ScenePoint2D scenePos) { - measureTool_->SetSide1End(scenePos); + dynamic_cast<AngleMeasureTool&>(*measureTool_).SetSide1End(scenePos); mementoModified_ = measureTool_->GetMemento(); } void EditAngleMeasureCommand::SetSide2End(ScenePoint2D scenePos) { - measureTool_->SetSide2End(scenePos); + dynamic_cast<AngleMeasureTool&>(*measureTool_).SetSide2End(scenePos); mementoModified_ = measureTool_->GetMemento(); } }
--- a/Framework/Scene2DViewport/EditAngleMeasureCommand.h Tue Nov 05 18:26:59 2019 +0100 +++ b/Framework/Scene2DViewport/EditAngleMeasureCommand.h Tue Nov 05 18:51:04 2019 +0100 @@ -28,8 +28,7 @@ public: /** Ctor sets end of side 1*/ EditAngleMeasureCommand( - boost::shared_ptr<AngleMeasureTool> measureTool, - MessageBroker& broker, + boost::shared_ptr<MeasureTool> measureTool, boost::weak_ptr<ViewportController> controllerW); /** This method sets center*/ @@ -46,6 +45,6 @@ { return measureTool_; } - boost::shared_ptr<AngleMeasureTool> measureTool_; + boost::shared_ptr<MeasureTool> measureTool_; }; }
--- a/Framework/Scene2DViewport/EditAngleMeasureTracker.cpp Tue Nov 05 18:26:59 2019 +0100 +++ b/Framework/Scene2DViewport/EditAngleMeasureTracker.cpp Tue Nov 05 18:51:04 2019 +0100 @@ -26,8 +26,7 @@ namespace OrthancStone { EditAngleMeasureTracker::EditAngleMeasureTracker( - boost::shared_ptr<AngleMeasureTool> measureTool, - MessageBroker& broker, + boost::shared_ptr<MeasureTool> measureTool, boost::weak_ptr<ViewportController> controllerW, const PointerEvent& e) : EditMeasureTracker(controllerW, e) @@ -35,9 +34,9 @@ ScenePoint2D scenePos = e.GetMainPosition().Apply( GetScene().GetCanvasToSceneTransform()); - modifiedZone_ = measureTool->AngleHitTest(scenePos); + modifiedZone_ = dynamic_cast<AngleMeasureTool&>(*measureTool).AngleHitTest(scenePos); - command_.reset(new EditAngleMeasureCommand(measureTool, broker, controllerW)); + command_.reset(new EditAngleMeasureCommand(measureTool, controllerW)); } EditAngleMeasureTracker::~EditAngleMeasureTracker()
--- a/Framework/Scene2DViewport/EditAngleMeasureTracker.h Tue Nov 05 18:26:59 2019 +0100 +++ b/Framework/Scene2DViewport/EditAngleMeasureTracker.h Tue Nov 05 18:51:04 2019 +0100 @@ -37,8 +37,7 @@ must be supplied, too */ EditAngleMeasureTracker( - boost::shared_ptr<AngleMeasureTool> measureTool, - MessageBroker& broker, + boost::shared_ptr<MeasureTool> measureTool, boost::weak_ptr<ViewportController> controllerW, const PointerEvent& e);
--- a/Framework/Scene2DViewport/EditLineMeasureCommand.cpp Tue Nov 05 18:26:59 2019 +0100 +++ b/Framework/Scene2DViewport/EditLineMeasureCommand.cpp Tue Nov 05 18:51:04 2019 +0100 @@ -23,8 +23,7 @@ namespace OrthancStone { EditLineMeasureCommand::EditLineMeasureCommand( - boost::shared_ptr<LineMeasureTool> measureTool, - MessageBroker& broker, + boost::shared_ptr<MeasureTool> measureTool, boost::weak_ptr<ViewportController> controllerW) : EditMeasureCommand(measureTool, controllerW) , measureTool_(measureTool) @@ -34,14 +33,14 @@ void EditLineMeasureCommand::SetStart(ScenePoint2D scenePos) { - measureTool_->SetStart(scenePos); + dynamic_cast<LineMeasureTool&>(*measureTool_).SetStart(scenePos); mementoModified_ = measureTool_->GetMemento(); } void EditLineMeasureCommand::SetEnd(ScenePoint2D scenePos) { - measureTool_->SetEnd(scenePos); + dynamic_cast<LineMeasureTool&>(*measureTool_).SetEnd(scenePos); mementoModified_ = measureTool_->GetMemento(); } }
--- a/Framework/Scene2DViewport/EditLineMeasureCommand.h Tue Nov 05 18:26:59 2019 +0100 +++ b/Framework/Scene2DViewport/EditLineMeasureCommand.h Tue Nov 05 18:51:04 2019 +0100 @@ -27,8 +27,7 @@ { public: EditLineMeasureCommand( - boost::shared_ptr<LineMeasureTool> measureTool, - MessageBroker& broker, + boost::shared_ptr<MeasureTool> measureTool, boost::weak_ptr<ViewportController> controllerW); void SetStart(ScenePoint2D scenePos); @@ -39,7 +38,6 @@ { return measureTool_; } - boost::shared_ptr<LineMeasureTool> measureTool_; + boost::shared_ptr<MeasureTool> measureTool_; }; } -
--- a/Framework/Scene2DViewport/EditLineMeasureTracker.cpp Tue Nov 05 18:26:59 2019 +0100 +++ b/Framework/Scene2DViewport/EditLineMeasureTracker.cpp Tue Nov 05 18:51:04 2019 +0100 @@ -27,8 +27,7 @@ namespace OrthancStone { EditLineMeasureTracker::EditLineMeasureTracker( - boost::shared_ptr<LineMeasureTool> measureTool, - MessageBroker& broker, + boost::shared_ptr<MeasureTool> measureTool, boost::weak_ptr<ViewportController> controllerW, const PointerEvent& e) : EditMeasureTracker(controllerW, e) @@ -36,13 +35,9 @@ ScenePoint2D scenePos = e.GetMainPosition().Apply( GetScene().GetCanvasToSceneTransform()); - modifiedZone_ = measureTool->LineHitTest(scenePos); + modifiedZone_ = dynamic_cast<LineMeasureTool&>(*measureTool).LineHitTest(scenePos); - command_.reset( - new EditLineMeasureCommand( - measureTool, - broker, - controllerW)); + command_.reset(new EditLineMeasureCommand(measureTool, controllerW)); } EditLineMeasureTracker::~EditLineMeasureTracker()
--- a/Framework/Scene2DViewport/EditLineMeasureTracker.h Tue Nov 05 18:26:59 2019 +0100 +++ b/Framework/Scene2DViewport/EditLineMeasureTracker.h Tue Nov 05 18:51:04 2019 +0100 @@ -37,8 +37,7 @@ must be supplied, too */ EditLineMeasureTracker( - boost::shared_ptr<LineMeasureTool> measureTool, - MessageBroker& broker, + boost::shared_ptr<MeasureTool> measureTool, boost::weak_ptr<ViewportController> controllerW, const PointerEvent& e);
--- a/Framework/Scene2DViewport/LineMeasureTool.cpp Tue Nov 05 18:26:59 2019 +0100 +++ b/Framework/Scene2DViewport/LineMeasureTool.cpp Tue Nov 05 18:51:04 2019 +0100 @@ -32,8 +32,8 @@ { LineMeasureTool::LineMeasureTool( - MessageBroker& broker, boost::weak_ptr<ViewportController> controllerW) - : MeasureTool(broker, controllerW) + boost::weak_ptr<ViewportController> controllerW) + : MeasureTool(controllerW) #if ORTHANC_STONE_ENABLE_OUTLINED_TEXT == 1 , layerHolder_(boost::make_shared<LayerHolder>(controllerW, 1, 5)) #else @@ -148,7 +148,7 @@ const PointerEvent & e); */ boost::shared_ptr<EditLineMeasureTracker> editLineMeasureTracker( - new EditLineMeasureTracker(shared_from_this(), GetBroker(), GetController(), e)); + new EditLineMeasureTracker(shared_from_this(), GetController(), e)); return editLineMeasureTracker; }
--- a/Framework/Scene2DViewport/LineMeasureTool.h Tue Nov 05 18:26:59 2019 +0100 +++ b/Framework/Scene2DViewport/LineMeasureTool.h Tue Nov 05 18:51:04 2019 +0100 @@ -35,10 +35,10 @@ namespace OrthancStone { - class LineMeasureTool : public MeasureTool, public boost::enable_shared_from_this<LineMeasureTool> + class LineMeasureTool : public MeasureTool { public: - LineMeasureTool(MessageBroker& broker, boost::weak_ptr<ViewportController> controllerW); + LineMeasureTool(boost::weak_ptr<ViewportController> controllerW); ~LineMeasureTool();
--- a/Framework/Scene2DViewport/MeasureTool.cpp Tue Nov 05 18:26:59 2019 +0100 +++ b/Framework/Scene2DViewport/MeasureTool.cpp Tue Nov 05 18:51:04 2019 +0100 @@ -28,14 +28,6 @@ namespace OrthancStone { - MeasureTool::~MeasureTool() - { - // if the controller is dead, let's not bother. - boost::shared_ptr<ViewportController> controller = controllerW_.lock(); - if (controller) - controller->Unregister(this); - } - void MeasureTool::Enable() { enabled_ = true; @@ -79,15 +71,13 @@ #endif } - MeasureTool::MeasureTool(MessageBroker& broker, + MeasureTool::MeasureTool( boost::weak_ptr<ViewportController> controllerW) - : IObserver(broker) - , controllerW_(controllerW) + : controllerW_(controllerW) , enabled_(true) { - GetController()->RegisterObserverCallback( - new Callable<MeasureTool, ViewportController::SceneTransformChanged> - (*this, &MeasureTool::OnSceneTransformChanged)); + // TODO => Move this out of constructor + Register<ViewportController::SceneTransformChanged>(*GetController(), &MeasureTool::OnSceneTransformChanged); }
--- a/Framework/Scene2DViewport/MeasureTool.h Tue Nov 05 18:26:59 2019 +0100 +++ b/Framework/Scene2DViewport/MeasureTool.h Tue Nov 05 18:51:04 2019 +0100 @@ -20,6 +20,7 @@ #pragma once +#include "../Messages/ObserverBase.h" #include "../Scene2D/PolylineSceneLayer.h" #include "../Scene2D/Scene2D.h" #include "../Scene2D/ScenePoint2D.h" @@ -27,7 +28,6 @@ #include "../Scene2DViewport/PredeclaredTypes.h" #include "../Scene2DViewport/ViewportController.h" -#include <boost/shared_ptr.hpp> #include <boost/weak_ptr.hpp> #include <vector> @@ -38,10 +38,12 @@ class IFlexiblePointerTracker; class MeasureToolMemento; - class MeasureTool : public IObserver + class MeasureTool : public ObserverBase<MeasureTool> { public: - virtual ~MeasureTool(); + virtual ~MeasureTool() + { + } /** Enabled tools are rendered in the scene. @@ -111,7 +113,7 @@ virtual std::string GetDescription() = 0; protected: - MeasureTool(MessageBroker& broker, boost::weak_ptr<ViewportController> controllerW); + MeasureTool(boost::weak_ptr<ViewportController> controllerW); /** The measuring tool may exist in a standalone fashion, without any available
--- a/Framework/Scene2DViewport/ViewportController.cpp Tue Nov 05 18:26:59 2019 +0100 +++ b/Framework/Scene2DViewport/ViewportController.cpp Tue Nov 05 18:51:04 2019 +0100 @@ -30,10 +30,8 @@ namespace OrthancStone { ViewportController::ViewportController(boost::weak_ptr<UndoStack> undoStackW, - MessageBroker& broker, IViewport& viewport) - : IObservable(broker) - , undoStackW_(undoStackW) + : undoStackW_(undoStackW) , canvasToSceneFactor_(0.0) , viewport_(viewport) {
--- a/Framework/Scene2DViewport/ViewportController.h Tue Nov 05 18:26:59 2019 +0100 +++ b/Framework/Scene2DViewport/ViewportController.h Tue Nov 05 18:51:04 2019 +0100 @@ -81,7 +81,6 @@ SceneTransformChanged, ViewportController); ViewportController(boost::weak_ptr<UndoStack> undoStackW, - MessageBroker& broker, IViewport& viewport);
--- a/Framework/Toolbox/GenericToolbox.h Tue Nov 05 18:26:59 2019 +0100 +++ b/Framework/Toolbox/GenericToolbox.h Tue Nov 05 18:51:04 2019 +0100 @@ -117,7 +117,7 @@ if (*p == '.') { double f = 0.0; - int n = 1; + size_t n = 1; ++p; while (*p >= '0' && *p <= '9' && n < FRAC_FACTORS_LEN) {
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Framework/Toolbox/ParsedDicomFileCache.cpp Tue Nov 05 18:51:04 2019 +0100 @@ -0,0 +1,141 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2019 Osimis S.A., Belgium + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU Affero General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + **/ + + +#include "ParsedDicomFileCache.h" + +namespace OrthancStone +{ + class ParsedDicomFileCache::Item : public Orthanc::ICacheable + { + private: + boost::mutex mutex_; + boost::shared_ptr<Orthanc::ParsedDicomFile> dicom_; + size_t fileSize_; + bool hasPixelData_; + + public: + Item(boost::shared_ptr<Orthanc::ParsedDicomFile> dicom, + size_t fileSize, + bool hasPixelData) : + dicom_(dicom), + fileSize_(fileSize), + hasPixelData_(hasPixelData) + { + if (dicom == NULL) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer); + } + } + + boost::mutex& GetMutex() + { + return mutex_; + } + + virtual size_t GetMemoryUsage() const + { + return fileSize_; + } + + boost::shared_ptr<Orthanc::ParsedDicomFile> GetDicom() const + { + assert(dicom_.get() != NULL); + return dicom_; + } + + bool HasPixelData() const + { + return hasPixelData_; + } + }; + + + void ParsedDicomFileCache::Acquire(const std::string& path, + boost::shared_ptr<Orthanc::ParsedDicomFile> dicom, + size_t fileSize, + bool hasPixelData) + { + cache_.Acquire(path, new Item(dicom, fileSize, hasPixelData)); + } + + + ParsedDicomFileCache::Reader::Reader(ParsedDicomFileCache& cache, + const std::string& path) : + reader_(cache.cache_, path) + { + if (reader_.IsValid()) + { + /** + * The "Orthanc::MemoryObjectCache" uses readers/writers. The + * "Reader" subclass of the cache locks as a reader. This means + * that multiple threads can still access the underlying + * "ParsedDicomFile" object, which is not supported by DCMTK. We + * thus protect the DCMTK object by a simple mutex. + **/ + + item_ = &dynamic_cast<Item&>(reader_.GetValue()); + lock_.reset(new boost::mutex::scoped_lock(item_->GetMutex())); + } + else + { + item_ = NULL; + } + } + + + bool ParsedDicomFileCache::Reader::HasPixelData() const + { + if (item_ == NULL) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); + } + else + { + return item_->HasPixelData(); + } + } + + + boost::shared_ptr<Orthanc::ParsedDicomFile> ParsedDicomFileCache::Reader::GetDicom() const + { + if (item_ == NULL) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); + } + else + { + return item_->GetDicom(); + } + } + + + size_t ParsedDicomFileCache::Reader::GetFileSize() const + { + if (item_ == NULL) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); + } + else + { + return item_->GetMemoryUsage(); + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Framework/Toolbox/ParsedDicomFileCache.h Tue Nov 05 18:51:04 2019 +0100 @@ -0,0 +1,72 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2019 Osimis S.A., Belgium + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU Affero General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + **/ + + +#pragma once + +#include <Core/Cache/MemoryObjectCache.h> +#include <Core/DicomParsing/ParsedDicomFile.h> + +#include <boost/shared_ptr.hpp> + +namespace OrthancStone +{ + class ParsedDicomFileCache : public boost::noncopyable + { + private: + class Item; + + Orthanc::MemoryObjectCache cache_; + + public: + ParsedDicomFileCache(size_t size) + { + cache_.SetMaximumSize(size); + } + + void Acquire(const std::string& path, + boost::shared_ptr<Orthanc::ParsedDicomFile> dicom, + size_t fileSize, + bool hasPixelData); + + class Reader : public boost::noncopyable + { + private: + Orthanc::MemoryObjectCache::Reader reader_; + std::auto_ptr<boost::mutex::scoped_lock> lock_; + Item* item_; + + public: + Reader(ParsedDicomFileCache& cache, + const std::string& path); + + bool IsValid() const + { + return item_ != NULL; + } + + bool HasPixelData() const; + + boost::shared_ptr<Orthanc::ParsedDicomFile> GetDicom() const; + + size_t GetFileSize() const; + }; + }; +}
--- a/Platforms/Generic/DelayedCallCommand.cpp Tue Nov 05 18:26:59 2019 +0100 +++ b/Platforms/Generic/DelayedCallCommand.cpp Tue Nov 05 18:51:04 2019 +0100 @@ -26,13 +26,11 @@ namespace Deprecated { - DelayedCallCommand::DelayedCallCommand(OrthancStone::MessageBroker& broker, - OrthancStone::MessageHandler<IDelayedCallExecutor::TimeoutMessage>* callback, // takes ownership + DelayedCallCommand::DelayedCallCommand(OrthancStone::MessageHandler<IDelayedCallExecutor::TimeoutMessage>* callback, // takes ownership unsigned int timeoutInMs, Orthanc::IDynamicObject* payload /* takes ownership */, OrthancStone::NativeStoneApplicationContext& context ) : - IObservable(broker), callback_(callback), payload_(payload), context_(context),
--- a/Platforms/Generic/DelayedCallCommand.h Tue Nov 05 18:26:59 2019 +0100 +++ b/Platforms/Generic/DelayedCallCommand.h Tue Nov 05 18:51:04 2019 +0100 @@ -42,8 +42,7 @@ unsigned int timeoutInMs_; public: - DelayedCallCommand(OrthancStone::MessageBroker& broker, - OrthancStone::MessageHandler<IDelayedCallExecutor::TimeoutMessage>* callback, // takes ownership + DelayedCallCommand(OrthancStone::MessageHandler<IDelayedCallExecutor::TimeoutMessage>* callback, // takes ownership unsigned int timeoutInMs, Orthanc::IDynamicObject* payload /* takes ownership */, OrthancStone::NativeStoneApplicationContext& context
--- a/Platforms/Generic/OracleDelayedCallExecutor.h Tue Nov 05 18:26:59 2019 +0100 +++ b/Platforms/Generic/OracleDelayedCallExecutor.h Tue Nov 05 18:51:04 2019 +0100 @@ -36,10 +36,8 @@ OrthancStone::NativeStoneApplicationContext& context_; public: - OracleDelayedCallExecutor(OrthancStone::MessageBroker& broker, - Oracle& oracle, + OracleDelayedCallExecutor(Oracle& oracle, OrthancStone::NativeStoneApplicationContext& context) : - IDelayedCallExecutor(broker), oracle_(oracle), context_(context) { @@ -48,7 +46,7 @@ virtual void Schedule(OrthancStone::MessageHandler<IDelayedCallExecutor::TimeoutMessage>* callback, unsigned int timeoutInMs = 1000) { - oracle_.Submit(new DelayedCallCommand(broker_, callback, timeoutInMs, NULL, context_)); + oracle_.Submit(new DelayedCallCommand(callback, timeoutInMs, NULL, context_)); } }; }
--- a/Platforms/Generic/OracleWebService.cpp Tue Nov 05 18:26:59 2019 +0100 +++ b/Platforms/Generic/OracleWebService.cpp Tue Nov 05 18:51:04 2019 +0100 @@ -35,13 +35,11 @@ OrthancStone::NativeStoneApplicationContext& context_; public: - WebServiceCachedGetCommand(OrthancStone::MessageBroker& broker, - OrthancStone::MessageHandler<IWebService::HttpRequestSuccessMessage>* successCallback, // takes ownership + WebServiceCachedGetCommand(OrthancStone::MessageHandler<IWebService::HttpRequestSuccessMessage>* successCallback, // takes ownership boost::shared_ptr<BaseWebService::CachedHttpRequestSuccessMessage> cachedMessage, Orthanc::IDynamicObject* payload /* takes ownership */, OrthancStone::NativeStoneApplicationContext& context ) : - IObservable(broker), successCallback_(successCallback), payload_(payload), cachedMessage_(cachedMessage), @@ -75,7 +73,7 @@ Orthanc::IDynamicObject* payload, // takes ownership OrthancStone::MessageHandler<IWebService::HttpRequestSuccessMessage>* successCallback) { - oracle_.Submit(new WebServiceCachedGetCommand(GetBroker(), successCallback, cachedMessage, payload, context_)); + oracle_.Submit(new WebServiceCachedGetCommand(successCallback, cachedMessage, payload, context_)); }
--- a/Platforms/Generic/OracleWebService.h Tue Nov 05 18:26:59 2019 +0100 +++ b/Platforms/Generic/OracleWebService.h Tue Nov 05 18:51:04 2019 +0100 @@ -43,11 +43,9 @@ class WebServiceCachedGetCommand; public: - OracleWebService(OrthancStone::MessageBroker& broker, - Oracle& oracle, + OracleWebService(Oracle& oracle, const Orthanc::WebServiceParameters& parameters, OrthancStone::NativeStoneApplicationContext& context) : - BaseWebService(broker), oracle_(oracle), context_(context), parameters_(parameters) @@ -62,7 +60,7 @@ OrthancStone::MessageHandler<IWebService::HttpRequestErrorMessage>* failureCallback = NULL, // takes ownership unsigned int timeoutInSeconds = 60) { - oracle_.Submit(new WebServicePostCommand(GetBroker(), successCallback, failureCallback, parameters_, uri, headers, timeoutInSeconds, body, payload, context_)); + oracle_.Submit(new WebServicePostCommand(successCallback, failureCallback, parameters_, uri, headers, timeoutInSeconds, body, payload, context_)); } virtual void DeleteAsync(const std::string& uri, @@ -72,7 +70,7 @@ OrthancStone::MessageHandler<IWebService::HttpRequestErrorMessage>* failureCallback = NULL, unsigned int timeoutInSeconds = 60) { - oracle_.Submit(new WebServiceDeleteCommand(GetBroker(), successCallback, failureCallback, parameters_, uri, headers, timeoutInSeconds, payload, context_)); + oracle_.Submit(new WebServiceDeleteCommand(successCallback, failureCallback, parameters_, uri, headers, timeoutInSeconds, payload, context_)); } protected: @@ -83,7 +81,7 @@ OrthancStone::MessageHandler<IWebService::HttpRequestErrorMessage>* failureCallback = NULL,// takes ownership unsigned int timeoutInSeconds = 60) { - oracle_.Submit(new WebServiceGetCommand(GetBroker(), successCallback, failureCallback, parameters_, uri, headers, timeoutInSeconds, payload, context_)); + oracle_.Submit(new WebServiceGetCommand(successCallback, failureCallback, parameters_, uri, headers, timeoutInSeconds, payload, context_)); } virtual void NotifyHttpSuccessLater(boost::shared_ptr<BaseWebService::CachedHttpRequestSuccessMessage> cachedHttpMessage,
--- a/Platforms/Generic/WebServiceCommandBase.cpp Tue Nov 05 18:26:59 2019 +0100 +++ b/Platforms/Generic/WebServiceCommandBase.cpp Tue Nov 05 18:51:04 2019 +0100 @@ -25,8 +25,7 @@ namespace Deprecated { - WebServiceCommandBase::WebServiceCommandBase(OrthancStone::MessageBroker& broker, - OrthancStone::MessageHandler<IWebService::HttpRequestSuccessMessage>* successCallback, + WebServiceCommandBase::WebServiceCommandBase(OrthancStone::MessageHandler<IWebService::HttpRequestSuccessMessage>* successCallback, OrthancStone::MessageHandler<IWebService::HttpRequestErrorMessage>* failureCallback, const Orthanc::WebServiceParameters& parameters, const std::string& url, @@ -34,7 +33,6 @@ unsigned int timeoutInSeconds, Orthanc::IDynamicObject* payload /* takes ownership */, OrthancStone::NativeStoneApplicationContext& context) : - IObservable(broker), successCallback_(successCallback), failureCallback_(failureCallback), parameters_(parameters),
--- a/Platforms/Generic/WebServiceCommandBase.h Tue Nov 05 18:26:59 2019 +0100 +++ b/Platforms/Generic/WebServiceCommandBase.h Tue Nov 05 18:51:04 2019 +0100 @@ -51,8 +51,7 @@ unsigned int timeoutInSeconds_; public: - WebServiceCommandBase(OrthancStone::MessageBroker& broker, - OrthancStone::MessageHandler<IWebService::HttpRequestSuccessMessage>* successCallback, // takes ownership + WebServiceCommandBase(OrthancStone::MessageHandler<IWebService::HttpRequestSuccessMessage>* successCallback, // takes ownership OrthancStone::MessageHandler<IWebService::HttpRequestErrorMessage>* failureCallback, // takes ownership const Orthanc::WebServiceParameters& parameters, const std::string& url,
--- a/Platforms/Generic/WebServiceDeleteCommand.cpp Tue Nov 05 18:26:59 2019 +0100 +++ b/Platforms/Generic/WebServiceDeleteCommand.cpp Tue Nov 05 18:51:04 2019 +0100 @@ -25,8 +25,7 @@ namespace Deprecated { - WebServiceDeleteCommand::WebServiceDeleteCommand(OrthancStone::MessageBroker& broker, - OrthancStone::MessageHandler<Deprecated::IWebService::HttpRequestSuccessMessage>* successCallback, // takes ownership + WebServiceDeleteCommand::WebServiceDeleteCommand(OrthancStone::MessageHandler<Deprecated::IWebService::HttpRequestSuccessMessage>* successCallback, // takes ownership OrthancStone::MessageHandler<Deprecated::IWebService::HttpRequestErrorMessage>* failureCallback, // takes ownership const Orthanc::WebServiceParameters& parameters, const std::string& url, @@ -34,7 +33,7 @@ unsigned int timeoutInSeconds, Orthanc::IDynamicObject* payload /* takes ownership */, OrthancStone::NativeStoneApplicationContext& context) : - WebServiceCommandBase(broker, successCallback, failureCallback, parameters, url, headers, timeoutInSeconds, payload, context) + WebServiceCommandBase(successCallback, failureCallback, parameters, url, headers, timeoutInSeconds, payload, context) { }
--- a/Platforms/Generic/WebServiceDeleteCommand.h Tue Nov 05 18:26:59 2019 +0100 +++ b/Platforms/Generic/WebServiceDeleteCommand.h Tue Nov 05 18:51:04 2019 +0100 @@ -28,8 +28,7 @@ class WebServiceDeleteCommand : public WebServiceCommandBase { public: - WebServiceDeleteCommand(OrthancStone::MessageBroker& broker, - OrthancStone::MessageHandler<IWebService::HttpRequestSuccessMessage>* successCallback, // takes ownership + WebServiceDeleteCommand(OrthancStone::MessageHandler<IWebService::HttpRequestSuccessMessage>* successCallback, // takes ownership OrthancStone::MessageHandler<IWebService::HttpRequestErrorMessage>* failureCallback, // takes ownership const Orthanc::WebServiceParameters& parameters, const std::string& url,
--- a/Platforms/Generic/WebServiceGetCommand.cpp Tue Nov 05 18:26:59 2019 +0100 +++ b/Platforms/Generic/WebServiceGetCommand.cpp Tue Nov 05 18:51:04 2019 +0100 @@ -25,9 +25,7 @@ namespace Deprecated { - - WebServiceGetCommand::WebServiceGetCommand(OrthancStone::MessageBroker& broker, - OrthancStone::MessageHandler<IWebService::HttpRequestSuccessMessage>* successCallback, // takes ownership + WebServiceGetCommand::WebServiceGetCommand(OrthancStone::MessageHandler<IWebService::HttpRequestSuccessMessage>* successCallback, // takes ownership OrthancStone::MessageHandler<IWebService::HttpRequestErrorMessage>* failureCallback, // takes ownership const Orthanc::WebServiceParameters& parameters, const std::string& url, @@ -35,7 +33,7 @@ unsigned int timeoutInSeconds, Orthanc::IDynamicObject* payload /* takes ownership */, OrthancStone::NativeStoneApplicationContext& context) : - WebServiceCommandBase(broker, successCallback, failureCallback, parameters, url, headers, timeoutInSeconds, payload, context) + WebServiceCommandBase(successCallback, failureCallback, parameters, url, headers, timeoutInSeconds, payload, context) { }
--- a/Platforms/Generic/WebServiceGetCommand.h Tue Nov 05 18:26:59 2019 +0100 +++ b/Platforms/Generic/WebServiceGetCommand.h Tue Nov 05 18:51:04 2019 +0100 @@ -28,8 +28,7 @@ class WebServiceGetCommand : public WebServiceCommandBase { public: - WebServiceGetCommand(OrthancStone::MessageBroker& broker, - OrthancStone::MessageHandler<IWebService::HttpRequestSuccessMessage>* successCallback, // takes ownership + WebServiceGetCommand(OrthancStone::MessageHandler<IWebService::HttpRequestSuccessMessage>* successCallback, // takes ownership OrthancStone::MessageHandler<IWebService::HttpRequestErrorMessage>* failureCallback, // takes ownership const Orthanc::WebServiceParameters& parameters, const std::string& url,
--- a/Platforms/Generic/WebServicePostCommand.cpp Tue Nov 05 18:26:59 2019 +0100 +++ b/Platforms/Generic/WebServicePostCommand.cpp Tue Nov 05 18:51:04 2019 +0100 @@ -25,8 +25,7 @@ namespace Deprecated { - WebServicePostCommand::WebServicePostCommand(OrthancStone::MessageBroker& broker, - OrthancStone::MessageHandler<Deprecated::IWebService::HttpRequestSuccessMessage>* successCallback, // takes ownership + WebServicePostCommand::WebServicePostCommand(OrthancStone::MessageHandler<Deprecated::IWebService::HttpRequestSuccessMessage>* successCallback, // takes ownership OrthancStone::MessageHandler<Deprecated::IWebService::HttpRequestErrorMessage>* failureCallback, // takes ownership const Orthanc::WebServiceParameters& parameters, const std::string& url, @@ -35,7 +34,7 @@ const std::string& body, Orthanc::IDynamicObject* payload /* takes ownership */, OrthancStone::NativeStoneApplicationContext& context) : - WebServiceCommandBase(broker, successCallback, failureCallback, parameters, url, headers, timeoutInSeconds, payload, context), + WebServiceCommandBase(successCallback, failureCallback, parameters, url, headers, timeoutInSeconds, payload, context), body_(body) { }
--- a/Platforms/Generic/WebServicePostCommand.h Tue Nov 05 18:26:59 2019 +0100 +++ b/Platforms/Generic/WebServicePostCommand.h Tue Nov 05 18:51:04 2019 +0100 @@ -31,8 +31,7 @@ std::string body_; public: - WebServicePostCommand(OrthancStone::MessageBroker& broker, - OrthancStone::MessageHandler<IWebService::HttpRequestSuccessMessage>* successCallback, // takes ownership + WebServicePostCommand(OrthancStone::MessageHandler<IWebService::HttpRequestSuccessMessage>* successCallback, // takes ownership OrthancStone::MessageHandler<IWebService::HttpRequestErrorMessage>* failureCallback, // takes ownership const Orthanc::WebServiceParameters& parameters, const std::string& url,
--- a/Resources/CMake/OrthancStoneConfiguration.cmake Tue Nov 05 18:26:59 2019 +0100 +++ b/Resources/CMake/OrthancStoneConfiguration.cmake Tue Nov 05 18:51:04 2019 +0100 @@ -399,10 +399,19 @@ endif() +if (ENABLE_DCMTK) + list(APPEND ORTHANC_STONE_SOURCES + ${ORTHANC_STONE_ROOT}/Framework/Oracle/ParseDicomFileCommand.cpp + ${ORTHANC_STONE_ROOT}/Framework/Toolbox/ParsedDicomFileCache.cpp + ) +endif() + if (ENABLE_THREADS) list(APPEND ORTHANC_STONE_SOURCES + ${ORTHANC_STONE_ROOT}/Framework/Messages/LockingEmitter.cpp ${ORTHANC_STONE_ROOT}/Framework/Messages/LockingEmitter.h ${ORTHANC_STONE_ROOT}/Framework/Oracle/ThreadedOracle.cpp + ${ORTHANC_STONE_ROOT}/Framework/Oracle/GenericOracleRunner.cpp ) endif() @@ -452,10 +461,7 @@ ${ORTHANC_STONE_ROOT}/Framework/Messages/ICallable.h ${ORTHANC_STONE_ROOT}/Framework/Messages/IMessage.h ${ORTHANC_STONE_ROOT}/Framework/Messages/IObservable.cpp - ${ORTHANC_STONE_ROOT}/Framework/Messages/IObserver.cpp ${ORTHANC_STONE_ROOT}/Framework/Messages/IObserver.h - ${ORTHANC_STONE_ROOT}/Framework/Messages/MessageBroker.h - ${ORTHANC_STONE_ROOT}/Framework/Messages/MessageForwarder.cpp ${ORTHANC_STONE_ROOT}/Framework/Oracle/GetOrthancImageCommand.cpp ${ORTHANC_STONE_ROOT}/Framework/Oracle/GetOrthancWebViewerJpegCommand.cpp ${ORTHANC_STONE_ROOT}/Framework/Oracle/OracleCommandWithPayload.cpp @@ -557,6 +563,8 @@ ${ORTHANC_STONE_ROOT}/Framework/Toolbox/Extent2D.h ${ORTHANC_STONE_ROOT}/Framework/Toolbox/FiniteProjectiveCamera.cpp ${ORTHANC_STONE_ROOT}/Framework/Toolbox/FiniteProjectiveCamera.h + ${ORTHANC_STONE_ROOT}/Framework/Toolbox/GenericToolbox.cpp + ${ORTHANC_STONE_ROOT}/Framework/Toolbox/GenericToolbox.h ${ORTHANC_STONE_ROOT}/Framework/Toolbox/GeometryToolbox.cpp ${ORTHANC_STONE_ROOT}/Framework/Toolbox/GeometryToolbox.h ${ORTHANC_STONE_ROOT}/Framework/Toolbox/ImageGeometry.cpp @@ -573,8 +581,6 @@ ${ORTHANC_STONE_ROOT}/Framework/Toolbox/TextRenderer.h ${ORTHANC_STONE_ROOT}/Framework/Toolbox/UndoRedoStack.cpp ${ORTHANC_STONE_ROOT}/Framework/Toolbox/UndoRedoStack.h - ${ORTHANC_STONE_ROOT}/Framework/Toolbox/GenericToolbox.cpp - ${ORTHANC_STONE_ROOT}/Framework/Toolbox/GenericToolbox.h ${ORTHANC_STONE_ROOT}/Framework/Viewport/IViewport.h ${ORTHANC_STONE_ROOT}/Framework/Viewport/ViewportBase.h
--- a/UnitTestsSources/TestMessageBroker.cpp Tue Nov 05 18:26:59 2019 +0100 +++ b/UnitTestsSources/TestMessageBroker.cpp Tue Nov 05 18:51:04 2019 +0100 @@ -21,10 +21,8 @@ #include "gtest/gtest.h" -#include "../Framework/Messages/MessageBroker.h" -#include "../Framework/Messages/IObservable.h" -#include "../Framework/Messages/IObserver.h" -#include "../Framework/Messages/MessageForwarder.h" +#include "Framework/Messages/IObservable.h" +#include "Framework/Messages/ObserverBase.h" int testCounter = 0; @@ -47,51 +45,26 @@ { } }; - - MyObservable(MessageBroker& broker) : - IObservable(broker) - { - } }; - class MyObserver : public IObserver + class MyObserver : public ObserverBase<MyObserver> { public: - MyObserver(MessageBroker& broker) - : IObserver(broker) - {} - void HandleCompletedMessage(const MyObservable::MyCustomMessage& message) { testCounter += message.payload_; } - - }; - - - class MyIntermediate : public IObserver, public IObservable - { - IObservable& observedObject_; - public: - MyIntermediate(MessageBroker& broker, IObservable& observedObject) - : IObserver(broker), - IObservable(broker), - observedObject_(observedObject) - { - observedObject_.RegisterObserverCallback(new MessageForwarder<MyObservable::MyCustomMessage>(broker, *this)); - } }; } TEST(MessageBroker, TestPermanentConnectionSimpleUseCase) { - MessageBroker broker; - MyObservable observable(broker); - MyObserver observer(broker); + MyObservable observable; + boost::shared_ptr<MyObserver> observer(new MyObserver); // create a permanent connection between an observable and an observer - observable.RegisterObserverCallback(new Callable<MyObserver, MyObservable::MyCustomMessage>(observer, &MyObserver::HandleCompletedMessage)); + observer->Register<MyObservable::MyCustomMessage>(observable, &MyObserver::HandleCompletedMessage); testCounter = 0; observable.BroadcastMessage(MyObservable::MyCustomMessage(12)); @@ -103,155 +76,29 @@ ASSERT_EQ(20, testCounter); // Unregister the observer; make sure it's not called anymore - observable.Unregister(&observer); + observer.reset(); testCounter = 0; observable.BroadcastMessage(MyObservable::MyCustomMessage(20)); ASSERT_EQ(0, testCounter); } -TEST(MessageBroker, TestMessageForwarderSimpleUseCase) -{ - MessageBroker broker; - MyObservable observable(broker); - MyIntermediate intermediate(broker, observable); - MyObserver observer(broker); - - // let the observer observers the intermediate that is actually forwarding the messages from the observable - intermediate.RegisterObserverCallback(new Callable<MyObserver, MyObservable::MyCustomMessage>(observer, &MyObserver::HandleCompletedMessage)); - - testCounter = 0; - observable.BroadcastMessage(MyObservable::MyCustomMessage(12)); - ASSERT_EQ(12, testCounter); - - // the connection is permanent; if we emit the same message again, the observer will be notified again - testCounter = 0; - observable.BroadcastMessage(MyObservable::MyCustomMessage(20)); - ASSERT_EQ(20, testCounter); -} - TEST(MessageBroker, TestPermanentConnectionDeleteObserver) { - MessageBroker broker; - MyObservable observable(broker); - MyObserver* observer = new MyObserver(broker); + MyObservable observable; + boost::shared_ptr<MyObserver> observer(new MyObserver); // create a permanent connection between an observable and an observer - observable.RegisterObserverCallback(new Callable<MyObserver, MyObservable::MyCustomMessage>(*observer, &MyObserver::HandleCompletedMessage)); + observer->Register<MyObservable::MyCustomMessage>(observable, &MyObserver::HandleCompletedMessage); testCounter = 0; observable.BroadcastMessage(MyObservable::MyCustomMessage(12)); ASSERT_EQ(12, testCounter); // delete the observer and check that the callback is not called anymore - delete observer; + observer.reset(); // the connection is permanent; if we emit the same message again, the observer will be notified again testCounter = 0; observable.BroadcastMessage(MyObservable::MyCustomMessage(20)); ASSERT_EQ(0, testCounter); } - -TEST(MessageBroker, TestMessageForwarderDeleteIntermediate) -{ - MessageBroker broker; - MyObservable observable(broker); - MyIntermediate* intermediate = new MyIntermediate(broker, observable); - MyObserver observer(broker); - - // let the observer observers the intermediate that is actually forwarding the messages from the observable - intermediate->RegisterObserverCallback(new Callable<MyObserver, MyObservable::MyCustomMessage>(observer, &MyObserver::HandleCompletedMessage)); - - testCounter = 0; - observable.BroadcastMessage(MyObservable::MyCustomMessage(12)); - ASSERT_EQ(12, testCounter); - - delete intermediate; - - observable.BroadcastMessage(MyObservable::MyCustomMessage(20)); - ASSERT_EQ(12, testCounter); -} - -TEST(MessageBroker, TestCustomMessage) -{ - MessageBroker broker; - MyObservable observable(broker); - MyIntermediate intermediate(broker, observable); - MyObserver observer(broker); - - // let the observer observers the intermediate that is actually forwarding the messages from the observable - intermediate.RegisterObserverCallback(new Callable<MyObserver, MyObservable::MyCustomMessage>(observer, &MyObserver::HandleCompletedMessage)); - - testCounter = 0; - observable.BroadcastMessage(MyObservable::MyCustomMessage(12)); - ASSERT_EQ(12, testCounter); - - // the connection is permanent; if we emit the same message again, the observer will be notified again - testCounter = 0; - observable.BroadcastMessage(MyObservable::MyCustomMessage(20)); - ASSERT_EQ(20, testCounter); -} - - -#if 0 /* __cplusplus >= 201103L*/ - -TEST(MessageBroker, TestLambdaSimpleUseCase) -{ - MessageBroker broker; - MyObservable observable(broker); - MyObserver* observer = new MyObserver(broker); - - // create a permanent connection between an observable and an observer - observable.RegisterObserverCallback(new LambdaCallable<MyObservable::MyCustomMessage>(*observer, [&](const MyObservable::MyCustomMessage& message) {testCounter += 2 * message.payload_;})); - - testCounter = 0; - observable.BroadcastMessage(MyObservable::MyCustomMessage(12)); - ASSERT_EQ(24, testCounter); - - // delete the observer and check that the callback is not called anymore - delete observer; - - // the connection is permanent; if we emit the same message again, the observer will be notified again - testCounter = 0; - observable.BroadcastMessage(MyObservable::MyCustomMessage(20)); - ASSERT_EQ(0, testCounter); -} - -namespace { - class MyObserverWithLambda : public IObserver { - private: - int multiplier_; // this is a private variable we want to access in a lambda - - public: - MyObserverWithLambda(MessageBroker& broker, int multiplier, MyObservable& observable) - : IObserver(broker), - multiplier_(multiplier) - { - // register a callable to a lambda that access private members - observable.RegisterObserverCallback(new LambdaCallable<MyObservable::MyCustomMessage>(*this, [this](const MyObservable::MyCustomMessage& message) { - testCounter += multiplier_ * message.payload_; - })); - - } - }; -} - -TEST(MessageBroker, TestLambdaCaptureThisAndAccessPrivateMembers) -{ - MessageBroker broker; - MyObservable observable(broker); - MyObserverWithLambda* observer = new MyObserverWithLambda(broker, 3, observable); - - testCounter = 0; - observable.BroadcastMessage(MyObservable::MyCustomMessage(12)); - ASSERT_EQ(36, testCounter); - - // delete the observer and check that the callback is not called anymore - delete observer; - - // the connection is permanent; if we emit the same message again, the observer will be notified again - testCounter = 0; - observable.BroadcastMessage(MyObservable::MyCustomMessage(20)); - ASSERT_EQ(0, testCounter); -} - -#endif // C++ 11
--- a/UnitTestsSources/TestStructureSet.cpp Tue Nov 05 18:26:59 2019 +0100 +++ b/UnitTestsSources/TestStructureSet.cpp Tue Nov 05 18:51:04 2019 +0100 @@ -4729,8 +4729,8 @@ } ds.Union(0, 4); - EXPECT_EQ(0, ds.Find(0)); - EXPECT_EQ(0, ds.Find(4)); + EXPECT_EQ(0u, ds.Find(0)); + EXPECT_EQ(0u, ds.Find(4)); ds.Union(4, 6); ds.Union(8, 9); @@ -4875,7 +4875,7 @@ boundaries.clear(); EXPECT_NO_THROW(AddSlabBoundaries(boundaries, slabCuts, 0)); - ASSERT_EQ(0, boundaries.size()); + ASSERT_EQ(0u, boundaries.size()); } TEST(StructureSet, ProcessBoundaryListTopRow) @@ -4889,7 +4889,7 @@ { size_t i = 0; - ASSERT_EQ(4, boundaries.size()); + ASSERT_EQ(4u, boundaries.size()); ASSERT_EQ(RectangleBoundaryKind_Start, boundaries[i].second); ASSERT_NEAR(5, boundaries[i].first, DELTA_MAX); @@ -4919,7 +4919,7 @@ AddSlabBoundaries(boundaries, slabCuts, 0); AddSlabBoundaries(boundaries, slabCuts, 1); - ASSERT_EQ(8, boundaries.size()); + ASSERT_EQ(8u, boundaries.size()); { size_t i = 0;