changeset 247:3d523c9a8f0d am

trying to use boost::signals2 even more.
author am@osimis.io
date Mon, 02 Jul 2018 12:32:02 +0200
parents 5470b15f7cf2
children 092f88e93389
files Applications/Samples/SimpleViewerApplication.h Framework/Layers/DicomStructureSetRendererFactory.cpp Framework/Layers/ILayerSource.h Framework/Layers/LayerSourceBase.cpp Framework/Layers/LayerSourceBase.h Framework/Layers/OrthancFrameLayerSource.cpp Framework/Layers/OrthancFrameLayerSource.h Framework/Toolbox/IWebService.h Framework/Toolbox/OrthancSlicesLoader.cpp Framework/Toolbox/OrthancSlicesLoader.h Framework/Volumes/StructureSetLoader.cpp Framework/Volumes/StructureSetLoader.h Framework/Widgets/LayerWidget.cpp Framework/Widgets/LayerWidget.h Framework/dev.h Platforms/Generic/OracleWebService.h Platforms/Generic/WebServiceGetCommand.cpp Platforms/Generic/WebServiceGetCommand.h Platforms/Generic/WebServicePostCommand.cpp Platforms/Generic/WebServicePostCommand.h Platforms/Wasm/WasmWebService.cpp Platforms/Wasm/WasmWebService.h Resources/CMake/OrthancStoneConfiguration.cmake
diffstat 23 files changed, 349 insertions(+), 247 deletions(-) [+]
line wrap: on
line diff
--- a/Applications/Samples/SimpleViewerApplication.h	Tue Jun 26 13:55:17 2018 +0200
+++ b/Applications/Samples/SimpleViewerApplication.h	Mon Jul 02 12:32:02 2018 +0200
@@ -179,7 +179,7 @@
         // Once the geometry of the series is downloaded from Orthanc,
         // display its first slice, and adapt the viewport to fit this
         // slice
-        if (source_ == &source)
+        if (source_.get() == &source)
         {
           //SetSlice(source_->GetSliceCount() / 2);
         }
@@ -187,12 +187,8 @@
         mainLayout_->SetDefaultView();
       }
 
-      void OnGeometryReady(const ILayerSource& source)
-      {
-        mainLayout_->SetDefaultView();
-      }
 
-      virtual void NotifyGeometryError(const ILayerSource& source)
+      void NotifyGeometryError(const ILayerSource& source)
       {
       }
       
@@ -205,7 +201,7 @@
       {
       }
  
-      virtual void NotifyLayerReady(std::auto_ptr<ILayerRenderer>& layer,
+      virtual void NotifyLayerReady(boost::shared_ptr<ILayerRenderer> renderer,
                                     const ILayerSource& source,
                                     const CoordinateSystem3D& slice,
                                     bool isError)
@@ -215,14 +211,14 @@
       std::unique_ptr<Interactor>     interactor_;
       LayoutWidget*                   mainLayout_;
       LayoutWidget*                   thumbnailsLayout_;
-      LayerWidget*                    mainViewport_;
-      std::vector<LayerWidget*>       thumbnails_;
+      boost::shared_ptr<LayerWidget>  mainViewport_;
+      std::vector<boost::shared_ptr<LayerWidget>>       thumbnails_;
       std::vector<std::string>        instances_;
       unsigned int                    currentInstanceIndex_;
       OrthancStone::WidgetViewport*                wasmViewport1_;
       OrthancStone::WidgetViewport*                wasmViewport2_;
 
-      OrthancFrameLayerSource*        source_;
+      boost::shared_ptr<OrthancFrameLayerSource>        source_;
       unsigned int                    slice_;
       
     public:
@@ -288,27 +284,30 @@
         thumbnailsLayout_->SetBackgroundColor(50, 50, 50);
         thumbnailsLayout_->SetVertical();
 
-        mainViewport_ = new LayerWidget();
-        thumbnails_.push_back(new LayerWidget());
-        thumbnails_.push_back(new LayerWidget());
+        mainViewport_.reset(new LayerWidget());
+        thumbnails_.push_back(boost::shared_ptr<LayerWidget>(new LayerWidget()));
+        thumbnails_.push_back(boost::shared_ptr<LayerWidget>(new LayerWidget()));
 
         // hierarchy
         mainLayout_->AddWidget(thumbnailsLayout_);
-        mainLayout_->AddWidget(mainViewport_);
-        thumbnailsLayout_->AddWidget(thumbnails_[0]);
-        thumbnailsLayout_->AddWidget(thumbnails_[1]);
+        mainLayout_->AddWidget(mainViewport_.get());
+        thumbnailsLayout_->AddWidget(thumbnails_[0].get());
+        thumbnailsLayout_->AddWidget(thumbnails_[1].get());
 
         // sources
-        source_ = new OrthancFrameLayerSource(context_->GetWebService());
+        source_.reset(new OrthancFrameLayerSource());
+        source_->Init(context_->GetWebService());
         source_->LoadFrame(instances_[currentInstanceIndex_], 0);
 //        source_->Register(*this);
-        source_->SignalGeometryReady.connect(boost::bind(&SimpleViewerApplication::OnGeometryReady, this, _1));
+        //source_->SignalGeometryReady.connect(boost::bind(&SimpleViewerApplication::NotifyGeometryReady, this, _1));
 
         mainViewport_->AddLayer(source_);
 
-        OrthancFrameLayerSource* thumb0 = new OrthancFrameLayerSource(context_->GetWebService());
+        boost::shared_ptr<OrthancFrameLayerSource> thumb0(new OrthancFrameLayerSource());
+        thumb0->Init(context_->GetWebService());
         thumb0->LoadFrame(instances_[0], 0);
-        OrthancFrameLayerSource* thumb1 = new OrthancFrameLayerSource(context_->GetWebService());
+        boost::shared_ptr<OrthancFrameLayerSource> thumb1(new OrthancFrameLayerSource());
+        thumb1->Init(context_->GetWebService());
         thumb1->LoadFrame(instances_[1], 0);
 
         thumbnails_[0]->AddLayer(thumb0);
@@ -323,7 +322,7 @@
       virtual void InitializeWasm() {
 
         AttachWidgetToWasmViewport("canvas", thumbnailsLayout_);
-        AttachWidgetToWasmViewport("canvas2", mainViewport_);
+        AttachWidgetToWasmViewport("canvas2", mainViewport_.get());  //TODO: check object lifecycle
       }
 #endif
       void NextImage(WorldSceneWidget& widget) {
@@ -331,11 +330,16 @@
 
         currentInstanceIndex_ = (currentInstanceIndex_ + 1) % instances_.size();
 
-        std::auto_ptr<OrthancFrameLayerSource> layer
-            (new OrthancFrameLayerSource(context_->GetWebService()));
-        layer->LoadFrame(instances_[currentInstanceIndex_], 0);
+        source_.reset(new OrthancFrameLayerSource());
+        source_->Init(context_->GetWebService());
+        source_->LoadFrame(instances_[currentInstanceIndex_], 0);
+
 
-        mainViewport_->ReplaceLayer(0, layer.release());
+//        std::auto_ptr<OrthancFrameLayerSource> layer
+//            (new OrthancFrameLayerSource(context_->GetWebService()));
+//        layer->LoadFrame(instances_[currentInstanceIndex_], 0);
+
+        mainViewport_->ReplaceLayer(0, source_);
         //  source_->LoadFrame("45b7e6bc-168e8ed1-063dc08d-cffd6431-133a276a", 0);
       }
 
--- a/Framework/Layers/DicomStructureSetRendererFactory.cpp	Tue Jun 26 13:55:17 2018 +0200
+++ b/Framework/Layers/DicomStructureSetRendererFactory.cpp	Mon Jul 02 12:32:02 2018 +0200
@@ -130,7 +130,7 @@
   {
     if (loader_.HasStructureSet())
     {
-      NotifyLayerReady(new Renderer(loader_.GetStructureSet(), viewportSlice), viewportSlice, false);
+      NotifyLayerReady(boost::shared_ptr<ILayerRenderer>(new Renderer(loader_.GetStructureSet(), viewportSlice)), viewportSlice, false);
     }
   }
 }
--- a/Framework/Layers/ILayerSource.h	Tue Jun 26 13:55:17 2018 +0200
+++ b/Framework/Layers/ILayerSource.h	Mon Jul 02 12:32:02 2018 +0200
@@ -23,6 +23,7 @@
 
 #include "ILayerRenderer.h"
 #include "../Toolbox/Slice.h"
+#include <boost/shared_ptr.hpp>
 
 namespace OrthancStone
 {
@@ -52,8 +53,8 @@
                                      const Slice& slice) = 0;
  
       // The layer must be deleted by the observer that releases the
-      // std::auto_ptr
-      virtual void NotifyLayerReady(std::auto_ptr<ILayerRenderer>& layer,
+      // std::auto_ptr   // TODO: check the lifecycle of the layer since we are not using an std::auto_ptr anymore
+      virtual void NotifyLayerReady(boost::shared_ptr<ILayerRenderer> renderer,
                                     const ILayerSource& source,
                                     const CoordinateSystem3D& slice,
                                     bool isError) = 0;  // TODO Shouldn't this be separate as NotifyLayerError?
@@ -63,7 +64,7 @@
     {
     }
 
-    virtual void Register(IObserver& observer) = 0;
+    virtual void Register(boost::shared_ptr<IObserver> observer) = 0;
 
     virtual bool GetExtent(std::vector<Vector>& points,
                            const CoordinateSystem3D& viewportSlice) = 0;
--- a/Framework/Layers/LayerSourceBase.cpp	Tue Jun 26 13:55:17 2018 +0200
+++ b/Framework/Layers/LayerSourceBase.cpp	Mon Jul 02 12:32:02 2018 +0200
@@ -27,65 +27,64 @@
 {
   namespace
   {
-    class LayerReadyFunctor : public boost::noncopyable
-    {
-    private:
-      std::auto_ptr<ILayerRenderer>  layer_;
-      const CoordinateSystem3D&      slice_;
-      bool                           isError_;
+//    class LayerReadyFunctor : public boost::noncopyable
+//    {
+//    private:
+//      std::auto_ptr<ILayerRenderer>  layer_;
+//      const CoordinateSystem3D&      slice_;
+//      bool                           isError_;
       
-    public:
-      LayerReadyFunctor(ILayerRenderer* layer,
-                        const CoordinateSystem3D& slice,
-                        bool isError) :
-        layer_(layer),
-        slice_(slice),
-        isError_(isError)
-      {
-      }
+//    public:
+//      LayerReadyFunctor(ILayerRenderer* layer,
+//                        const CoordinateSystem3D& slice,
+//                        bool isError) :
+//        layer_(layer),
+//        slice_(slice),
+//        isError_(isError)
+//      {
+//      }
 
-      void operator() (ILayerSource::IObserver& observer,
-                       const ILayerSource& source)
-      {
-        observer.NotifyLayerReady(layer_, source, slice_, isError_);
-      }
-    };
+//      void operator() (ILayerSource::IObserver& observer,
+//                       const ILayerSource& source)
+//      {
+//        observer.NotifyLayerReady(layer_, source, slice_, isError_);
+//      }
+//    };
   }
 
   void LayerSourceBase::NotifyGeometryReady()
   {
-    //new observers
     SignalGeometryReady(*this);
-
-    //old observers
-    observers_.Apply(*this, &IObserver::NotifyGeometryReady);
   }
     
   void LayerSourceBase::NotifyGeometryError()
   {
-    observers_.Apply(*this, &IObserver::NotifyGeometryError);
+    SignalGeometryError(*this);
   }  
     
   void LayerSourceBase::NotifyContentChange()
   {
-    observers_.Apply(*this, &IObserver::NotifyContentChange);
+    SignalContentChange(*this);
   }
 
   void LayerSourceBase::NotifySliceChange(const Slice& slice)
   {
-    observers_.Apply(*this, &IObserver::NotifySliceChange, slice);
+    SignalSliceChange(*this, slice);
   }
 
-  void LayerSourceBase::NotifyLayerReady(ILayerRenderer* layer,
+  void LayerSourceBase::NotifyLayerReady(boost::shared_ptr<ILayerRenderer> renderer,
                                          const CoordinateSystem3D& slice,
                                          bool isError)
   {
-    LayerReadyFunctor functor(layer, slice, isError);
-    observers_.Notify(*this, functor);
+    SignalLayerReady(renderer, *this, slice, isError);
   }
 
-  void LayerSourceBase::Register(IObserver& observer)
+  void LayerSourceBase::Register(boost::shared_ptr<IObserver> observer)
   {
-    observers_.Register(observer);
+    SignalGeometryReady.connect(LayerSourceBase::SignalGeometryReadyType::slot_type(&IObserver::NotifyGeometryReady, observer.get(), _1).track(observer));
+    SignalGeometryError.connect(LayerSourceBase::SignalGeometryErrorType::slot_type(&IObserver::NotifyGeometryError, observer.get(), _1).track(observer));
+    SignalContentChange.connect(LayerSourceBase::SignalContentChangeType::slot_type(&IObserver::NotifyContentChange, observer.get(), _1).track(observer));
+    SignalSliceChange.connect(LayerSourceBase::SignalSliceChangeType::slot_type(&IObserver::NotifySliceChange, observer.get(), _1, _2).track(observer));
+    SignalLayerReady.connect(LayerSourceBase::SignalLayerReadyType::slot_type(&IObserver::NotifyLayerReady, observer.get(), _1, _2, _3, _4).track(observer));
   }
 }
--- a/Framework/Layers/LayerSourceBase.h	Tue Jun 26 13:55:17 2018 +0200
+++ b/Framework/Layers/LayerSourceBase.h	Mon Jul 02 12:32:02 2018 +0200
@@ -24,15 +24,16 @@
 #include "ILayerSource.h"
 #include "../Toolbox/ObserversRegistry.h"
 #include <boost/signals2.hpp>
+#include <boost/shared_ptr.hpp>
 
 namespace OrthancStone
 {
   class LayerSourceBase : public ILayerSource
   {
   private:
-    typedef ObserversRegistry<ILayerSource, IObserver>  Observers;
+    //typedef ObserversRegistry<ILayerSource, IObserver>  Observers;
 
-    Observers  observers_;
+    //Observers  observers_;
 
   protected:
     void NotifyGeometryReady();
@@ -43,12 +44,32 @@
 
     void NotifySliceChange(const Slice& slice);
 
-    void NotifyLayerReady(ILayerRenderer* layer,
+    void NotifyLayerReady(boost::shared_ptr<ILayerRenderer> renderer,
                           const CoordinateSystem3D& slice,
                           bool isError);
 
   public:
-    virtual void Register(IObserver& observer);
-    boost::signals2::signal<void (const ILayerSource& source)> SignalGeometryReady;
+    virtual void Register(boost::shared_ptr<IObserver> observer);
+
+  protected:
+    typedef boost::signals2::signal<void (const ILayerSource& source)> SignalGeometryReadyType;
+    typedef boost::signals2::signal<void (const ILayerSource& source)> SignalGeometryErrorType;
+    typedef boost::signals2::signal<void (const ILayerSource& source)> SignalContentChangeType;
+    typedef boost::signals2::signal<void (const ILayerSource& source,
+                                  const Slice& slice)> SignalSliceChangeType;
+    typedef boost::signals2::signal<void (boost::shared_ptr<ILayerRenderer> renderer,
+                                  const ILayerSource& source,
+                                  const CoordinateSystem3D& slice,
+                                  bool isError)> SignalLayerReadyType;
+
+    SignalGeometryReadyType SignalGeometryReady;
+    SignalGeometryErrorType SignalGeometryError;
+    SignalContentChangeType SignalContentChange;
+    SignalSliceChangeType SignalSliceChange;
+    SignalLayerReadyType SignalLayerReady;
+
+
+    //boost::signals2::signal<void (const ILayerSource& source)> SignalGeometryError;
+
   };
 }
--- a/Framework/Layers/OrthancFrameLayerSource.cpp	Tue Jun 26 13:55:17 2018 +0200
+++ b/Framework/Layers/OrthancFrameLayerSource.cpp	Mon Jul 02 12:32:02 2018 +0200
@@ -55,7 +55,7 @@
                                                       SliceImageQuality quality)
   {
     bool isFull = (quality == SliceImageQuality_Full);
-    LayerSourceBase::NotifyLayerReady(FrameRenderer::CreateRenderer(image.release(), slice, isFull),
+    LayerSourceBase::NotifyLayerReady(boost::shared_ptr<ILayerRenderer>(FrameRenderer::CreateRenderer(image.release(), slice, isFull)),
                                       slice.GetGeometry(), false);
   }
 
@@ -68,29 +68,33 @@
   }
 
 
-  OrthancFrameLayerSource::OrthancFrameLayerSource(IWebService& orthanc) :
-    loader_(*this, orthanc),
+  OrthancFrameLayerSource::OrthancFrameLayerSource() :
     quality_(SliceImageQuality_Full)
   {
   }
 
-  
+  void OrthancFrameLayerSource::Init(IWebService& orthanc) {
+    // note: there must have been a shared_ptr created on this object before calling shared_from_this()
+
+    loader_.reset(new OrthancSlicesLoader(shared_from_this(), orthanc));
+  }
+
   void OrthancFrameLayerSource::LoadSeries(const std::string& seriesId)
   {
-    loader_.ScheduleLoadSeries(seriesId);
+    loader_->ScheduleLoadSeries(loader_, seriesId);
   }
 
 
   void OrthancFrameLayerSource::LoadInstance(const std::string& instanceId)
   {
-    loader_.ScheduleLoadInstance(instanceId);
+    loader_->ScheduleLoadInstance(loader_, instanceId);
   }
 
 
   void OrthancFrameLayerSource::LoadFrame(const std::string& instanceId,
                                           unsigned int frame)
   {
-    loader_.ScheduleLoadFrame(instanceId, frame);
+    loader_->ScheduleLoadFrame(loader_, instanceId, frame);
   }
 
 
@@ -98,10 +102,10 @@
                                           const CoordinateSystem3D& viewportSlice)
   {
     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
@@ -115,11 +119,11 @@
   {
     size_t index;
 
-    if (loader_.IsGeometryReady())
+    if (loader_->IsGeometryReady())
     {
-      if (loader_.LookupSlice(index, viewportSlice))
+      if (loader_->LookupSlice(index, viewportSlice))
       {
-        loader_.ScheduleLoadSliceImage(index, quality_);
+        loader_->ScheduleLoadSliceImage(loader_, index, quality_);
       }
       else
       {
--- a/Framework/Layers/OrthancFrameLayerSource.h	Tue Jun 26 13:55:17 2018 +0200
+++ b/Framework/Layers/OrthancFrameLayerSource.h	Mon Jul 02 12:32:02 2018 +0200
@@ -24,15 +24,18 @@
 #include "LayerSourceBase.h"
 #include "../Toolbox/IWebService.h"
 #include "../Toolbox/OrthancSlicesLoader.h"
+#include <boost/shared_ptr.hpp>
+#include <boost/enable_shared_from_this.hpp>
 
 namespace OrthancStone
 {  
   class OrthancFrameLayerSource :
     public LayerSourceBase,
-    private OrthancSlicesLoader::ICallback
+    public OrthancSlicesLoader::IObserver,
+      public boost::enable_shared_from_this<OrthancFrameLayerSource>
   {
   private:
-    OrthancSlicesLoader  loader_;
+    boost::shared_ptr<OrthancSlicesLoader> loader_;
     SliceImageQuality    quality_;
 
     virtual void NotifyGeometryReady(const OrthancSlicesLoader& loader);
@@ -51,8 +54,11 @@
                                        SliceImageQuality quality);
 
   public:
-    OrthancFrameLayerSource(IWebService& orthanc);
+    OrthancFrameLayerSource();
+    void Init(IWebService& orthanc);
+    virtual ~OrthancFrameLayerSource() {
 
+    }
     void LoadSeries(const std::string& seriesId);
 
     void LoadInstance(const std::string& instanceId);
@@ -67,12 +73,12 @@
 
     size_t GetSliceCount() const
     {
-      return loader_.GetSliceCount();
+      return loader_->GetSliceCount();
     }
 
     const Slice& GetSlice(size_t slice) const 
     {
-      return loader_.GetSlice(slice);
+      return loader_->GetSlice(slice);
     }
 
     virtual bool GetExtent(std::vector<Vector>& points,
--- a/Framework/Toolbox/IWebService.h	Tue Jun 26 13:55:17 2018 +0200
+++ b/Framework/Toolbox/IWebService.h	Mon Jul 02 12:32:02 2018 +0200
@@ -24,23 +24,33 @@
 #include <Core/IDynamicObject.h>
 
 #include <string>
+#include <boost/shared_ptr.hpp>
+#include <boost/signals2.hpp>
 
 namespace OrthancStone
 {
   class IWebService : public boost::noncopyable
   {
   public:
-    class ICallback : public boost::noncopyable
+    class IWebServiceObserver : public boost::noncopyable
     {
     public:
-      virtual ~ICallback()
+        typedef boost::signals2::signal<void (const std::string& uri,
+                                    Orthanc::IDynamicObject* payload)> SignalErrorType;
+        typedef boost::signals2::signal<void (const std::string& uri,
+                                      const void* answer,
+                                      size_t answerSize,
+                                      Orthanc::IDynamicObject* payload)> SignalSuccessType;
+
+    public:
+      virtual ~IWebServiceObserver()
       {
       }
 
-      virtual void NotifyError(const std::string& uri,
+      virtual void OnRequestError(const std::string& uri,
                                Orthanc::IDynamicObject* payload) = 0;
 
-      virtual void NotifySuccess(const std::string& uri,
+      virtual void OnRequestSuccess(const std::string& uri,
                                  const void* answer,
                                  size_t answerSize,
                                  Orthanc::IDynamicObject* payload) = 0;
@@ -50,11 +60,13 @@
     {
     }
 
-    virtual void ScheduleGetRequest(ICallback& callback,
+    virtual void ScheduleGetRequest(IWebServiceObserver* observer,
+                                    boost::shared_ptr<boost::noncopyable> tracker,
                                     const std::string& uri,
                                     Orthanc::IDynamicObject* payload) = 0;
 
-    virtual void SchedulePostRequest(ICallback& callback,
+    virtual void SchedulePostRequest(IWebServiceObserver* observer,
+                                     boost::shared_ptr<boost::noncopyable> tracker,
                                      const std::string& uri,
                                      const std::string& body,
                                      Orthanc::IDynamicObject* payload) = 0;
--- a/Framework/Toolbox/OrthancSlicesLoader.cpp	Tue Jun 26 13:55:17 2018 +0200
+++ b/Framework/Toolbox/OrthancSlicesLoader.cpp	Mon Jul 02 12:32:02 2018 +0200
@@ -169,18 +169,18 @@
   };
     
 
-  class OrthancSlicesLoader::WebCallback : public IWebService::ICallback
-  {
-  private:
-    OrthancSlicesLoader&  that_;
+//  class OrthancSlicesLoader::WebCallback : public IWebService::ICallback
+//  {
+//  private:
+//    OrthancSlicesLoader&  that_;
 
-  public:
-    WebCallback(OrthancSlicesLoader&  that) :
-      that_(that)
-    {
-    }
+//  public:
+//    WebCallback(OrthancSlicesLoader&  that) :
+//      that_(that)
+//    {
+//    }
 
-    virtual void NotifySuccess(const std::string& uri,
+    void OrthancSlicesLoader::OnRequestSuccess(const std::string& uri,
                                const void* answer,
                                size_t answerSize,
                                Orthanc::IDynamicObject* payload)
@@ -190,15 +190,15 @@
       switch (operation->GetMode())
       {
         case Mode_SeriesGeometry:
-          that_.ParseSeriesGeometry(answer, answerSize);
+          ParseSeriesGeometry(answer, answerSize);
           break;
 
         case Mode_InstanceGeometry:
-          that_.ParseInstanceGeometry(operation->GetInstanceId(), answer, answerSize);
+          ParseInstanceGeometry(operation->GetInstanceId(), answer, answerSize);
           break;
 
         case Mode_FrameGeometry:
-          that_.ParseFrameGeometry(operation->GetInstanceId(),
+          ParseFrameGeometry(operation->GetInstanceId(),
                                    operation->GetFrame(), answer, answerSize);
           break;
 
@@ -206,13 +206,13 @@
           switch (operation->GetQuality())
           {
             case SliceImageQuality_Full:
-              that_.ParseSliceImagePng(*operation, answer, answerSize);
+              ParseSliceImagePng(*operation, answer, answerSize);
               break;
 
             case SliceImageQuality_Jpeg50:
             case SliceImageQuality_Jpeg90:
             case SliceImageQuality_Jpeg95:
-              that_.ParseSliceImageJpeg(*operation, answer, answerSize);
+              ParseSliceImageJpeg(*operation, answer, answerSize);
               break;
 
             default:
@@ -222,7 +222,7 @@
           break;
 
         case Mode_LoadRawImage:
-          that_.ParseSliceRawImage(*operation, answer, answerSize);
+          ParseSliceRawImage(*operation, answer, answerSize);
           break;
 
         default:
@@ -230,7 +230,7 @@
       }
     }
 
-    virtual void NotifyError(const std::string& uri,
+    void OrthancSlicesLoader::OnRequestError(const std::string& uri,
                              Orthanc::IDynamicObject* payload)
     {
       std::auto_ptr<Operation> operation(dynamic_cast<Operation*>(payload));
@@ -240,12 +240,12 @@
       {
         case Mode_FrameGeometry:
         case Mode_SeriesGeometry:
-          that_.userCallback_.NotifyGeometryError(that_);
-          that_.state_ = State_Error;
+          SignalGeometryError(*this);
+          state_ = State_Error;
           break;
 
         case Mode_LoadImage:
-          that_.userCallback_.NotifySliceImageError(that_, operation->GetSliceIndex(),
+          SignalSliceImageError(*this, operation->GetSliceIndex(),
                                                     operation->GetSlice(),
                                                     operation->GetQuality());
           break;
@@ -254,7 +254,7 @@
           throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError);
       }
     }     
-  };
+//  };
 
 
   
@@ -267,16 +267,14 @@
     }
     else
     {
-      userCallback_.NotifySliceImageReady
-        (*this, operation.GetSliceIndex(), operation.GetSlice(), image, operation.GetQuality());
+      SignalSliceImageReady(*this, operation.GetSliceIndex(), operation.GetSlice(), image, operation.GetQuality());
     }
   }
 
   
   void OrthancSlicesLoader::NotifySliceImageError(const Operation& operation) const
   {
-    userCallback_.NotifySliceImageError
-      (*this, operation.GetSliceIndex(), operation.GetSlice(), operation.GetQuality());
+    SignalSliceImageError(*this, operation.GetSliceIndex(), operation.GetSlice(), operation.GetQuality());
   }
 
 
@@ -301,12 +299,12 @@
     if (ok)
     {
       LOG(INFO) << "Loaded a series with " << slices_.GetSliceCount() << " slice(s)";
-      userCallback_.NotifyGeometryReady(*this);
+      SignalGeometryReady(*this);
     }
     else
     {
       LOG(ERROR) << "This series is empty";
-      userCallback_.NotifyGeometryError(*this);
+      SignalGeometryError(*this);
     }
   }
 
@@ -318,7 +316,7 @@
     if (!MessagingToolbox::ParseJson(series, answer, size) ||
         series.type() != Json::objectValue)
     {
-      userCallback_.NotifyGeometryError(*this);
+      SignalGeometryError(*this);
       return;
     }
 
@@ -365,7 +363,7 @@
     if (!MessagingToolbox::ParseJson(tags, answer, size) ||
         tags.type() != Json::objectValue)
     {
-      userCallback_.NotifyGeometryError(*this);
+      SignalGeometryError(*this);
       return;
     }
 
@@ -392,7 +390,7 @@
       else
       {
         LOG(WARNING) << "Skipping invalid multi-frame instance " << instanceId;
-        userCallback_.NotifyGeometryError(*this);
+        SignalGeometryError(*this);
         return;
       }
     }
@@ -410,7 +408,7 @@
     if (!MessagingToolbox::ParseJson(tags, answer, size) ||
         tags.type() != Json::objectValue)
     {
-      userCallback_.NotifyGeometryError(*this);
+      SignalGeometryError(*this);
       return;
     }
 
@@ -426,12 +424,12 @@
     {
       LOG(INFO) << "Loaded instance " << instanceId;
       slices_.AddSlice(slice.release());
-      userCallback_.NotifyGeometryReady(*this);
+      SignalGeometryReady(*this);
     }
     else
     {
       LOG(WARNING) << "Skipping invalid instance " << instanceId;
-      userCallback_.NotifyGeometryError(*this);
+      SignalGeometryError(*this);
     }
   }
 
@@ -715,17 +713,22 @@
   }
 
 
-  OrthancSlicesLoader::OrthancSlicesLoader(ICallback& callback,
+  OrthancSlicesLoader::OrthancSlicesLoader(boost::shared_ptr<OrthancSlicesLoader::IObserver> observer,
                                            IWebService& orthanc) :
-    webCallback_(new WebCallback(*this)),
-    userCallback_(callback),
+    //webCallback_(new WebCallback(*this)),
+//    userCallback_(callback),
+    observer_(observer),
     orthanc_(orthanc),
     state_(State_Initialization)
   {
+    SignalGeometryReady.connect(OrthancSlicesLoader::IObserver::SignalGeometryReadyType::slot_type(&OrthancSlicesLoader::IObserver::NotifyGeometryReady, observer.get(), _1).track(observer));
+    SignalGeometryError.connect(OrthancSlicesLoader::IObserver::SignalGeometryErrorType::slot_type(&OrthancSlicesLoader::IObserver::NotifyGeometryError, observer.get(), _1).track(observer));
+    SignalSliceImageReady.connect(OrthancSlicesLoader::IObserver::SignalSliceImageReadyType::slot_type(&OrthancSlicesLoader::IObserver::NotifySliceImageReady, observer.get(), _1, _2, _3, _4, _5).track(observer));
+    SignalSliceImageError.connect(OrthancSlicesLoader::IObserver::SignalSliceImageErrorType::slot_type(&OrthancSlicesLoader::IObserver::NotifySliceImageError, observer.get(), _1, _2, _3, _4).track(observer));
   }
 
   
-  void OrthancSlicesLoader::ScheduleLoadSeries(const std::string& seriesId)
+  void OrthancSlicesLoader::ScheduleLoadSeries(boost::shared_ptr<boost::noncopyable> tracker, const std::string& seriesId)
   {
     if (state_ != State_Initialization)
     {
@@ -735,12 +738,12 @@
     {
       state_ = State_LoadingGeometry;
       std::string uri = "/series/" + seriesId + "/instances-tags";
-      orthanc_.ScheduleGetRequest(*webCallback_, uri, Operation::DownloadSeriesGeometry());
+      orthanc_.ScheduleGetRequest(this, tracker, uri, Operation::DownloadSeriesGeometry());
     }
   }
 
 
-  void OrthancSlicesLoader::ScheduleLoadInstance(const std::string& instanceId)
+  void OrthancSlicesLoader::ScheduleLoadInstance(boost::shared_ptr<boost::noncopyable> tracker, const std::string& instanceId)
   {
     if (state_ != State_Initialization)
     {
@@ -754,12 +757,12 @@
       // mandatory to read RT DOSE, but is too long to be returned by default
       std::string uri = "/instances/" + instanceId + "/tags?ignore-length=3004-000c";
       orthanc_.ScheduleGetRequest
-        (*webCallback_, uri, Operation::DownloadInstanceGeometry(instanceId));
+        (this, tracker, uri, Operation::DownloadInstanceGeometry(instanceId));
     }
   }
   
 
-  void OrthancSlicesLoader::ScheduleLoadFrame(const std::string& instanceId,
+  void OrthancSlicesLoader::ScheduleLoadFrame(boost::shared_ptr<boost::noncopyable> tracker, const std::string& instanceId,
                                               unsigned int frame)
   {
     if (state_ != State_Initialization)
@@ -771,7 +774,7 @@
       state_ = State_LoadingGeometry;
       std::string uri = "/instances/" + instanceId + "/tags";
       orthanc_.ScheduleGetRequest
-        (*webCallback_, uri, Operation::DownloadFrameGeometry(instanceId, frame));
+        (this, tracker, uri, Operation::DownloadFrameGeometry(instanceId, frame));
     }
   }
   
@@ -816,7 +819,7 @@
   }
   
 
-  void OrthancSlicesLoader::ScheduleSliceImagePng(const Slice& slice,
+  void OrthancSlicesLoader::ScheduleSliceImagePng(boost::shared_ptr<boost::noncopyable> tracker, const Slice& slice,
                                                   size_t index)
   {
     std::string uri = ("/instances/" + slice.GetOrthancInstanceId() + "/frames/" + 
@@ -840,12 +843,12 @@
         throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
     }
 
-    orthanc_.ScheduleGetRequest(*webCallback_, uri,
+    orthanc_.ScheduleGetRequest(this, tracker, uri,
                                 Operation::DownloadSliceImage(index, slice, SliceImageQuality_Full));
   }
 
 
-  void OrthancSlicesLoader::ScheduleSliceImageJpeg(const Slice& slice,
+  void OrthancSlicesLoader::ScheduleSliceImageJpeg(boost::shared_ptr<boost::noncopyable> tracker, const Slice& slice,
                                                    size_t index,
                                                    SliceImageQuality quality)
   {
@@ -875,13 +878,13 @@
                        "-" + slice.GetOrthancInstanceId() + "_" + 
                        boost::lexical_cast<std::string>(slice.GetFrame()));
       
-    orthanc_.ScheduleGetRequest(*webCallback_, uri,
+    orthanc_.ScheduleGetRequest(this, tracker, uri,
                                 Operation::DownloadSliceImage(index, slice, quality));
   }
 
 
 
-  void OrthancSlicesLoader::ScheduleLoadSliceImage(size_t index,
+  void OrthancSlicesLoader::ScheduleLoadSliceImage(boost::shared_ptr<boost::noncopyable> tracker, size_t index,
                                                    SliceImageQuality quality)
   {
     if (state_ != State_GeometryReady)
@@ -895,18 +898,18 @@
     {
       if (quality == SliceImageQuality_Full)
       {
-        ScheduleSliceImagePng(slice, index);
+        ScheduleSliceImagePng(tracker, slice, index);
       }
       else
       {
-        ScheduleSliceImageJpeg(slice, index, quality);
+        ScheduleSliceImageJpeg(tracker, slice, index, quality);
       }
     }
     else
     {
       std::string uri = ("/instances/" + slice.GetOrthancInstanceId() + "/frames/" + 
                          boost::lexical_cast<std::string>(slice.GetFrame()) + "/raw.gz");
-      orthanc_.ScheduleGetRequest(*webCallback_, uri,
+      orthanc_.ScheduleGetRequest(this, tracker, uri,
                                   Operation::DownloadSliceRawImage(index, slice));
     }
   }
--- a/Framework/Toolbox/OrthancSlicesLoader.h	Tue Jun 26 13:55:17 2018 +0200
+++ b/Framework/Toolbox/OrthancSlicesLoader.h	Mon Jul 02 12:32:02 2018 +0200
@@ -26,16 +26,31 @@
 #include "../StoneEnumerations.h"
 
 #include <boost/shared_ptr.hpp>
+#include <boost/signals2.hpp>
 
 namespace OrthancStone
 {
-  class OrthancSlicesLoader : public boost::noncopyable
+  class OrthancSlicesLoader : public IWebService::IWebServiceObserver
   {
   public:
-    class ICallback : public boost::noncopyable
+    class IObserver : public boost::noncopyable
     {
     public:
-      virtual ~ICallback()
+      typedef boost::signals2::signal<void (const OrthancSlicesLoader& loader)> SignalGeometryReadyType;
+      typedef boost::signals2::signal<void (const OrthancSlicesLoader& loader)> SignalGeometryErrorType;
+      typedef boost::signals2::signal<void (const OrthancSlicesLoader& loader,
+                                            unsigned int sliceIndex,
+                                            const Slice& slice,
+                                            std::auto_ptr<Orthanc::ImageAccessor>& image,
+                                            SliceImageQuality effectiveQuality)> SignalSliceImageReadyType;
+      typedef boost::signals2::signal<void (const OrthancSlicesLoader& loader,
+                                            unsigned int sliceIndex,
+                                            const Slice& slice,
+                                            SliceImageQuality quality)> SignalSliceImageErrorType;
+
+
+    public:
+      virtual ~IObserver()
       {
       }
 
@@ -54,7 +69,13 @@
                                          const Slice& slice,
                                          SliceImageQuality quality) = 0;
     };
-    
+
+  private:
+    IObserver::SignalGeometryReadyType SignalGeometryReady;
+    IObserver::SignalGeometryErrorType SignalGeometryError;
+    IObserver::SignalSliceImageReadyType SignalSliceImageReady;
+    IObserver::SignalSliceImageErrorType SignalSliceImageError;
+
   private:
     enum State
     {
@@ -74,11 +95,12 @@
     };
 
     class Operation;
-    class WebCallback;
+    //class WebCallback;
 
-    boost::shared_ptr<WebCallback>  webCallback_;  // This is a PImpl pattern
+    //boost::shared_ptr<WebCallback>  webCallback_;  // This is a PImpl pattern
 
-    ICallback&    userCallback_;
+    //ICallback&    userCallback_;
+    boost::shared_ptr<OrthancSlicesLoader::IObserver> observer_;
     IWebService&  orthanc_;
     State         state_;
     SlicesSorter  slices_;
@@ -112,24 +134,24 @@
                             const void* answer,
                             size_t size);
 
-    void ScheduleSliceImagePng(const Slice& slice,
+    void ScheduleSliceImagePng(boost::shared_ptr<boost::noncopyable> tracker, const Slice& slice,
                                size_t index);
     
-    void ScheduleSliceImageJpeg(const Slice& slice,
+    void ScheduleSliceImageJpeg(boost::shared_ptr<boost::noncopyable> tracker, const Slice& slice,
                                 size_t index,
                                 SliceImageQuality quality);
 
     void SortAndFinalizeSlices();
     
   public:
-    OrthancSlicesLoader(ICallback& callback,
+    OrthancSlicesLoader(boost::shared_ptr<OrthancSlicesLoader::IObserver> observer,
                         IWebService& orthanc);
 
-    void ScheduleLoadSeries(const std::string& seriesId);
+    void ScheduleLoadSeries(boost::shared_ptr<boost::noncopyable> tracker, const std::string& seriesId);
 
-    void ScheduleLoadInstance(const std::string& instanceId);
+    void ScheduleLoadInstance(boost::shared_ptr<boost::noncopyable> tracker, const std::string& instanceId);
 
-    void ScheduleLoadFrame(const std::string& instanceId,
+    void ScheduleLoadFrame(boost::shared_ptr<boost::noncopyable> tracker, const std::string& instanceId,
                            unsigned int frame);
 
     bool IsGeometryReady() const;
@@ -141,7 +163,17 @@
     bool LookupSlice(size_t& index,
                      const CoordinateSystem3D& plane) const;
 
-    void ScheduleLoadSliceImage(size_t index,
+    void ScheduleLoadSliceImage(boost::shared_ptr<boost::noncopyable> tracker, size_t index,
                                 SliceImageQuality requestedQuality);
+
+
+    void OnRequestSuccess(const std::string& uri,
+                   const void* answer,
+                               size_t answerSize,
+                               Orthanc::IDynamicObject* payload);
+
+    void OnRequestError(const std::string& uri,
+                             Orthanc::IDynamicObject* payload);
+
   };
 }
--- a/Framework/Volumes/StructureSetLoader.cpp	Tue Jun 26 13:55:17 2018 +0200
+++ b/Framework/Volumes/StructureSetLoader.cpp	Mon Jul 02 12:32:02 2018 +0200
@@ -61,14 +61,14 @@
   };
 
 
-  void StructureSetLoader::NotifyError(const std::string& uri,
+  void StructureSetLoader::OnRequestError(const std::string& uri,
                                        Orthanc::IDynamicObject* payload)
   {
     // TODO
   }
 
   
-  void StructureSetLoader::NotifySuccess(const std::string& uri,
+  void StructureSetLoader::OnRequestSuccess(const std::string& uri,
                                          const void* answer,
                                          size_t answerSize,
                                          Orthanc::IDynamicObject* payload)
--- a/Framework/Volumes/StructureSetLoader.h	Tue Jun 26 13:55:17 2018 +0200
+++ b/Framework/Volumes/StructureSetLoader.h	Mon Jul 02 12:32:02 2018 +0200
@@ -29,15 +29,15 @@
 {
   class StructureSetLoader :
     public VolumeLoaderBase,
-    private IWebService::ICallback
+    private IWebService::IWebServiceObserver
   {
   private:
     class Operation;
     
-    virtual void NotifyError(const std::string& uri,
+    virtual void OnRequestError(const std::string& uri,
                              Orthanc::IDynamicObject* payload);
 
-    virtual void NotifySuccess(const std::string& uri,
+    virtual void OnRequestSuccess(const std::string& uri,
                                const void* answer,
                                size_t answerSize,
                                Orthanc::IDynamicObject* payload);
--- a/Framework/Widgets/LayerWidget.cpp	Tue Jun 26 13:55:17 2018 +0200
+++ b/Framework/Widgets/LayerWidget.cpp	Mon Jul 02 12:32:02 2018 +0200
@@ -36,7 +36,7 @@
     CoordinateSystem3D            slice_;
     double                        thickness_;
     size_t                        countMissing_;
-    std::vector<ILayerRenderer*>  renderers_;
+    std::vector<boost::shared_ptr<ILayerRenderer>>  renderers_;
 
     void DeleteLayer(size_t index)
     {
@@ -47,11 +47,10 @@
 
       assert(countMissing_ <= renderers_.size());
 
-      if (renderers_[index] != NULL)
+      if (renderers_[index].get() != NULL)
       {
         assert(countMissing_ < renderers_.size());
-        delete renderers_[index];
-        renderers_[index] = NULL;
+        renderers_[index].reset();
         countMissing_++;
       }
     }
@@ -63,7 +62,7 @@
       slice_(slice),
       thickness_(thickness),
       countMissing_(countLayers),
-      renderers_(countLayers, NULL)
+      renderers_(countLayers)
     {
       if (thickness <= 0)
       {
@@ -80,9 +79,9 @@
     }
 
     void SetLayer(size_t index,
-                  ILayerRenderer* renderer)  // Takes ownership
+                  boost::shared_ptr<ILayerRenderer> renderer)
     {
-      if (renderer == NULL)
+      if (renderer.get() == NULL)
       {
         throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer);
       }
@@ -100,7 +99,7 @@
 
     bool HasRenderer(size_t index)
     {
-      return renderers_[index] != NULL;
+      return renderers_[index].get() != NULL;
     }
 
     bool IsComplete() const
@@ -122,7 +121,7 @@
 
       for (size_t i = 0; i < renderers_.size(); i++)
       {
-        if (renderers_[i] != NULL)
+        if (renderers_[i].get() != NULL)
         {
           const CoordinateSystem3D& frameSlice = renderers_[i]->GetLayerSlice();
           
@@ -161,7 +160,7 @@
           cairo_restore(cr);
         }
 
-        if (renderers_[i] != NULL &&
+        if (renderers_[i].get() != NULL &&
             !renderers_[i]->IsFullQuality())
         {
           fullQuality = false;
@@ -196,7 +195,7 @@
     void SetLayerStyle(size_t index,
                        const RenderStyle& style)
     {
-      if (renderers_[index] != NULL)
+      if (renderers_[index].get() != NULL)
       {
         renderers_[index]->SetLayerStyle(style);
       }
@@ -245,7 +244,7 @@
     {
       index = found->second;
       assert(index < layers_.size() &&
-             layers_[index] == &layer);
+             layers_[index].get() == &layer);
       return true;
     }
   }
@@ -317,14 +316,12 @@
   
 
   void LayerWidget::UpdateLayer(size_t index,
-                                ILayerRenderer* renderer,
+                                boost::shared_ptr<ILayerRenderer> renderer,
                                 const CoordinateSystem3D& slice)
   {
     LOG(INFO) << "Updating layer " << index;
     
-    std::auto_ptr<ILayerRenderer> tmp(renderer);
-
-    if (renderer == NULL)
+    if (renderer.get() == NULL)
     {
       throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer);
     }
@@ -340,13 +337,13 @@
     if (currentScene_.get() != NULL &&
         currentScene_->ContainsPlane(slice))
     {
-      currentScene_->SetLayer(index, tmp.release());
+      currentScene_->SetLayer(index, renderer);
       NotifyChange();
     }
     else if (pendingScene_.get() != NULL &&
              pendingScene_->ContainsPlane(slice))
     {
-      pendingScene_->SetLayer(index, tmp.release());
+      pendingScene_->SetLayer(index, renderer);
 
       if (currentScene_.get() == NULL ||
           !currentScene_->IsComplete() ||
@@ -370,14 +367,14 @@
   {
     for (size_t i = 0; i < layers_.size(); i++)
     {
-      delete layers_[i];
+      layers_[i].reset();
     }
   }
   
 
-  size_t LayerWidget::AddLayer(ILayerSource* layer)  // Takes ownership
+  size_t LayerWidget::AddLayer(boost::shared_ptr<ILayerSource> layer)
   {
-    if (layer == NULL)
+    if (layer.get() == NULL)
     {
       throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer);
     }
@@ -385,19 +382,19 @@
     size_t index = layers_.size();
     layers_.push_back(layer);
     styles_.push_back(RenderStyle());
-    layersIndex_[layer] = index;
+    layersIndex_[layer.get()] = index;
 
     ResetPendingScene();
-    layer->Register(*this);
+    layer->Register(reinterpret_cast<boost::enable_shared_from_this<ILayerSource::IObserver>&>(*this).shared_from_this());
 
     ResetChangedLayers();
 
     return index;
   }
 
-  void LayerWidget::ReplaceLayer(size_t index, ILayerSource* layer)  // Takes ownership
+  void LayerWidget::ReplaceLayer(size_t index, boost::shared_ptr<ILayerSource> layer)
   {
-    if (layer == NULL)
+    if (layer.get() == NULL)
     {
       throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer);
     }
@@ -407,12 +404,11 @@
       throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
     }
 
-    delete layers_[index];
-    layers_[index] = layer;
-    layersIndex_[layer] = index;
+    layers_[index]= layer;
+    layersIndex_[layer.get()] = index;
 
     ResetPendingScene();
-    layer->Register(*this);
+    layer->Register(shared_from_this());
 
     InvalidateLayer(index);
   }
@@ -549,7 +545,7 @@
   }
   
   
-  void LayerWidget::NotifyLayerReady(std::auto_ptr<ILayerRenderer>& renderer,
+  void LayerWidget::NotifyLayerReady(boost::shared_ptr<ILayerRenderer> renderer,
                                      const ILayerSource& source,
                                      const CoordinateSystem3D& slice,
                                      bool isError)
@@ -566,9 +562,10 @@
         LOG(INFO) << "Renderer ready for layer " << index;
       }
       
-      if (renderer.get() != NULL)
+      if (renderer)
       {
-        UpdateLayer(index, renderer.release(), slice);
+        UpdateLayer(index, renderer, slice);
+        //delete renderer; // TODO: find a better way to handle lifecycle !
       }
       else if (isError)
       {
--- a/Framework/Widgets/LayerWidget.h	Tue Jun 26 13:55:17 2018 +0200
+++ b/Framework/Widgets/LayerWidget.h	Mon Jul 02 12:32:02 2018 +0200
@@ -24,6 +24,7 @@
 #include "WorldSceneWidget.h"
 #include "../Layers/ILayerSource.h"
 #include "../Toolbox/Extent2D.h"
+#include <boost/enable_shared_from_this.hpp>
 
 #include <map>
 
@@ -31,7 +32,10 @@
 {
   class LayerWidget :
     public WorldSceneWidget,
-    private ILayerSource::IObserver
+    public ILayerSource::IObserver,
+    public boost::enable_shared_from_this<ILayerSource::IObserver>
+      //public boost::enable_shared_from_this<LayerWidget>
+
   {
   private:
     class Scene;
@@ -40,7 +44,7 @@
 
     bool                        started_;
     LayersIndex                 layersIndex_;
-    std::vector<ILayerSource*>  layers_;
+    std::vector<boost::shared_ptr<ILayerSource>>  layers_;
     std::vector<RenderStyle>    styles_;
     CoordinateSystem3D          slice_;
     std::auto_ptr<Scene>        currentScene_;
@@ -62,7 +66,7 @@
     virtual void NotifySliceChange(const ILayerSource& source,
                                    const Slice& slice);
 
-    virtual void NotifyLayerReady(std::auto_ptr<ILayerRenderer>& renderer,
+    virtual void NotifyLayerReady(boost::shared_ptr<ILayerRenderer> renderer,
                                   const ILayerSource& source,
                                   const CoordinateSystem3D& slice,
                                   bool isError);
@@ -79,7 +83,7 @@
     void ResetPendingScene();
 
     void UpdateLayer(size_t index,
-                     ILayerRenderer* renderer,
+                     boost::shared_ptr<ILayerRenderer>  renderer,
                      const CoordinateSystem3D& slice);
 
     void InvalidateAllLayers();
@@ -91,9 +95,9 @@
 
     virtual ~LayerWidget();
 
-    size_t AddLayer(ILayerSource* layer);  // Takes ownership
+    size_t AddLayer(boost::shared_ptr<ILayerSource> layer);
 
-    void ReplaceLayer(size_t layerIndex, ILayerSource* layer); // Takes ownership
+    void ReplaceLayer(size_t layerIndex, boost::shared_ptr<ILayerSource> layer); // Takes ownership
 
     size_t GetLayerCount() const
     {
--- a/Framework/dev.h	Tue Jun 26 13:55:17 2018 +0200
+++ b/Framework/dev.h	Mon Jul 02 12:32:02 2018 +0200
@@ -43,10 +43,10 @@
   // TODO: Handle errors while loading
   class OrthancVolumeImage : 
     public SlicedVolumeBase,
-    private OrthancSlicesLoader::ICallback
+    public OrthancSlicesLoader::IObserver
   { 
   private:
-    OrthancSlicesLoader           loader_;
+    boost::shared_ptr<OrthancSlicesLoader> loader_;
     std::auto_ptr<ImageBuffer3D>  image_;
     std::auto_ptr<DownloadStack>  downloadStack_;
     bool                          computeRange_;
@@ -59,7 +59,7 @@
       unsigned int slice;
       if (downloadStack_->Pop(slice))
       {
-        loader_.ScheduleLoadSliceImage(slice, SliceImageQuality_Jpeg90);
+        loader_->ScheduleLoadSliceImage(loader_, slice, SliceImageQuality_Jpeg90);
       }
     }
 
@@ -217,36 +217,36 @@
   public:
     OrthancVolumeImage(IWebService& orthanc,
                        bool computeRange) : 
-      loader_(*this, orthanc),
       computeRange_(computeRange),
       pendingSlices_(0)
     {
+        loader_.reset(new OrthancSlicesLoader(boost::shared_ptr<OrthancSlicesLoader::IObserver>(this), orthanc));
     }
 
     void ScheduleLoadSeries(const std::string& seriesId)
     {
-      loader_.ScheduleLoadSeries(seriesId);
+      loader_->ScheduleLoadSeries(loader_, seriesId);
     }
 
     void ScheduleLoadInstance(const std::string& instanceId)
     {
-      loader_.ScheduleLoadInstance(instanceId);
+      loader_->ScheduleLoadInstance(loader_, instanceId);
     }
 
     void ScheduleLoadFrame(const std::string& instanceId,
                            unsigned int frame)
     {
-      loader_.ScheduleLoadFrame(instanceId, frame);
+      loader_->ScheduleLoadFrame(loader_, instanceId, frame);
     }
 
     virtual size_t GetSliceCount() const
     {
-      return loader_.GetSliceCount();
+      return loader_->GetSliceCount();
     }
 
     virtual const Slice& GetSlice(size_t index) const
     {
-      return loader_.GetSlice(index);
+      return loader_->GetSlice(index);
     }
 
     ImageBuffer3D& GetImage() const
@@ -629,8 +629,8 @@
           }
 
           std::auto_ptr<Slice> slice(geometry.GetSlice(closest));
-          LayerSourceBase::NotifyLayerReady(
-            FrameRenderer::CreateRenderer(frame.release(), *slice, isFullQuality),
+          LayerSourceBase::NotifyLayerReady(boost::shared_ptr<ILayerRenderer>(
+            FrameRenderer::CreateRenderer(frame.release(), *slice, isFullQuality)),
             //new SliceOutlineRenderer(slice),
             slice->GetGeometry(), false);
           return;
@@ -855,7 +855,7 @@
                                                  extent.GetX1(), extent.GetY1(),
                                                  extent.GetX2(), extent.GetY2()))
         {
-          NotifyLayerReady(new LineLayerRenderer(x1, y1, x2, y2, slice), reference.GetGeometry(), false);
+          NotifyLayerReady(boost::shared_ptr<ILayerRenderer>(new LineLayerRenderer(x1, y1, x2, y2, slice)), reference.GetGeometry(), false);
         }
         else
         {
--- a/Platforms/Generic/OracleWebService.h	Tue Jun 26 13:55:17 2018 +0200
+++ b/Platforms/Generic/OracleWebService.h	Mon Jul 02 12:32:02 2018 +0200
@@ -42,20 +42,22 @@
     {
     }
 
-    virtual void ScheduleGetRequest(ICallback& callback,
+    virtual void ScheduleGetRequest(IWebServiceObserver* observer,
+                                    boost::shared_ptr<boost::noncopyable> tracker,
                                     const std::string& uri,
                                     Orthanc::IDynamicObject* payload)
     {
 
-      oracle_.Submit(new WebServiceGetCommand(callback, parameters_, uri, payload));
+      oracle_.Submit(new WebServiceGetCommand(observer, tracker, parameters_, uri, payload));
     }
 
-    virtual void SchedulePostRequest(ICallback& callback,
+    virtual void SchedulePostRequest(IWebServiceObserver* observer,
+                                     boost::shared_ptr<boost::noncopyable> tracker,
                                      const std::string& uri,
                                      const std::string& body,
                                      Orthanc::IDynamicObject* payload)
     {
-      oracle_.Submit(new WebServicePostCommand(callback, parameters_, uri, body, payload));
+      oracle_.Submit(new WebServicePostCommand(observer, tracker, parameters_, uri, body, payload));
     }
 
     void Start()
--- a/Platforms/Generic/WebServiceGetCommand.cpp	Tue Jun 26 13:55:17 2018 +0200
+++ b/Platforms/Generic/WebServiceGetCommand.cpp	Mon Jul 02 12:32:02 2018 +0200
@@ -25,16 +25,18 @@
 
 namespace OrthancStone
 {
-  WebServiceGetCommand::WebServiceGetCommand(IWebService::ICallback& callback,
-                                             const Orthanc::WebServiceParameters& parameters,
+  WebServiceGetCommand::WebServiceGetCommand(IWebService::IWebServiceObserver* observer,
+                                             boost::shared_ptr<boost::noncopyable> tracker,const Orthanc::WebServiceParameters& parameters,
                                              const std::string& uri,
                                              Orthanc::IDynamicObject* payload /* takes ownership */) :
-    callback_(callback),
+    observer_(observer),
     parameters_(parameters),
     uri_(uri),
     payload_(payload)
   {
-    //SignalSuccess.connect(boost::bind(&IWebService::ICallback::NotifySuccess, callback, _1, _2, _3, _4));
+    // connect the signals and track the deletion of the observer
+    SignalSuccess.connect(IWebService::IWebServiceObserver::SignalSuccessType::slot_type(&IWebService::IWebServiceObserver::OnRequestSuccess, observer_, _1, _2, _3, _4).track(tracker));
+    SignalError.connect(IWebService::IWebServiceObserver::SignalErrorType::slot_type(&IWebService::IWebServiceObserver::OnRequestError, observer_, _1, _2).track(tracker));
   }
 
 
@@ -52,11 +54,10 @@
     if (success_)
     {
       SignalSuccess(uri_, answer_.c_str(), answer_.size(), payload_.release());
-      //callback_.NotifySuccess(uri_, answer_.c_str(), answer_.size(), payload_.release());
     }
     else
     {
-      callback_.NotifyError(uri_, payload_.release());
+      SignalError(uri_, payload_.release());
     }
   }
 }
--- a/Platforms/Generic/WebServiceGetCommand.h	Tue Jun 26 13:55:17 2018 +0200
+++ b/Platforms/Generic/WebServiceGetCommand.h	Mon Jul 02 12:32:02 2018 +0200
@@ -35,7 +35,7 @@
   class WebServiceGetCommand : public IOracleCommand
   {
   private:
-    IWebService::ICallback&                 callback_;
+    IWebService::IWebServiceObserver*       observer_;
     Orthanc::WebServiceParameters           parameters_;
     std::string                             uri_;
     std::auto_ptr<Orthanc::IDynamicObject>  payload_;
@@ -43,7 +43,8 @@
     std::string                             answer_;
 
   public:
-    WebServiceGetCommand(IWebService::ICallback& callback,
+    WebServiceGetCommand(IWebService::IWebServiceObserver* observer,
+                         boost::shared_ptr<boost::noncopyable> tracker,
                          const Orthanc::WebServiceParameters& parameters,
                          const std::string& uri,
                          Orthanc::IDynamicObject* payload /* takes ownership */);
@@ -52,10 +53,10 @@
 
     virtual void Commit();
 
-    boost::signals2::signal<void (const std::string& uri,
-                                  const void* answer,
-                                  size_t answerSize,
-                                  Orthanc::IDynamicObject* payload)> SignalSuccess;
+  private:
+
+    IWebService::IWebServiceObserver::SignalSuccessType SignalSuccess;
+    IWebService::IWebServiceObserver::SignalErrorType SignalError;
 
   };
 }
--- a/Platforms/Generic/WebServicePostCommand.cpp	Tue Jun 26 13:55:17 2018 +0200
+++ b/Platforms/Generic/WebServicePostCommand.cpp	Mon Jul 02 12:32:02 2018 +0200
@@ -25,17 +25,21 @@
 
 namespace OrthancStone
 {
-  WebServicePostCommand::WebServicePostCommand(IWebService::ICallback& callback,
+  WebServicePostCommand::WebServicePostCommand(IWebService::IWebServiceObserver* observer,
+                                               boost::shared_ptr<boost::noncopyable> tracker,
                                                const Orthanc::WebServiceParameters& parameters,
                                                const std::string& uri,
                                                const std::string& body,
                                                Orthanc::IDynamicObject* payload /* takes ownership */) :
-    callback_(callback),
+    observer_(observer),
     parameters_(parameters),
     uri_(uri),
     body_(body),
     payload_(payload)
   {
+    // connect the signals and track the deletion of the observer
+    SignalSuccess.connect(IWebService::IWebServiceObserver::SignalSuccessType::slot_type(&IWebService::IWebServiceObserver::OnRequestSuccess, observer_, _1, _2, _3, _4).track(tracker));
+    SignalError.connect(IWebService::IWebServiceObserver::SignalErrorType::slot_type(&IWebService::IWebServiceObserver::OnRequestError, observer_, _1, _2).track(tracker));
   }
 
   void WebServicePostCommand::Execute()
@@ -51,11 +55,11 @@
   {
     if (success_)
     {
-      callback_.NotifySuccess(uri_, answer_.c_str(), answer_.size(), payload_.release());
+      SignalSuccess(uri_, answer_.c_str(), answer_.size(), payload_.release());
     }
     else
     {
-      callback_.NotifyError(uri_, payload_.release());
+      SignalError(uri_, payload_.release());
     }
   }
 }
--- a/Platforms/Generic/WebServicePostCommand.h	Tue Jun 26 13:55:17 2018 +0200
+++ b/Platforms/Generic/WebServicePostCommand.h	Mon Jul 02 12:32:02 2018 +0200
@@ -34,7 +34,7 @@
   class WebServicePostCommand : public IOracleCommand
   {
   private:
-    IWebService::ICallback&                 callback_;
+    IWebService::IWebServiceObserver*       observer_;
     Orthanc::WebServiceParameters           parameters_;
     std::string                             uri_;
     std::string                             body_;
@@ -43,7 +43,8 @@
     std::string                             answer_;
 
   public:
-    WebServicePostCommand(IWebService::ICallback& callback,
+    WebServicePostCommand(IWebService::IWebServiceObserver* observer,
+                          boost::shared_ptr<boost::noncopyable> tracker,
                           const Orthanc::WebServiceParameters& parameters,
                           const std::string& uri,
                           const std::string& body,
@@ -52,5 +53,10 @@
     virtual void Execute();
 
     virtual void Commit();
+
+  private:
+
+    IWebService::IWebServiceObserver::SignalSuccessType SignalSuccess;
+    IWebService::IWebServiceObserver::SignalErrorType SignalError;
   };
 }
--- a/Platforms/Wasm/WasmWebService.cpp	Tue Jun 26 13:55:17 2018 +0200
+++ b/Platforms/Wasm/WasmWebService.cpp	Mon Jul 02 12:32:02 2018 +0200
@@ -16,35 +16,35 @@
                                                  size_t bodySize,
                                                  void* payload);
 
-  void EMSCRIPTEN_KEEPALIVE WasmWebService_NotifyError(void* callback,
+  void EMSCRIPTEN_KEEPALIVE WasmWebService_NotifyError(void* observer,
                                                        const char* uri,
                                                        void* payload)
   {
-    if (callback == NULL)
+    if (observer == NULL)
     {
       throw;
     }
     else
     {
-      reinterpret_cast<OrthancStone::IWebService::ICallback*>(callback)->
-        NotifyError(uri, reinterpret_cast<Orthanc::IDynamicObject*>(payload));
+      reinterpret_cast<OrthancStone::IWebService::IWebServiceObserver*>(observer)->
+        OnRequestError(uri, reinterpret_cast<Orthanc::IDynamicObject*>(payload));
     }
   }
 
-  void EMSCRIPTEN_KEEPALIVE WasmWebService_NotifySuccess(void* callback,
+  void EMSCRIPTEN_KEEPALIVE WasmWebService_NotifySuccess(void* observer,
                                                          const char* uri,
                                                          const void* body,
                                                          size_t bodySize,
                                                          void* payload)
   {
-    if (callback == NULL)
+    if (observer == NULL)
     {
       throw;
     }
     else
     {
-      reinterpret_cast<OrthancStone::IWebService::ICallback*>(callback)->
-        NotifySuccess(uri, body, bodySize, reinterpret_cast<Orthanc::IDynamicObject*>(payload)); 
+      reinterpret_cast<OrthancStone::IWebService::IWebServiceObserver*>(observer)->
+        OnRequestSuccess(uri, body, bodySize, reinterpret_cast<Orthanc::IDynamicObject*>(payload)); 
    }
   }
 
@@ -75,21 +75,23 @@
     }
   }
 
-  void WasmWebService::ScheduleGetRequest(ICallback& callback,
+  void WasmWebService::ScheduleGetRequest(IWebServiceObserver* observer,
+                                          boost::shared_ptr<boost::noncopyable> tracker,
                                           const std::string& uri,
                                           Orthanc::IDynamicObject* payload)
   {
     std::string url = base_ + uri;
-    WasmWebService_ScheduleGetRequest(&callback, url.c_str(), payload);
+    WasmWebService_ScheduleGetRequest(observer, url.c_str(), payload);
   }
 
-  void WasmWebService::SchedulePostRequest(ICallback& callback,
+  void WasmWebService::SchedulePostRequest(IWebServiceObserver* observer,
+                                           boost::shared_ptr<boost::noncopyable> tracker,
                                            const std::string& uri,
                                            const std::string& body,
                                            Orthanc::IDynamicObject* payload)
   {
     std::string url = base_ + uri;
-    WasmWebService_SchedulePostRequest(&callback, url.c_str(),
+    WasmWebService_SchedulePostRequest(observer, url.c_str(),
                                        body.c_str(), body.size(), payload);
   }
 }
--- a/Platforms/Wasm/WasmWebService.h	Tue Jun 26 13:55:17 2018 +0200
+++ b/Platforms/Wasm/WasmWebService.h	Mon Jul 02 12:32:02 2018 +0200
@@ -24,11 +24,13 @@
 
     void SetBaseUrl(const std::string base);
 
-    virtual void ScheduleGetRequest(ICallback& callback,
+    virtual void ScheduleGetRequest(IWebServiceObserver* observer,
+                                    boost::shared_ptr<boost::noncopyable> tracker,
                                     const std::string& uri,
                                     Orthanc::IDynamicObject* payload);
 
-    virtual void SchedulePostRequest(ICallback& callback,
+    virtual void SchedulePostRequest(IWebServiceObserver* observer,
+                                     boost::shared_ptr<boost::noncopyable> tracker,
                                      const std::string& uri,
                                      const std::string& body,
                                      Orthanc::IDynamicObject* payload);
--- a/Resources/CMake/OrthancStoneConfiguration.cmake	Tue Jun 26 13:55:17 2018 +0200
+++ b/Resources/CMake/OrthancStoneConfiguration.cmake	Mon Jul 02 12:32:02 2018 +0200
@@ -175,6 +175,7 @@
   ${ORTHANC_STONE_ROOT}/Framework/Layers/DicomStructureSetRendererFactory.cpp
   ${ORTHANC_STONE_ROOT}/Framework/Layers/FrameRenderer.cpp
   ${ORTHANC_STONE_ROOT}/Framework/Layers/GrayscaleFrameRenderer.cpp
+  ${ORTHANC_STONE_ROOT}/Framework/Layers/ILayerSource.h
   ${ORTHANC_STONE_ROOT}/Framework/Layers/LayerSourceBase.cpp
   ${ORTHANC_STONE_ROOT}/Framework/Layers/LineLayerRenderer.cpp
   ${ORTHANC_STONE_ROOT}/Framework/Layers/LineMeasureTracker.cpp
@@ -206,7 +207,7 @@
   ${ORTHANC_STONE_ROOT}/Framework/Viewport/WidgetViewport.cpp
   ${ORTHANC_STONE_ROOT}/Framework/Volumes/ImageBuffer3D.cpp
   ${ORTHANC_STONE_ROOT}/Framework/Volumes/SlicedVolumeBase.cpp
-  ${ORTHANC_STONE_ROOT}/Framework/Volumes/StructureSetLoader.cpp
+#  ${ORTHANC_STONE_ROOT}/Framework/Volumes/StructureSetLoader.cpp
   ${ORTHANC_STONE_ROOT}/Framework/Volumes/VolumeLoaderBase.cpp
   ${ORTHANC_STONE_ROOT}/Framework/Volumes/VolumeReslicer.cpp
   ${ORTHANC_STONE_ROOT}/Framework/Widgets/CairoWidget.cpp