# HG changeset patch # User Sebastien Jodogne # Date 1572976264 -3600 # Node ID d7e06542304cc2b7fcfd33c684c585f5b30817a2 # Parent a8bf817568392d8104f507d83bd0b1a952e99753# Parent 45df56448b2ac681ee865593395d8d398b0cc5fb integration mainline->broker diff -r 45df56448b2a -r d7e06542304c Applications/Generic/GuiAdapter.cpp --- 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) { diff -r 45df56448b2a -r d7e06542304c Applications/Generic/GuiAdapter.h --- 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 /** diff -r 45df56448b2a -r d7e06542304c Applications/Generic/NativeStoneApplicationContext.cpp --- 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 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 { diff -r 45df56448b2a -r d7e06542304c Applications/Generic/NativeStoneApplicationContext.h --- 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 widget); Deprecated::IViewport& GetCentralViewport() { @@ -67,14 +67,9 @@ { that_.updateDelayInMs_ = delayInMs; } - - MessageBroker& GetMessageBroker() - { - return that_.GetMessageBroker(); - } }; - NativeStoneApplicationContext(MessageBroker& broker); + NativeStoneApplicationContext(); void Start(); diff -r 45df56448b2a -r d7e06542304c Applications/Generic/NativeStoneApplicationRunner.cpp --- 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 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) { diff -r 45df56448b2a -r d7e06542304c Applications/Generic/NativeStoneApplicationRunner.h --- 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 application_; + public: - - NativeStoneApplicationRunner(MessageBroker& broker, - IStoneApplication& application) - : broker_(broker), - application_(application) + NativeStoneApplicationRunner(boost::shared_ptr application) + : application_(application) { } int Execute(int argc, diff -r 45df56448b2a -r d7e06542304c Applications/IStoneApplication.h --- 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 widget) = 0; + + virtual boost::shared_ptr GetCentralWidget() = 0; + virtual void Finalize() = 0; }; } diff -r 45df56448b2a -r d7e06542304c Applications/Samples/SampleApplicationBase.h --- 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 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 widget) ORTHANC_OVERRIDE + { + mainWidget_ = widget; + } + + virtual boost::shared_ptr 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 diff -r 45df56448b2a -r d7e06542304c Applications/Samples/SampleMainNative.cpp --- 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 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 } diff -r 45df56448b2a -r d7e06542304c Applications/Samples/SimpleViewerApplicationSingleFile.h --- 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 { 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_; Deprecated::LayoutWidget* mainLayout_; Deprecated::LayoutWidget* thumbnailsLayout_; - std::vector thumbnails_; + std::vector > thumbnails_; std::map > instancesIdsPerSeriesId_; std::map 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 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 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 - (*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 - (*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(mainWidget_); + Deprecated::SliceViewerWidget& widget = dynamic_cast(*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 thumbnailWidget(new Deprecated::SliceViewerWidget("thumbnail-series-" + seriesId)); thumbnails_.push_back(thumbnailWidget); thumbnailsLayout_->AddWidget(thumbnailWidget); - thumbnailWidget->RegisterObserverCallback(new Callable(*this, &SimpleViewerApplication::OnWidgetGeometryChanged)); + Register(*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 - (*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(mainWidget_); + Deprecated::SliceViewerWidget& widget = dynamic_cast(*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 diff -r 45df56448b2a -r d7e06542304c Applications/Samples/SingleFrameApplication.h --- 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 { private: class Interactor : public Deprecated::IWorldSceneInteractor @@ -127,7 +127,7 @@ void OffsetSlice(int offset) { - if (source_ != NULL) + if (source_) { int slice = static_cast(slice_) + offset; @@ -149,21 +149,15 @@ } - Deprecated::SliceViewerWidget& GetMainWidget() - { - return *dynamic_cast(mainWidget_); - } - - void SetSlice(size_t index) { - if (source_ != NULL && + if (source_ && index < source_->GetSlicesCount()) { slice_ = static_cast(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(); @@ -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 widget_; std::auto_ptr mainWidgetInteractor_; - const Deprecated::DicomSeriesVolumeSlicer* source_; + boost::shared_ptr 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(); int frame = parameters["frame"].as(); - mainWidget_ = new Deprecated::SliceViewerWidget(GetBroker(), "main-widget"); + widget_.reset(new Deprecated::SliceViewerWidget("main-widget")); + SetCentralWidget(widget_); - std::auto_ptr layer(new Deprecated::DicomSeriesVolumeSlicer(GetBroker(), context->GetOrthancApiClient())); - source_ = layer.get(); + boost::shared_ptr layer(new Deprecated::DicomSeriesVolumeSlicer); + layer->Connect(context->GetOrthancApiClient()); + source_ = layer; layer->LoadFrame(instance, frame); - layer->RegisterObserverCallback(new Callable(*this, &SingleFrameApplication::OnMainWidgetGeometryReady)); - GetMainWidget().AddLayer(layer.release()); + Register(*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_); } }; diff -r 45df56448b2a -r d7e06542304c Applications/Samples/SingleFrameEditorApplication.h --- 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 @@ -56,7 +56,7 @@ { class RadiographyEditorInteractor : public Deprecated::IWorldSceneInteractor, - public IObserver + public ObserverBase { 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 scene(new RadiographyScene(GetBroker())); + boost::shared_ptr 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 widget(new RadiographyWidget(scene_, "main-widget")); + widget->SetTransmitMouseOver(true); + widget->SetInteractor(interactor_); + SetCentralWidget(widget); //scene_->SetWindowing(128, 256); } diff -r 45df56448b2a -r d7e06542304c Applications/Sdl/SdlEngine.cpp --- 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), diff -r 45df56448b2a -r d7e06542304c Applications/Sdl/SdlEngine.h --- 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 { private: SdlWindow& window_; @@ -46,8 +47,7 @@ public: SdlEngine(SdlWindow& window, - NativeStoneApplicationContext& context, - MessageBroker& broker); + NativeStoneApplicationContext& context); void OnViewportChanged(const Deprecated::IViewport::ViewportChangedMessage& message) { diff -r 45df56448b2a -r d7e06542304c Applications/Sdl/SdlStoneApplicationRunner.cpp --- 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 sdl(new SdlEngine(window, context)); { NativeStoneApplicationContext::GlobalMutexLocker locker(context); - locker.GetCentralViewport().RegisterObserverCallback( - new Callable - (sdl, &SdlEngine::OnViewportChanged)); + sdl->Register + (locker.GetCentralViewport(), &SdlEngine::OnViewportChanged); //context.GetCentralViewport().Register(sdl); // (*) } context.Start(); - sdl.Run(); + sdl->Run(); LOG(WARNING) << "Stopping the application"; diff -r 45df56448b2a -r d7e06542304c Applications/Sdl/SdlStoneApplicationRunner.h --- 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 application) : + NativeStoneApplicationRunner(application) { } diff -r 45df56448b2a -r d7e06542304c Applications/StoneApplicationContext.cpp --- 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 StoneApplicationContext::GetWebService() { if (webService_ == NULL) { throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); } - return *webService_; + return webService_; } - Deprecated::OrthancApiClient& StoneApplicationContext::GetOrthancApiClient() + boost::shared_ptr 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 webService) { - webService_ = &webService; + webService_ = webService; InitializeOrthanc(); } diff -r 45df56448b2a -r d7e06542304c Applications/StoneApplicationContext.h --- 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 orthanc_; + boost::shared_ptr webService_; + Deprecated::IDelayedCallExecutor* delayedCallExecutor_; // TODO => shared_ptr ?? + boost::shared_ptr 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 GetWebService(); - bool HasWebService() const - { - return webService_ != NULL; - } + boost::shared_ptr GetOrthancApiClient(); - Deprecated::IWebService& GetWebService(); - - Deprecated::OrthancApiClient& GetOrthancApiClient(); - - void SetWebService(Deprecated::IWebService& webService); + void SetWebService(boost::shared_ptr webService); void SetOrthancBaseUrl(const std::string& baseUrl); diff -r 45df56448b2a -r d7e06542304c Framework/Deprecated/Layers/DicomSeriesVolumeSlicer.cpp --- 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 - (*this, &DicomSeriesVolumeSlicer::OnSliceGeometryReady)); - - loader_.RegisterObserverCallback( - new OrthancStone::Callable - (*this, &DicomSeriesVolumeSlicer::OnSliceGeometryError)); + } - loader_.RegisterObserverCallback( - new OrthancStone::Callable - (*this, &DicomSeriesVolumeSlicer::OnSliceImageReady)); - - loader_.RegisterObserverCallback( - new OrthancStone::Callable - (*this, &DicomSeriesVolumeSlicer::OnSliceImageError)); + void DicomSeriesVolumeSlicer::Connect(boost::shared_ptr orthanc) + { + loader_.reset(new OrthancSlicesLoader(orthanc)); + Register(*loader_, &DicomSeriesVolumeSlicer::OnSliceGeometryReady); + Register(*loader_, &DicomSeriesVolumeSlicer::OnSliceGeometryError); + Register(*loader_, &DicomSeriesVolumeSlicer::OnSliceImageReady); + Register(*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& 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_); } } } diff -r 45df56448b2a -r d7e06542304c Framework/Deprecated/Layers/DicomSeriesVolumeSlicer.h --- 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 //private OrthancSlicesLoader::ISliceLoaderObserver { public: @@ -79,13 +80,14 @@ private: class RendererFactory; - OrthancSlicesLoader loader_; + boost::shared_ptr loader_; SliceImageQuality quality_; public: - DicomSeriesVolumeSlicer(OrthancStone::MessageBroker& broker, - OrthancApiClient& orthanc); + DicomSeriesVolumeSlicer(); + void Connect(boost::shared_ptr 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& points, diff -r 45df56448b2a -r d7e06542304c Framework/Deprecated/Layers/DicomStructureSetSlicer.cpp --- 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 - (*this, &DicomStructureSetSlicer::OnStructureSetLoaded)); + Register(loader_, &DicomStructureSetSlicer::OnStructureSetLoaded); } diff -r 45df56448b2a -r d7e06542304c Framework/Deprecated/Layers/DicomStructureSetSlicer.h --- 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 { private: class Renderer; @@ -42,8 +42,7 @@ } public: - DicomStructureSetSlicer(OrthancStone::MessageBroker& broker, - StructureSetLoader& loader); + DicomStructureSetSlicer(StructureSetLoader& loader); virtual bool GetExtent(std::vector& points, const OrthancStone::CoordinateSystem3D& viewportPlane) diff -r 45df56448b2a -r d7e06542304c Framework/Deprecated/Layers/IVolumeSlicer.h --- 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() { } diff -r 45df56448b2a -r d7e06542304c Framework/Deprecated/SmartLoader.cpp --- 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) : 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 layerSource; + boost::shared_ptr layerSource; std::string sliceKeyId = instanceId + ":" + boost::lexical_cast(frame); SmartLoader::CachedSlice* cachedSlice = NULL; @@ -151,22 +142,23 @@ } else { - layerSource.reset(new DicomSeriesVolumeSlicer(IObserver::GetBroker(), orthancApiClient_)); + layerSource.reset(new DicomSeriesVolumeSlicer); + dynamic_cast(layerSource.get())->Connect(orthancApiClient_); dynamic_cast(layerSource.get())->SetImageQuality(imageQuality_); - layerSource->RegisterObserverCallback(new OrthancStone::Callable(*this, &SmartLoader::OnLayerGeometryReady)); - layerSource->RegisterObserverCallback(new OrthancStone::Callable(*this, &SmartLoader::OnFrameReady)); - layerSource->RegisterObserverCallback(new OrthancStone::Callable(*this, &SmartLoader::OnLayerReady)); + Register(*layerSource, &SmartLoader::OnLayerGeometryReady); + Register(*layerSource, &SmartLoader::OnFrameReady); + Register(*layerSource, &SmartLoader::OnLayerReady); dynamic_cast(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(new CachedSlice(IObserver::GetBroker())); + boost::shared_ptr cachedSlice(new CachedSlice); cachedSlice->slice_.reset(new Slice(instanceId, frame)); cachedSlice->status_ = CachedSliceStatus_ScheduledToLoad; std::string sliceKeyId = instanceId + ":" + boost::lexical_cast(frame); @@ -199,12 +191,12 @@ cachedSlices_[sliceKeyId] = boost::shared_ptr(cachedSlice); - std::auto_ptr layerSource(new DicomSeriesVolumeSlicer(IObserver::GetBroker(), orthancApiClient_)); - + std::auto_ptr layerSource(new DicomSeriesVolumeSlicer); + dynamic_cast(layerSource.get())->Connect(orthancApiClient_); dynamic_cast(layerSource.get())->SetImageQuality(imageQuality_); - layerSource->RegisterObserverCallback(new OrthancStone::Callable(*this, &SmartLoader::OnLayerGeometryReady)); - layerSource->RegisterObserverCallback(new OrthancStone::Callable(*this, &SmartLoader::OnFrameReady)); - layerSource->RegisterObserverCallback(new OrthancStone::Callable(*this, &SmartLoader::OnLayerReady)); + Register(*layerSource, &SmartLoader::OnLayerGeometryReady); + Register(*layerSource, &SmartLoader::OnFrameReady); + Register(*layerSource, &SmartLoader::OnLayerReady); dynamic_cast(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(new CachedSlice(IObserver::GetBroker())); + boost::shared_ptr 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(new CachedSlice(IObserver::GetBroker())); + boost::shared_ptr cachedSlice(new CachedSlice); cachedSlice->image_.reset(Orthanc::Image::Clone(message.GetFrame())); cachedSlice->effectiveQuality_ = message.GetImageQuality(); cachedSlice->slice_.reset(message.GetSlice().Clone()); diff -r 45df56448b2a -r d7e06542304c Framework/Deprecated/SmartLoader.h --- 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 { class CachedSlice; @@ -42,10 +42,10 @@ PreloadingInstances preloadingInstances_; SliceImageQuality imageQuality_; - OrthancApiClient& orthancApiClient_; + boost::shared_ptr orthancApiClient_; public: - SmartLoader(OrthancStone::MessageBroker& broker, OrthancApiClient& orthancApiClient); // TODO: add maxPreloadStorageSizeInBytes + SmartLoader(boost::shared_ptr orthancApiClient); // TODO: add maxPreloadStorageSizeInBytes // void PreloadStudy(const std::string studyId); // void PreloadSeries(const std::string seriesId); diff -r 45df56448b2a -r d7e06542304c Framework/Deprecated/Toolbox/BaseWebService.cpp --- 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 - (*this, &BaseWebService::CacheAndNotifyHttpSuccess), + (GetSharedObserver(), &BaseWebService::CacheAndNotifyHttpSuccess), new OrthancStone::Callable - (*this, &BaseWebService::NotifyHttpError), + (GetSharedObserver(), &BaseWebService::NotifyHttpError), timeoutInSeconds); } else diff -r 45df56448b2a -r d7e06542304c Framework/Deprecated/Toolbox/BaseWebService.h --- 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 #include @@ -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 { public: class CachedHttpRequestSuccessMessage @@ -90,10 +91,7 @@ std::deque orderedCacheKeys_; public: - - BaseWebService(OrthancStone::MessageBroker& broker) : - IWebService(broker), - IObserver(broker), + BaseWebService() : cacheEnabled_(false), cacheCurrentSize_(0), cacheMaxSize_(100*1024*1024) diff -r 45df56448b2a -r d7e06542304c Framework/Deprecated/Toolbox/IDelayedCallExecutor.h --- 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* callback, unsigned int timeoutInMs = 1000) = 0; diff -r 45df56448b2a -r d7e06542304c Framework/Deprecated/Toolbox/IWebService.h --- 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 HttpHeaders; @@ -138,12 +135,6 @@ }; - IWebService(OrthancStone::MessageBroker& broker) : - broker_(broker) - { - } - - virtual ~IWebService() { } diff -r 45df56448b2a -r d7e06542304c Framework/Deprecated/Toolbox/OrthancApiClient.cpp --- 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 > binaryHandler_; std::auto_ptr< OrthancStone::MessageHandler > 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* handler, + WebServicePayload(OrthancStone::MessageHandler* handler, OrthancStone::MessageHandler* 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* handler, + WebServicePayload(OrthancStone::MessageHandler* handler, OrthancStone::MessageHandler* 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* handler, + WebServicePayload(OrthancStone::MessageHandler* handler, OrthancStone::MessageHandler* 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 - (*this, &OrthancApiClient::NotifyHttpSuccess), + (GetSharedObserver(), &OrthancApiClient::NotifyHttpSuccess), new OrthancStone::Callable - (*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 - (*this, &OrthancApiClient::NotifyHttpSuccess), + (GetSharedObserver(), &OrthancApiClient::NotifyHttpSuccess), new OrthancStone::Callable - (*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 - (*this, &OrthancApiClient::NotifyHttpSuccess), + (GetSharedObserver(), &OrthancApiClient::NotifyHttpSuccess), new OrthancStone::Callable - (*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 - (*this, &OrthancApiClient::NotifyHttpSuccess), + (GetSharedObserver(), &OrthancApiClient::NotifyHttpSuccess), new OrthancStone::Callable - (*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 - (*this, &OrthancApiClient::NotifyHttpSuccess), + (GetSharedObserver(), &OrthancApiClient::NotifyHttpSuccess), new OrthancStone::Callable - (*this, &OrthancApiClient::NotifyHttpError)); + (GetSharedObserver(), &OrthancApiClient::NotifyHttpError)); } diff -r 45df56448b2a -r d7e06542304c Framework/Deprecated/Toolbox/OrthancApiClient.h --- 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 #include "IWebService.h" -#include "../../Messages/IObservable.h" +#include "../../Messages/ObserverBase.h" namespace Deprecated { class OrthancApiClient : public OrthancStone::IObservable, - public OrthancStone::IObserver + public OrthancStone::ObserverBase { 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() diff -r 45df56448b2a -r d7e06542304c Framework/Deprecated/Toolbox/OrthancSlicesLoader.cpp --- 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 orthanc) : orthanc_(orthanc), state_(State_Initialization) { @@ -658,10 +655,10 @@ else { state_ = State_LoadingGeometry; - orthanc_.GetJsonAsync("/series/" + seriesId + "/instances-tags", - new OrthancStone::Callable(*this, &OrthancSlicesLoader::ParseSeriesGeometry), - new OrthancStone::Callable(*this, &OrthancSlicesLoader::OnGeometryError), - NULL); + orthanc_->GetJsonAsync("/series/" + seriesId + "/instances-tags", + new OrthancStone::Callable(GetSharedObserver(), &OrthancSlicesLoader::ParseSeriesGeometry), + new OrthancStone::Callable(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(*this, &OrthancSlicesLoader::ParseInstanceGeometry), - new OrthancStone::Callable(*this, &OrthancSlicesLoader::OnGeometryError), - Operation::DownloadInstanceGeometry(instanceId)); + orthanc_->GetJsonAsync("/instances/" + instanceId + "/tags?ignore-length=3004-000c", + new OrthancStone::Callable(GetSharedObserver(), &OrthancSlicesLoader::ParseInstanceGeometry), + new OrthancStone::Callable(GetSharedObserver(), &OrthancSlicesLoader::OnGeometryError), + Operation::DownloadInstanceGeometry(instanceId)); } } @@ -696,10 +693,10 @@ { state_ = State_LoadingGeometry; - orthanc_.GetJsonAsync("/instances/" + instanceId + "/tags", - new OrthancStone::Callable(*this, &OrthancSlicesLoader::ParseFrameGeometry), - new OrthancStone::Callable(*this, &OrthancSlicesLoader::OnGeometryError), - Operation::DownloadFrameGeometry(instanceId, frame)); + orthanc_->GetJsonAsync("/instances/" + instanceId + "/tags", + new OrthancStone::Callable(GetSharedObserver(), &OrthancSlicesLoader::ParseFrameGeometry), + new OrthancStone::Callable(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 - (*this, &OrthancSlicesLoader::ParseSliceImagePng), - new OrthancStone::Callable - (*this, &OrthancSlicesLoader::OnSliceImageError), - Operation::DownloadSliceImage( - static_cast(index), slice, SliceImageQuality_FullPng)); -} + orthanc_->GetBinaryAsync(uri, "image/png", + new OrthancStone::Callable + (GetSharedObserver(), &OrthancSlicesLoader::ParseSliceImagePng), + new OrthancStone::Callable + (GetSharedObserver(), &OrthancSlicesLoader::OnSliceImageError), + Operation::DownloadSliceImage( + static_cast(index), slice, SliceImageQuality_FullPng)); + } void OrthancSlicesLoader::ScheduleSliceImagePam(const Slice& slice, size_t index) { std::string uri = ("/instances/" + slice.GetOrthancInstanceId() + "/frames/" + - boost::lexical_cast(slice.GetFrame())); + boost::lexical_cast(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 - (*this, &OrthancSlicesLoader::ParseSliceImagePam), - new OrthancStone::Callable - (*this, &OrthancSlicesLoader::OnSliceImageError), - Operation::DownloadSliceImage(static_cast(index), - slice, SliceImageQuality_FullPam)); + orthanc_->GetBinaryAsync(uri, "image/x-portable-arbitrarymap", + new OrthancStone::Callable + (GetSharedObserver(), &OrthancSlicesLoader::ParseSliceImagePam), + new OrthancStone::Callable + (GetSharedObserver(), &OrthancSlicesLoader::OnSliceImageError), + Operation::DownloadSliceImage(static_cast(index), + slice, SliceImageQuality_FullPam)); } @@ -849,15 +846,15 @@ "-" + slice.GetOrthancInstanceId() + "_" + boost::lexical_cast(slice.GetFrame())); - orthanc_.GetJsonAsync(uri, - new OrthancStone::Callable - (*this, &OrthancSlicesLoader::ParseSliceImageJpeg), - new OrthancStone::Callable - (*this, &OrthancSlicesLoader::OnSliceImageError), - Operation::DownloadSliceImage( - static_cast(index), slice, quality)); + orthanc_->GetJsonAsync(uri, + new OrthancStone::Callable + (GetSharedObserver(), &OrthancSlicesLoader::ParseSliceImageJpeg), + new OrthancStone::Callable + (GetSharedObserver(), &OrthancSlicesLoader::OnSliceImageError), + Operation::DownloadSliceImage( + static_cast(index), slice, quality)); } @@ -890,15 +887,15 @@ { std::string uri = ("/instances/" + slice.GetOrthancInstanceId() + "/frames/" + boost::lexical_cast(slice.GetFrame()) + "/raw.gz"); - orthanc_.GetBinaryAsync(uri, IWebService::HttpHeaders(), - new OrthancStone::Callable - (*this, &OrthancSlicesLoader::ParseSliceRawImage), - new OrthancStone::Callable - (*this, &OrthancSlicesLoader::OnSliceImageError), - Operation::DownloadSliceRawImage( - static_cast(index), slice)); + orthanc_->GetBinaryAsync(uri, IWebService::HttpHeaders(), + new OrthancStone::Callable + (GetSharedObserver(), &OrthancSlicesLoader::ParseSliceRawImage), + new OrthancStone::Callable + (GetSharedObserver(), &OrthancSlicesLoader::OnSliceImageError), + Operation::DownloadSliceRawImage( + static_cast(index), slice)); } } } diff -r 45df56448b2a -r d7e06542304c Framework/Deprecated/Toolbox/OrthancSlicesLoader.h --- 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 { public: ORTHANC_STONE_DEFINE_ORIGIN_MESSAGE(__FILE__, __LINE__, SliceGeometryReadyMessage, OrthancSlicesLoader); @@ -143,7 +146,7 @@ class Operation; - OrthancApiClient& orthanc_; + boost::shared_ptr 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 orthancApi); void ScheduleLoadSeries(const std::string& seriesId); diff -r 45df56448b2a -r d7e06542304c Framework/Deprecated/Viewport/IViewport.h --- 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; diff -r 45df56448b2a -r d7e06542304c Framework/Deprecated/Viewport/WidgetViewport.cpp --- 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 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; } diff -r 45df56448b2a -r d7e06542304c Framework/Deprecated/Viewport/WidgetViewport.h --- 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 centralWidget_; + boost::shared_ptr centralWidget_; IStatusBar* statusBar_; std::auto_ptr 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 widget); virtual void NotifyBackgroundChanged(); diff -r 45df56448b2a -r d7e06542304c Framework/Deprecated/Volumes/ISlicedVolume.h --- 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; diff -r 45df56448b2a -r d7e06542304c Framework/Deprecated/Volumes/IVolumeLoader.h --- 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) - { - } }; } diff -r 45df56448b2a -r d7e06542304c Framework/Deprecated/Volumes/StructureSetLoader.cpp --- 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(*this, &StructureSetLoader::OnLookupCompleted)); + new OrthancStone::Callable(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(*this, &StructureSetLoader::OnReferencedSliceLoaded)); + new OrthancStone::Callable(GetSharedObserver(), &StructureSetLoader::OnReferencedSliceLoaded)); } @@ -97,7 +94,7 @@ else { orthanc_.GetJsonAsync("/instances/" + instance + "/tags?ignore-length=3006-0050", - new OrthancStone::Callable(*this, &StructureSetLoader::OnStructureSetLoaded)); + new OrthancStone::Callable(GetSharedObserver(), &StructureSetLoader::OnStructureSetLoaded)); } } diff -r 45df56448b2a -r d7e06542304c Framework/Deprecated/Volumes/StructureSetLoader.h --- 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 { 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); diff -r 45df56448b2a -r d7e06542304c Framework/Deprecated/Widgets/LayoutWidget.cpp --- 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 widget_; + boost::shared_ptr widget_; int left_; int top_; unsigned int width_; unsigned int height_; public: - ChildWidget(IWidget* widget) : + ChildWidget(boost::shared_ptr widget) : widget_(widget) { assert(widget != NULL); @@ -354,7 +354,7 @@ } - IWidget& LayoutWidget::AddWidget(IWidget* widget) // Takes ownership + void LayoutWidget::AddWidget(boost::shared_ptr widget) // Takes ownership { if (widget == NULL) { @@ -375,8 +375,6 @@ { hasAnimation_ = true; } - - return *widget; } diff -r 45df56448b2a -r d7e06542304c Framework/Deprecated/Widgets/LayoutWidget.h --- 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 widget); virtual void SetStatusBar(IStatusBar& statusBar); diff -r 45df56448b2a -r d7e06542304c Framework/Deprecated/Widgets/SliceViewerWidget.cpp --- 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 - (*this, &SliceViewerWidget::OnGeometryReady)); - // currently ignore errors layer->RegisterObserverCallback(new Callable(*this, &SliceViewerWidget::...)); - layer.RegisterObserverCallback(new OrthancStone::Callable - (*this, &SliceViewerWidget::OnSliceChanged)); - layer.RegisterObserverCallback(new OrthancStone::Callable - (*this, &SliceViewerWidget::OnContentChanged)); - layer.RegisterObserverCallback(new OrthancStone::Callable - (*this, &SliceViewerWidget::OnLayerReady)); - layer.RegisterObserverCallback(new OrthancStone::Callable - (*this, &SliceViewerWidget::OnLayerError)); + // currently ignoring errors of type IVolumeSlicer::GeometryErrorMessage + + Register(layer, &SliceViewerWidget::OnGeometryReady); + Register(layer, &SliceViewerWidget::OnSliceChanged); + Register(layer, &SliceViewerWidget::OnContentChanged); + Register(layer, &SliceViewerWidget::OnLayerReady); + Register(layer, &SliceViewerWidget::OnLayerError); } - size_t SliceViewerWidget::AddLayer(IVolumeSlicer* layer) // Takes ownership + size_t SliceViewerWidget::AddLayer(boost::shared_ptr 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 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(); diff -r 45df56448b2a -r d7e06542304c Framework/Deprecated/Widgets/SliceViewerWidget.h --- 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 @@ -32,7 +32,7 @@ { class SliceViewerWidget : public WorldSceneWidget, - public OrthancStone::IObserver, + public OrthancStone::ObserverBase, public OrthancStone::IObservable { public: @@ -72,7 +72,7 @@ bool started_; LayersIndex layersIndex_; - std::vector layers_; + std::vector > layers_; std::vector styles_; OrthancStone::CoordinateSystem3D plane_; std::auto_ptr 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 layer); - void ReplaceLayer(size_t layerIndex, IVolumeSlicer* layer); // Takes ownership + void ReplaceLayer(size_t layerIndex, boost::shared_ptr layer); // Takes ownership void RemoveLayer(size_t layerIndex); diff -r 45df56448b2a -r d7e06542304c Framework/Loaders/DicomStructureSetLoader.cpp --- 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), diff -r 45df56448b2a -r d7e06542304c Framework/Loaders/LoaderCache.cpp --- 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 diff -r 45df56448b2a -r d7e06542304c Framework/Loaders/LoaderCache.h --- 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 @@ -87,7 +90,7 @@ WebAssemblyOracle& oracle_; #else ThreadedOracle& oracle_; - LockingEmitter& lockingEmitter_; + Deprecated::LockingEmitter& lockingEmitter_; #endif std::map > diff -r 45df56448b2a -r d7e06542304c Framework/Loaders/LoaderStateMachine.cpp --- 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 observer(GetSharedObserver()); + oracle_.Schedule(observer, nextCommand); pendingCommands_.pop_front(); activeCommands_++; @@ -136,7 +137,6 @@ template 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 - (*this, &LoaderStateMachine::HandleSuccessMessage)); - - oracleObservable.RegisterObserverCallback( - new Callable - (*this, &LoaderStateMachine::HandleSuccessMessage)); - - oracleObservable.RegisterObserverCallback( - new Callable - (*this, &LoaderStateMachine::HandleSuccessMessage)); - - oracleObservable.RegisterObserverCallback( - new Callable - (*this, &LoaderStateMachine::HandleExceptionMessage)); + // TODO => Move this out of constructor + Register(oracleObservable, &LoaderStateMachine::HandleSuccessMessage); + Register(oracleObservable, &LoaderStateMachine::HandleSuccessMessage); + Register(oracleObservable, &LoaderStateMachine::HandleSuccessMessage); + Register(oracleObservable, &LoaderStateMachine::HandleExceptionMessage); } LoaderStateMachine::~LoaderStateMachine() { - oracleObservable_.Unregister(this); LOG(TRACE) << "LoaderStateMachine(" << std::hex << this << std::dec << ")::~LoaderStateMachine()"; Clear(); } diff -r 45df56448b2a -r d7e06542304c Framework/Loaders/LoaderStateMachine.h --- 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 { protected: class State : public Orthanc::IDynamicObject @@ -95,7 +95,6 @@ typedef std::list PendingCommands; IOracle& oracle_; - IObservable& oracleObservable_; bool active_; unsigned int simultaneousDownloads_; PendingCommands pendingCommands_; diff -r 45df56448b2a -r d7e06542304c Framework/Loaders/OrthancMultiframeVolumeLoader.cpp --- 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) { diff -r 45df56448b2a -r d7e06542304c Framework/Loaders/OrthancSeriesVolumeProgressiveLoader.cpp --- 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(sliceIndex)); - oracle_.Schedule(*this, command.release()); + + boost::shared_ptr observer(GetSharedObserver()); + oracle_.Schedule(observer, command.release()); } else { @@ -421,32 +423,26 @@ OrthancSeriesVolumeProgressiveLoader::OrthancSeriesVolumeProgressiveLoader(const boost::shared_ptr& 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 - (*this, &OrthancSeriesVolumeProgressiveLoader::LoadGeometry)); + // TODO => Move this out of constructor + Register + (oracleObservable, &OrthancSeriesVolumeProgressiveLoader::LoadGeometry); - oracleObservable.RegisterObserverCallback( - new Callable - (*this, &OrthancSeriesVolumeProgressiveLoader::LoadBestQualitySliceContent)); + Register + (oracleObservable, &OrthancSeriesVolumeProgressiveLoader::LoadBestQualitySliceContent); - oracleObservable.RegisterObserverCallback( - new Callable - (*this, &OrthancSeriesVolumeProgressiveLoader::LoadJpegSliceContent)); + Register + (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 observer(GetSharedObserver()); + oracle_.Schedule(observer, command.release()); // LOG(TRACE) << "OrthancSeriesVolumeProgressiveLoader::LoadSeries called oracle_.Schedule"; } } diff -r 45df56448b2a -r d7e06542304c Framework/Loaders/OrthancSeriesVolumeProgressiveLoader.h --- 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, 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_; diff -r 45df56448b2a -r d7e06542304c Framework/Messages/ICallable.h --- 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 #include +#include #include -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 GetObserver() const = 0; }; + + // TODO - Remove this class template - class MessageHandler: public ICallable + class MessageHandler : public ICallable { }; @@ -61,47 +64,28 @@ class Callable : public MessageHandler { private: - typedef void (TObserver::* MemberFunction) (const TMessage&); + typedef void (TObserver::* MemberMethod) (const TMessage&); - TObserver& observer_; - MemberFunction function_; - std::string observerFingerprint_; + boost::weak_ptr observer_; + MemberMethod function_; public: - Callable(TObserver& observer, - MemberFunction function) : + Callable(boost::shared_ptr 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(message)); + boost::shared_ptr lock(observer_); + if (lock) + { + TObserver& observer = dynamic_cast(*lock); + const TMessage& typedMessage = dynamic_cast(message); + (observer.*function_) (typedMessage); + } } virtual const MessageIdentifier& GetMessageIdentifier() @@ -109,41 +93,9 @@ return TMessage::GetStaticIdentifier(); } - virtual IObserver* GetObserver() const + virtual boost::weak_ptr GetObserver() const { - return &observer_; + return observer_; } }; - -#if 0 /* __cplusplus >= 201103L*/ - -#include - - template - class LambdaCallable : public MessageHandler - { - private: - - IObserver& observer_; - std::function lambda_; - - public: - LambdaCallable(IObserver& observer, - std::function lambdaFunction) : - observer_(observer), - lambda_(lambdaFunction) - { - } - - virtual void Apply(const IMessage& message) - { - lambda_(dynamic_cast(message)); - } - - virtual IObserver* GetObserver() const - { - return &observer_; - } - }; -#endif //__cplusplus >= 201103L } diff -r 45df56448b2a -r d7e06542304c Framework/Messages/IMessage.h --- 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 #include #include @@ -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(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); + } }; diff -r 45df56448b2a -r d7e06542304c Framework/Messages/IMessageEmitter.h --- 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 + namespace OrthancStone { /** @@ -39,7 +41,7 @@ { } - virtual void EmitMessage(const IObserver& observer, + virtual void EmitMessage(boost::weak_ptr observer, const IMessage& message) = 0; }; } diff -r 45df56448b2a -r d7e06542304c Framework/Messages/IObservable.cpp --- 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 -#include #include @@ -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(*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::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 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 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 lock(observer.lock()); + if (lock) { - throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer); + EmitMessageInternal(lock.get(), message); } - - forwarders_.insert(forwarder); } } diff -r 45df56448b2a -r d7e06542304c Framework/Messages/IObservable.h --- 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 #include @@ -37,39 +35,20 @@ private: typedef std::map > Callables; - typedef std::set 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 observer, const IMessage& message); - - // Takes ownsership - void RegisterForwarder(IMessageForwarder* forwarder); }; } diff -r 45df56448b2a -r d7e06542304c Framework/Messages/IObserver.cpp --- 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 . - **/ - - -#include "IObserver.h" - -#include "IMessage.h" -#include "../StoneException.h" - -#include -#include - -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; - } -} diff -r 45df56448b2a -r d7e06542304c Framework/Messages/IObserver.h --- 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 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_; } }; } diff -r 45df56448b2a -r d7e06542304c Framework/Messages/LockingEmitter.cpp --- /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 . + **/ + +#include "LockingEmitter.h" + +#include + +namespace OrthancStone +{ + namespace Deprecated + { + void LockingEmitter::EmitMessage(boost::weak_ptr observer, + const IMessage& message) + { + try + { + boost::unique_lock lock(mutex_); + oracleObservable_.EmitMessage(observer, message); + } + catch (Orthanc::OrthancException& e) + { + LOG(ERROR) << "Exception while emitting a message: " << e.What(); + } + } + } +} diff -r 45df56448b2a -r d7e06542304c Framework/Messages/LockingEmitter.h --- 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 +#include // For ORTHANC_OVERRIDE + +#include 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 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 observer, + const IMessage& message) ORTHANC_OVERRIDE; - class ReaderLock : public boost::noncopyable - { - private: - LockingEmitter& that_; - boost::shared_lock lock_; + class ReaderLock : public boost::noncopyable + { + private: + LockingEmitter& that_; + boost::shared_lock 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 lock_; + class WriterLock : public boost::noncopyable + { + private: + LockingEmitter& that_; + boost::unique_lock 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_; + } + }; }; - }; + } } diff -r 45df56448b2a -r d7e06542304c Framework/Messages/MessageBroker.h --- 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 . - **/ - -#pragma once - -#include "boost/noncopyable.hpp" - -#include - -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 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(); - } - }; -} diff -r 45df56448b2a -r d7e06542304c Framework/Messages/MessageForwarder.cpp --- 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 . - **/ - - -#include "MessageForwarder.h" - -#include "IObservable.h" - -namespace OrthancStone -{ - - void IMessageForwarder::ForwardMessageInternal(const IMessage& message) - { - emitter_.BroadcastMessage(message); - } - - void IMessageForwarder::RegisterForwarderInEmitter() - { - emitter_.RegisterForwarder(this); - } -} diff -r 45df56448b2a -r d7e06542304c Framework/Messages/MessageForwarder.h --- 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 . - **/ - - -#pragma once - -#include "ICallable.h" -#include "IObserver.h" - -#include - -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(broker, *this) // where "this" is B - * - * in C: - * B.RegisterObserverCallback(new Callable(*this, &B::MyCallback)) // where "this" is C - */ - template - class MessageForwarder : public IMessageForwarder, public Callable, TMessage> - { - public: - MessageForwarder(MessageBroker& broker, - IObservable& emitter // the object that will emit the messages to forward - ) - : IMessageForwarder(broker, emitter), - Callable, TMessage>(*this, &MessageForwarder::ForwardMessage) - { - RegisterForwarderInEmitter(); - } - -protected: - void ForwardMessage(const TMessage& message) - { - ForwardMessageInternal(message); - } - - }; -} diff -r 45df56448b2a -r d7e06542304c Framework/Messages/ObserverBase.h --- /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 . + **/ + + +#pragma once + +#include "ICallable.h" +#include "IObserver.h" +#include "IObservable.h" + +#include + +#include + +namespace OrthancStone +{ + template + class ObserverBase : + public IObserver, + public boost::enable_shared_from_this + { + public: + boost::shared_ptr 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 + ICallable* CreateCallable(void (TObserver::* MemberMethod) (const TMessage&)) + { + return new Callable(GetSharedObserver(), MemberMethod); + } + + template + void Register(IObservable& observable, + void (TObserver::* MemberMethod) (const TMessage&)) + { + observable.RegisterCallable(CreateCallable(MemberMethod)); + } + }; +} diff -r 45df56448b2a -r d7e06542304c Framework/Oracle/CustomOracleCommand.h --- /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 . + **/ + + +#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; + }; +} diff -r 45df56448b2a -r d7e06542304c Framework/Oracle/GenericOracleRunner.cpp --- /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 . + **/ + + +#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 +#endif + +#include +#include +#include +#include +#include + +#include + + +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(static_cast(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(fileSize), command.IsPixelDataIncluded()); + } + else + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat, + "Cannot parse file: " + path); + } + } + + + static ParseDicomFileCommand::SuccessMessage* Execute(boost::shared_ptr 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 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(command)); + + case IOracleCommand::Type_OrthancRestApi: + return Execute(orthanc_, dynamic_cast(command)); + + case IOracleCommand::Type_GetOrthancImage: + return Execute(orthanc_, dynamic_cast(command)); + + case IOracleCommand::Type_GetOrthancWebViewerJpeg: + return Execute(orthanc_, dynamic_cast(command)); + + case IOracleCommand::Type_Custom: + return dynamic_cast(command).Execute(*this); + + case IOracleCommand::Type_ReadFile: + return Execute(rootDirectory_, dynamic_cast(command)); + + case IOracleCommand::Type_ParseDicomFile: +#if ORTHANC_ENABLE_DCMTK == 1 + return Execute(dicomCache_, rootDirectory_, + dynamic_cast(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); + } + } +} diff -r 45df56448b2a -r d7e06542304c Framework/Oracle/GenericOracleRunner.h --- /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 . + **/ + + +#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 // For ORTHANC_OVERRIDE +#include + +namespace OrthancStone +{ + class GenericOracleRunner : public IOracleRunner + { + private: + Orthanc::WebServiceParameters orthanc_; + std::string rootDirectory_; + +#if ORTHANC_ENABLE_DCMTK == 1 + boost::shared_ptr 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 cache) + { + dicomCache_ = cache; + } +#endif + + virtual IMessage* Run(IOracleCommand& command) ORTHANC_OVERRIDE; + }; +} diff -r 45df56448b2a -r d7e06542304c Framework/Oracle/GetOrthancImageCommand.cpp --- 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); } } diff -r 45df56448b2a -r d7e06542304c Framework/Oracle/GetOrthancImageCommand.h --- 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 @@ -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; }; } diff -r 45df56448b2a -r d7e06542304c Framework/Oracle/GetOrthancWebViewerJpegCommand.cpp --- 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(stretchLow) / scaling; Orthanc::ImageProcessing::ShiftScale(*image, offset, scaling, true); } - - SuccessMessage message(*this, image.release()); - emitter.EmitMessage(receiver, message); + + return new SuccessMessage(*this, image.release()); } } diff -r 45df56448b2a -r d7e06542304c Framework/Oracle/GetOrthancWebViewerJpegCommand.h --- 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 @@ -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; }; } diff -r 45df56448b2a -r d7e06542304c Framework/Oracle/HttpCommand.cpp --- 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); + } + } } diff -r 45df56448b2a -r d7e06542304c Framework/Oracle/HttpCommand.h --- 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; }; } diff -r 45df56448b2a -r d7e06542304c Framework/Oracle/IOracle.h --- 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 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 receiver, IOracleCommand* command) = 0; // Takes ownership }; } diff -r 45df56448b2a -r d7e06542304c Framework/Oracle/IOracleCommand.h --- 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() diff -r 45df56448b2a -r d7e06542304c Framework/Oracle/IOracleRunner.h --- /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 . + **/ + + +#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; + }; +} diff -r 45df56448b2a -r d7e06542304c Framework/Oracle/OrthancRestApiCommand.cpp --- 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) { } diff -r 45df56448b2a -r d7e06542304c Framework/Oracle/OrthancRestApiCommand.h --- 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_; + } }; } diff -r 45df56448b2a -r d7e06542304c Framework/Oracle/ParseDicomFileCommand.cpp --- /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 . + **/ + + +#include "ParseDicomFileCommand.h" + +#include + +#include + +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 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(); + } +} diff -r 45df56448b2a -r d7e06542304c Framework/Oracle/ParseDicomFileCommand.h --- /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 . + **/ + + +#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 + +#include + +namespace OrthancStone +{ + class ParseDicomFileCommand : public OracleCommandWithPayload + { + public: + class SuccessMessage : public OriginMessage + { + ORTHANC_STONE_MESSAGE(__FILE__, __LINE__); + + private: + boost::shared_ptr 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 dicom, + size_t fileSize, + bool hasPixelData); + + boost::shared_ptr 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; + } + }; +} diff -r 45df56448b2a -r d7e06542304c Framework/Oracle/ReadFileCommand.h --- /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 . + **/ + + +#pragma once + +#include "../Messages/IMessage.h" +#include "OracleCommandWithPayload.h" + +namespace OrthancStone +{ + class ReadFileCommand : public OracleCommandWithPayload + { + public: + class SuccessMessage : public OriginMessage + { + 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_; + } + }; +} diff -r 45df56448b2a -r d7e06542304c Framework/Oracle/ThreadedOracle.cpp --- 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 -#include +#include #include -#include - namespace OrthancStone { class ThreadedOracle::Item : public Orthanc::IDynamicObject { private: - const IObserver& receiver_; + boost::weak_ptr receiver_; std::auto_ptr command_; public: - Item(const IObserver& receiver, + Item(boost::weak_ptr receiver, IOracleCommand* command) : receiver_(receiver), command_(command) @@ -54,7 +46,7 @@ } } - const IObserver& GetReceiver() const + boost::weak_ptr GetReceiver() { return receiver_; } @@ -73,12 +65,12 @@ class Item { private: - const IObserver& receiver_; + boost::weak_ptr receiver_; std::auto_ptr command_; boost::posix_time::ptime expiration_; public: - Item(const IObserver& receiver, + Item(boost::weak_ptr receiver, SleepOracleCommand* command) : receiver_(receiver), command_(command) @@ -123,7 +115,7 @@ } } - void Add(const IObserver& receiver, + void Add(boost::weak_ptr 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 object(queue_.Dequeue(100)); @@ -316,60 +160,37 @@ { Item& item = dynamic_cast(*object); - try + if (item.GetCommand().GetType() == IOracleCommand::Type_Sleep) { - switch (item.GetCommand().GetType()) + SleepOracleCommand& command = dynamic_cast(item.GetCommand()); + + std::auto_ptr copy(new SleepOracleCommand(command.GetDelay())); + + if (command.HasPayload()) { - case IOracleCommand::Type_Sleep: - { - SleepOracleCommand& command = dynamic_cast(item.GetCommand()); - - std::auto_ptr 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(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(item.GetCommand())); - break; - - case IOracleCommand::Type_GetOrthancImage: - Execute(emitter_, orthanc_, item.GetReceiver(), - dynamic_cast(item.GetCommand())); - break; - - case IOracleCommand::Type_GetOrthancWebViewerJpeg: - Execute(emitter_, orthanc_, item.GetReceiver(), - dynamic_cast(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 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 receiver, IOracleCommand* command) { - queue_.Enqueue(new Item(receiver, command)); + std::auto_ptr 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; + } + } } } diff -r 45df56448b2a -r d7e06542304c Framework/Oracle/ThreadedOracle.h --- 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 #include @@ -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 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 receiver, + IOracleCommand* command) ORTHANC_OVERRIDE; }; } diff -r 45df56448b2a -r d7e06542304c Framework/Oracle/WebAssemblyOracle.cpp --- 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& receiver, IOracleCommand* command) { LOG(TRACE) << "WebAssemblyOracle::Schedule : receiver = " diff -r 45df56448b2a -r d7e06542304c Framework/Oracle/WebAssemblyOracle.h --- 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& receiver, + IOracleCommand* command) ORTHANC_OVERRIDE; }; } diff -r 45df56448b2a -r d7e06542304c Framework/Radiography/RadiographyAlphaLayer.h --- 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) { diff -r 45df56448b2a -r d7e06542304c Framework/Radiography/RadiographyDicomLayer.cpp --- 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) { } diff -r 45df56448b2a -r d7e06542304c Framework/Radiography/RadiographyDicomLayer.h --- 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) { diff -r 45df56448b2a -r d7e06542304c Framework/Radiography/RadiographyLayer.cpp --- 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), diff -r 45df56448b2a -r d7e06542304c Framework/Radiography/RadiographyLayer.h --- 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() { diff -r 45df56448b2a -r d7e06542304c Framework/Radiography/RadiographyMaskLayer.h --- 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 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) diff -r 45df56448b2a -r d7e06542304c Framework/Radiography/RadiographyScene.cpp --- 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(*this, &RadiographyScene::OnLayerEdited)); + Register(*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 alpha(new RadiographyTextLayer(IObservable::GetBroker(), *this)); + std::auto_ptr alpha(new RadiographyTextLayer(*this)); alpha->LoadText(font, utf8); if (geometry != NULL) { @@ -328,7 +326,7 @@ float foreground, RadiographyLayer::Geometry* geometry) { - std::auto_ptr mask(new RadiographyMaskLayer(IObservable::GetBroker(), *this, dicomLayer, foreground)); + std::auto_ptr 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 alpha(new RadiographyAlphaLayer(IObservable::GetBroker(), *this)); + std::auto_ptr alpha(new RadiographyAlphaLayer(*this)); alpha->SetAlpha(bitmap); if (geometry != NULL) { @@ -358,7 +356,7 @@ RadiographyPhotometricDisplayMode preferredPhotometricDisplayMode, RadiographyLayer::Geometry* geometry) { - RadiographyDicomLayer& layer = dynamic_cast(RegisterLayer(new RadiographyDicomLayer(IObservable::GetBroker(), *this))); + RadiographyDicomLayer& layer = dynamic_cast(RegisterLayer(new RadiographyDicomLayer(*this))); layer.SetInstance(instance, frame); @@ -380,7 +378,7 @@ bool httpCompression, RadiographyLayer::Geometry* geometry) { - RadiographyDicomLayer& layer = dynamic_cast(RegisterLayer(new RadiographyDicomLayer(IObservable::GetBroker(), *this))); + RadiographyDicomLayer& layer = dynamic_cast(RegisterLayer(new RadiographyDicomLayer( *this))); layer.SetInstance(instance, frame); if (geometry != NULL) @@ -395,7 +393,7 @@ orthanc.GetBinaryAsync( uri, headers, new Callable - (*this, &RadiographyScene::OnTagsReceived), NULL, + (GetSharedObserver(), &RadiographyScene::OnTagsReceived), NULL, new Orthanc::SingleValueObject(layer.GetIndex())); } @@ -414,7 +412,7 @@ orthanc.GetBinaryAsync( uri, headers, new Callable - (*this, &RadiographyScene::OnFrameReceived), NULL, + (GetSharedObserver(), &RadiographyScene::OnFrameReceived), NULL, new Orthanc::SingleValueObject(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 - (*this, &RadiographyScene::OnDicomExported), + (GetSharedObserver(), &RadiographyScene::OnDicomExported), NULL, NULL); } diff -r 45df56448b2a -r d7e06542304c Framework/Radiography/RadiographyScene.h --- 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, + public IObservable { public: class GeometryChangedMessage : public OriginMessage @@ -159,7 +160,7 @@ virtual void OnLayerEdited(const RadiographyLayer::LayerEditedMessage& message); public: - RadiographyScene(MessageBroker& broker); + RadiographyScene(); virtual ~RadiographyScene(); diff -r 45df56448b2a -r d7e06542304c Framework/Radiography/RadiographySceneReader.cpp --- 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(&(scene_.LoadDicomFrame(orthancApiClient_, instanceId, frame, false, geometry))); + return dynamic_cast(&(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(&(scene_.LoadDicomFrame(orthancApiClient_, jsonLayer["instanceId"].asString(), jsonLayer["frame"].asUInt(), false, &geometry))); + dicomLayer = dynamic_cast(&(scene_.LoadDicomFrame(*orthancApiClient_, jsonLayer["instanceId"].asString(), jsonLayer["frame"].asUInt(), false, &geometry))); } else if (jsonLayer["type"].asString() == "mask") { diff -r 45df56448b2a -r d7e06542304c Framework/Radiography/RadiographySceneReader.h --- 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 orthancApiClient_; public: - RadiographySceneReader(RadiographyScene& scene, Deprecated::OrthancApiClient& orthancApiClient) : + RadiographySceneReader(RadiographyScene& scene, + boost::shared_ptr orthancApiClient) : RadiographySceneBuilder(scene), orthancApiClient_(orthancApiClient) { diff -r 45df56448b2a -r d7e06542304c Framework/Radiography/RadiographyTextLayer.h --- 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) { } diff -r 45df56448b2a -r d7e06542304c Framework/Radiography/RadiographyWidget.cpp --- 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 scene, + RadiographyWidget::RadiographyWidget(boost::shared_ptr 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 scene) { - if (scene_ != NULL) - { - scene_->Unregister(this); - } - scene_ = scene; - scene_->RegisterObserverCallback( - new Callable - (*this, &RadiographyWidget::OnGeometryChanged)); - - scene_->RegisterObserverCallback( - new Callable - (*this, &RadiographyWidget::OnContentChanged)); + Register(*scene_, &RadiographyWidget::OnGeometryChanged); + Register(*scene_, &RadiographyWidget::OnContentChanged); NotifyContentChanged(); diff -r 45df56448b2a -r d7e06542304c Framework/Radiography/RadiographyWidget.h --- 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 { private: boost::shared_ptr scene_; @@ -60,8 +61,7 @@ bool IsInvertedInternal() const; public: - RadiographyWidget(MessageBroker& broker, - boost::shared_ptr 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 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 diff -r 45df56448b2a -r d7e06542304c Framework/Scene2DViewport/AngleMeasureTool.cpp --- 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 controllerW) - : MeasureTool(broker, controllerW) + boost::weak_ptr controllerW) + : MeasureTool(controllerW) #if ORTHANC_STONE_ENABLE_OUTLINED_TEXT == 1 , layerHolder_(boost::make_shared(controllerW,1,5)) #else @@ -189,8 +189,9 @@ boost::weak_ptr controllerW, const PointerEvent & e); */ + boost::shared_ptr editAngleMeasureTracker( - new EditAngleMeasureTracker(shared_from_this(), GetBroker(), GetController(), e)); + new EditAngleMeasureTracker(shared_from_this(), GetController(), e)); return editAngleMeasureTracker; } diff -r 45df56448b2a -r d7e06542304c Framework/Scene2DViewport/AngleMeasureTool.h --- 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 + class AngleMeasureTool : public MeasureTool { public: - AngleMeasureTool(MessageBroker& broker, boost::weak_ptr controllerW); + AngleMeasureTool(boost::weak_ptr controllerW); ~AngleMeasureTool(); diff -r 45df56448b2a -r d7e06542304c Framework/Scene2DViewport/CreateAngleMeasureCommand.cpp --- 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 controllerW, ScenePoint2D point) : CreateMeasureCommand(controllerW) , measureTool_( - boost::make_shared(boost::ref(broker), controllerW)) + boost::make_shared(controllerW)) { GetController()->AddMeasureTool(measureTool_); measureTool_->SetSide1End(point); diff -r 45df56448b2a -r d7e06542304c Framework/Scene2DViewport/CreateAngleMeasureCommand.h --- 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 controllerW, ScenePoint2D point); diff -r 45df56448b2a -r d7e06542304c Framework/Scene2DViewport/CreateAngleMeasureTracker.cpp --- 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 controllerW, const PointerEvent& e) : CreateMeasureTracker(controllerW) @@ -34,7 +33,6 @@ { command_.reset( new CreateAngleMeasureCommand( - broker, controllerW, e.GetMainPosition().Apply(GetScene().GetCanvasToSceneTransform()))); } diff -r 45df56448b2a -r d7e06542304c Framework/Scene2DViewport/CreateAngleMeasureTracker.h --- 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 controllerW, const PointerEvent& e); diff -r 45df56448b2a -r d7e06542304c Framework/Scene2DViewport/CreateLineMeasureCommand.cpp --- 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 controllerW, ScenePoint2D point) : CreateMeasureCommand(controllerW) , measureTool_( - boost::make_shared(boost::ref(broker), controllerW)) + boost::make_shared(controllerW)) { GetController()->AddMeasureTool(measureTool_); measureTool_->Set(point, point); diff -r 45df56448b2a -r d7e06542304c Framework/Scene2DViewport/CreateLineMeasureCommand.h --- 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 controllerW, ScenePoint2D point); diff -r 45df56448b2a -r d7e06542304c Framework/Scene2DViewport/CreateLineMeasureTracker.cpp --- 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 controllerW, const PointerEvent& e) : CreateMeasureTracker(controllerW) { command_.reset( new CreateLineMeasureCommand( - broker, controllerW, e.GetMainPosition().Apply(GetScene().GetCanvasToSceneTransform()))); } diff -r 45df56448b2a -r d7e06542304c Framework/Scene2DViewport/CreateLineMeasureTracker.h --- 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 controllerW, const PointerEvent& e); diff -r 45df56448b2a -r d7e06542304c Framework/Scene2DViewport/EditAngleMeasureCommand.cpp --- 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 measureTool, - MessageBroker& broker, + boost::shared_ptr measureTool, boost::weak_ptr controllerW) : EditMeasureCommand(measureTool, controllerW) , measureTool_(measureTool) @@ -33,21 +32,21 @@ void EditAngleMeasureCommand::SetCenter(ScenePoint2D scenePos) { - measureTool_->SetCenter(scenePos); + dynamic_cast(*measureTool_).SetCenter(scenePos); mementoModified_ = measureTool_->GetMemento(); } void EditAngleMeasureCommand::SetSide1End(ScenePoint2D scenePos) { - measureTool_->SetSide1End(scenePos); + dynamic_cast(*measureTool_).SetSide1End(scenePos); mementoModified_ = measureTool_->GetMemento(); } void EditAngleMeasureCommand::SetSide2End(ScenePoint2D scenePos) { - measureTool_->SetSide2End(scenePos); + dynamic_cast(*measureTool_).SetSide2End(scenePos); mementoModified_ = measureTool_->GetMemento(); } } diff -r 45df56448b2a -r d7e06542304c Framework/Scene2DViewport/EditAngleMeasureCommand.h --- 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 measureTool, - MessageBroker& broker, + boost::shared_ptr measureTool, boost::weak_ptr controllerW); /** This method sets center*/ @@ -46,6 +45,6 @@ { return measureTool_; } - boost::shared_ptr measureTool_; + boost::shared_ptr measureTool_; }; } diff -r 45df56448b2a -r d7e06542304c Framework/Scene2DViewport/EditAngleMeasureTracker.cpp --- 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 measureTool, - MessageBroker& broker, + boost::shared_ptr measureTool, boost::weak_ptr 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(*measureTool).AngleHitTest(scenePos); - command_.reset(new EditAngleMeasureCommand(measureTool, broker, controllerW)); + command_.reset(new EditAngleMeasureCommand(measureTool, controllerW)); } EditAngleMeasureTracker::~EditAngleMeasureTracker() diff -r 45df56448b2a -r d7e06542304c Framework/Scene2DViewport/EditAngleMeasureTracker.h --- 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 measureTool, - MessageBroker& broker, + boost::shared_ptr measureTool, boost::weak_ptr controllerW, const PointerEvent& e); diff -r 45df56448b2a -r d7e06542304c Framework/Scene2DViewport/EditLineMeasureCommand.cpp --- 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 measureTool, - MessageBroker& broker, + boost::shared_ptr measureTool, boost::weak_ptr controllerW) : EditMeasureCommand(measureTool, controllerW) , measureTool_(measureTool) @@ -34,14 +33,14 @@ void EditLineMeasureCommand::SetStart(ScenePoint2D scenePos) { - measureTool_->SetStart(scenePos); + dynamic_cast(*measureTool_).SetStart(scenePos); mementoModified_ = measureTool_->GetMemento(); } void EditLineMeasureCommand::SetEnd(ScenePoint2D scenePos) { - measureTool_->SetEnd(scenePos); + dynamic_cast(*measureTool_).SetEnd(scenePos); mementoModified_ = measureTool_->GetMemento(); } } diff -r 45df56448b2a -r d7e06542304c Framework/Scene2DViewport/EditLineMeasureCommand.h --- 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 measureTool, - MessageBroker& broker, + boost::shared_ptr measureTool, boost::weak_ptr controllerW); void SetStart(ScenePoint2D scenePos); @@ -39,7 +38,6 @@ { return measureTool_; } - boost::shared_ptr measureTool_; + boost::shared_ptr measureTool_; }; } - diff -r 45df56448b2a -r d7e06542304c Framework/Scene2DViewport/EditLineMeasureTracker.cpp --- 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 measureTool, - MessageBroker& broker, + boost::shared_ptr measureTool, boost::weak_ptr 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(*measureTool).LineHitTest(scenePos); - command_.reset( - new EditLineMeasureCommand( - measureTool, - broker, - controllerW)); + command_.reset(new EditLineMeasureCommand(measureTool, controllerW)); } EditLineMeasureTracker::~EditLineMeasureTracker() diff -r 45df56448b2a -r d7e06542304c Framework/Scene2DViewport/EditLineMeasureTracker.h --- 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 measureTool, - MessageBroker& broker, + boost::shared_ptr measureTool, boost::weak_ptr controllerW, const PointerEvent& e); diff -r 45df56448b2a -r d7e06542304c Framework/Scene2DViewport/LineMeasureTool.cpp --- 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 controllerW) - : MeasureTool(broker, controllerW) + boost::weak_ptr controllerW) + : MeasureTool(controllerW) #if ORTHANC_STONE_ENABLE_OUTLINED_TEXT == 1 , layerHolder_(boost::make_shared(controllerW, 1, 5)) #else @@ -148,7 +148,7 @@ const PointerEvent & e); */ boost::shared_ptr editLineMeasureTracker( - new EditLineMeasureTracker(shared_from_this(), GetBroker(), GetController(), e)); + new EditLineMeasureTracker(shared_from_this(), GetController(), e)); return editLineMeasureTracker; } diff -r 45df56448b2a -r d7e06542304c Framework/Scene2DViewport/LineMeasureTool.h --- 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 + class LineMeasureTool : public MeasureTool { public: - LineMeasureTool(MessageBroker& broker, boost::weak_ptr controllerW); + LineMeasureTool(boost::weak_ptr controllerW); ~LineMeasureTool(); diff -r 45df56448b2a -r d7e06542304c Framework/Scene2DViewport/MeasureTool.cpp --- 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 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 controllerW) - : IObserver(broker) - , controllerW_(controllerW) + : controllerW_(controllerW) , enabled_(true) { - GetController()->RegisterObserverCallback( - new Callable - (*this, &MeasureTool::OnSceneTransformChanged)); + // TODO => Move this out of constructor + Register(*GetController(), &MeasureTool::OnSceneTransformChanged); } diff -r 45df56448b2a -r d7e06542304c Framework/Scene2DViewport/MeasureTool.h --- 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 #include #include @@ -38,10 +38,12 @@ class IFlexiblePointerTracker; class MeasureToolMemento; - class MeasureTool : public IObserver + class MeasureTool : public ObserverBase { 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 controllerW); + MeasureTool(boost::weak_ptr controllerW); /** The measuring tool may exist in a standalone fashion, without any available diff -r 45df56448b2a -r d7e06542304c Framework/Scene2DViewport/ViewportController.cpp --- 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 undoStackW, - MessageBroker& broker, IViewport& viewport) - : IObservable(broker) - , undoStackW_(undoStackW) + : undoStackW_(undoStackW) , canvasToSceneFactor_(0.0) , viewport_(viewport) { diff -r 45df56448b2a -r d7e06542304c Framework/Scene2DViewport/ViewportController.h --- 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 undoStackW, - MessageBroker& broker, IViewport& viewport); diff -r 45df56448b2a -r d7e06542304c Framework/Toolbox/GenericToolbox.h --- 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) { diff -r 45df56448b2a -r d7e06542304c Framework/Toolbox/ParsedDicomFileCache.cpp --- /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 . + **/ + + +#include "ParsedDicomFileCache.h" + +namespace OrthancStone +{ + class ParsedDicomFileCache::Item : public Orthanc::ICacheable + { + private: + boost::mutex mutex_; + boost::shared_ptr dicom_; + size_t fileSize_; + bool hasPixelData_; + + public: + Item(boost::shared_ptr 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 GetDicom() const + { + assert(dicom_.get() != NULL); + return dicom_; + } + + bool HasPixelData() const + { + return hasPixelData_; + } + }; + + + void ParsedDicomFileCache::Acquire(const std::string& path, + boost::shared_ptr 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(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 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(); + } + } +} diff -r 45df56448b2a -r d7e06542304c Framework/Toolbox/ParsedDicomFileCache.h --- /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 . + **/ + + +#pragma once + +#include +#include + +#include + +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 dicom, + size_t fileSize, + bool hasPixelData); + + class Reader : public boost::noncopyable + { + private: + Orthanc::MemoryObjectCache::Reader reader_; + std::auto_ptr lock_; + Item* item_; + + public: + Reader(ParsedDicomFileCache& cache, + const std::string& path); + + bool IsValid() const + { + return item_ != NULL; + } + + bool HasPixelData() const; + + boost::shared_ptr GetDicom() const; + + size_t GetFileSize() const; + }; + }; +} diff -r 45df56448b2a -r d7e06542304c Platforms/Generic/DelayedCallCommand.cpp --- 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* callback, // takes ownership + DelayedCallCommand::DelayedCallCommand(OrthancStone::MessageHandler* callback, // takes ownership unsigned int timeoutInMs, Orthanc::IDynamicObject* payload /* takes ownership */, OrthancStone::NativeStoneApplicationContext& context ) : - IObservable(broker), callback_(callback), payload_(payload), context_(context), diff -r 45df56448b2a -r d7e06542304c Platforms/Generic/DelayedCallCommand.h --- 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* callback, // takes ownership + DelayedCallCommand(OrthancStone::MessageHandler* callback, // takes ownership unsigned int timeoutInMs, Orthanc::IDynamicObject* payload /* takes ownership */, OrthancStone::NativeStoneApplicationContext& context diff -r 45df56448b2a -r d7e06542304c Platforms/Generic/OracleDelayedCallExecutor.h --- 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* callback, unsigned int timeoutInMs = 1000) { - oracle_.Submit(new DelayedCallCommand(broker_, callback, timeoutInMs, NULL, context_)); + oracle_.Submit(new DelayedCallCommand(callback, timeoutInMs, NULL, context_)); } }; } diff -r 45df56448b2a -r d7e06542304c Platforms/Generic/OracleWebService.cpp --- 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* successCallback, // takes ownership + WebServiceCachedGetCommand(OrthancStone::MessageHandler* successCallback, // takes ownership boost::shared_ptr 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* successCallback) { - oracle_.Submit(new WebServiceCachedGetCommand(GetBroker(), successCallback, cachedMessage, payload, context_)); + oracle_.Submit(new WebServiceCachedGetCommand(successCallback, cachedMessage, payload, context_)); } diff -r 45df56448b2a -r d7e06542304c Platforms/Generic/OracleWebService.h --- 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* 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* 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* 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 cachedHttpMessage, diff -r 45df56448b2a -r d7e06542304c Platforms/Generic/WebServiceCommandBase.cpp --- 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* successCallback, + WebServiceCommandBase::WebServiceCommandBase(OrthancStone::MessageHandler* successCallback, OrthancStone::MessageHandler* 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), diff -r 45df56448b2a -r d7e06542304c Platforms/Generic/WebServiceCommandBase.h --- 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* successCallback, // takes ownership + WebServiceCommandBase(OrthancStone::MessageHandler* successCallback, // takes ownership OrthancStone::MessageHandler* failureCallback, // takes ownership const Orthanc::WebServiceParameters& parameters, const std::string& url, diff -r 45df56448b2a -r d7e06542304c Platforms/Generic/WebServiceDeleteCommand.cpp --- 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* successCallback, // takes ownership + WebServiceDeleteCommand::WebServiceDeleteCommand(OrthancStone::MessageHandler* successCallback, // takes ownership OrthancStone::MessageHandler* 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) { } diff -r 45df56448b2a -r d7e06542304c Platforms/Generic/WebServiceDeleteCommand.h --- 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* successCallback, // takes ownership + WebServiceDeleteCommand(OrthancStone::MessageHandler* successCallback, // takes ownership OrthancStone::MessageHandler* failureCallback, // takes ownership const Orthanc::WebServiceParameters& parameters, const std::string& url, diff -r 45df56448b2a -r d7e06542304c Platforms/Generic/WebServiceGetCommand.cpp --- 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* successCallback, // takes ownership + WebServiceGetCommand::WebServiceGetCommand(OrthancStone::MessageHandler* successCallback, // takes ownership OrthancStone::MessageHandler* 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) { } diff -r 45df56448b2a -r d7e06542304c Platforms/Generic/WebServiceGetCommand.h --- 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* successCallback, // takes ownership + WebServiceGetCommand(OrthancStone::MessageHandler* successCallback, // takes ownership OrthancStone::MessageHandler* failureCallback, // takes ownership const Orthanc::WebServiceParameters& parameters, const std::string& url, diff -r 45df56448b2a -r d7e06542304c Platforms/Generic/WebServicePostCommand.cpp --- 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* successCallback, // takes ownership + WebServicePostCommand::WebServicePostCommand(OrthancStone::MessageHandler* successCallback, // takes ownership OrthancStone::MessageHandler* 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) { } diff -r 45df56448b2a -r d7e06542304c Platforms/Generic/WebServicePostCommand.h --- 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* successCallback, // takes ownership + WebServicePostCommand(OrthancStone::MessageHandler* successCallback, // takes ownership OrthancStone::MessageHandler* failureCallback, // takes ownership const Orthanc::WebServiceParameters& parameters, const std::string& url, diff -r 45df56448b2a -r d7e06542304c Resources/CMake/OrthancStoneConfiguration.cmake --- 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 diff -r 45df56448b2a -r d7e06542304c UnitTestsSources/GenericToolboxTests.cpp diff -r 45df56448b2a -r d7e06542304c UnitTestsSources/TestMessageBroker.cpp --- 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 { 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(broker, *this)); - } }; } TEST(MessageBroker, TestPermanentConnectionSimpleUseCase) { - MessageBroker broker; - MyObservable observable(broker); - MyObserver observer(broker); + MyObservable observable; + boost::shared_ptr observer(new MyObserver); // create a permanent connection between an observable and an observer - observable.RegisterObserverCallback(new Callable(observer, &MyObserver::HandleCompletedMessage)); + observer->Register(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(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 observer(new MyObserver); // create a permanent connection between an observable and an observer - observable.RegisterObserverCallback(new Callable(*observer, &MyObserver::HandleCompletedMessage)); + observer->Register(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(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(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(*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(*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 diff -r 45df56448b2a -r d7e06542304c UnitTestsSources/TestStructureSet.cpp --- 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;