changeset 405:3942123602ba

removing ObserversRegistry
author Sebastien Jodogne <s.jodogne@gmail.com>
date Sun, 11 Nov 2018 17:50:11 +0100
parents ba4ace20454e
children 5d359b115b29
files Framework/StoneEnumerations.h Framework/Toolbox/ObserversRegistry.h Framework/Volumes/ISlicedVolume.h Framework/Volumes/SlicedVolumeBase.cpp Framework/Volumes/SlicedVolumeBase.h Framework/dev.h Resources/CMake/OrthancStoneConfiguration.cmake UnitTestsSources/UnitTestsMain.cpp
diffstat 8 files changed, 97 insertions(+), 292 deletions(-) [+]
line wrap: on
line diff
--- a/Framework/StoneEnumerations.h	Sun Nov 11 13:02:38 2018 +0100
+++ b/Framework/StoneEnumerations.h	Sun Nov 11 17:50:11 2018 +0100
@@ -140,6 +140,12 @@
     MessageType_VolumeLoader_GeometryError,
     MessageType_VolumeLoader_ContentChanged,  // Content of several slices in the loader has changed
 
+    MessageType_SlicedVolume_GeometryReady,
+    MessageType_SlicedVolume_GeometryError,
+    MessageType_SlicedVolume_VolumeReady,
+    MessageType_SlicedVolume_ContentChanged,
+    MessageType_SlicedVolume_SliceContentChanged,
+
     MessageType_HttpRequestSuccess,
     MessageType_HttpRequestError,
 
--- a/Framework/Toolbox/ObserversRegistry.h	Sun Nov 11 13:02:38 2018 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,105 +0,0 @@
-/**
- * Stone of Orthanc
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2018 Osimis S.A., Belgium
- *
- * This program is free software: you can redistribute it and/or
- * modify it under the terms of the GNU Affero General Public License
- * as published by the Free Software Foundation, either version 3 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Affero General Public License for more details.
- * 
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- **/
-
-
-#pragma once
-
-#include <Core/OrthancException.h>
-
-#include <boost/noncopyable.hpp>
-#include <set>
-
-namespace OrthancStone
-{
-  template <
-    typename Source,
-    typename Observer = typename Source::IObserver
-    >
-  class ObserversRegistry : public boost::noncopyable
-  {
-  private:
-    typedef std::set<Observer*>  Observers;
-
-    Observers  observers_;
-
-  public:
-    template <typename Functor>
-    void Notify(const Source& source,
-                Functor& functor)
-    {
-      for (typename Observers::const_iterator observer = observers_.begin();
-           observer != observers_.end(); ++observer)
-      {
-        functor(**observer, source);
-      }
-    }
-
-    void Register(Observer& observer)
-    {
-      observers_.insert(&observer);
-    }
-
-    void Unregister(Observer& observer)
-    {
-      observers_.erase(&observer);
-    }
-
-    bool IsEmpty()
-    {
-      return observers_.empty();
-    }
-
-    void Apply(const Source& source,
-               void (Observer::*method) (const Source&))
-    {
-      for (typename Observers::const_iterator it = observers_.begin();
-           it != observers_.end(); ++it)
-      {
-        ((*it)->*method) (source);
-      }
-    }
-
-    template <typename Argument0>
-    void Apply(const Source& source,
-               void (Observer::*method) (const Source&, const Argument0&),
-               const Argument0& argument0)
-    {
-      for (typename Observers::const_iterator it = observers_.begin();
-           it != observers_.end(); ++it)
-      {
-        ((*it)->*method) (source, argument0);
-      }
-    }
-
-    template <typename Argument0,
-              typename Argument1>
-    void Apply(const Source& source,
-               void (Observer::*method) (const Source&, const Argument0&, const Argument1&),
-               const Argument0& argument0,
-               const Argument1& argument1)
-    {
-      for (typename Observers::const_iterator it = observers_.begin();
-           it != observers_.end(); ++it)
-      {
-        ((*it)->*method) (source, argument0, argument1);
-      }
-    }
-  };
-}
--- a/Framework/Volumes/ISlicedVolume.h	Sun Nov 11 13:02:38 2018 +0100
+++ b/Framework/Volumes/ISlicedVolume.h	Sun Nov 11 17:50:11 2018 +0100
@@ -21,44 +21,53 @@
 
 #pragma once
 
+#include "../Messages/IObservable.h"
 #include "../Toolbox/Slice.h"
 
 namespace OrthancStone
 {
-  class ISlicedVolume : public boost::noncopyable
+  class ISlicedVolume : public IObservable
   {
   public:
-    class IObserver : public boost::noncopyable
+    typedef OriginMessage<MessageType_SlicedVolume_ContentChanged, ISlicedVolume> ContentChangedMessage;
+    typedef OriginMessage<MessageType_SlicedVolume_GeometryError, ISlicedVolume> GeometryErrorMessage;
+    typedef OriginMessage<MessageType_SlicedVolume_GeometryReady, ISlicedVolume> GeometryReadyMessage;
+    typedef OriginMessage<MessageType_SlicedVolume_VolumeReady, ISlicedVolume> VolumeReadyMessage;
+
+    class SliceContentChangedMessage :
+      public OriginMessage<MessageType_SlicedVolume_SliceContentChanged, ISlicedVolume>
     {
+    private:
+      size_t        sliceIndex_;
+      const Slice&  slice_;
+      
     public:
-      virtual ~IObserver()
+      SliceContentChangedMessage(ISlicedVolume& origin,
+                                 size_t sliceIndex,
+                                 const Slice& slice) :
+        OriginMessage(origin),
+        sliceIndex_(sliceIndex),
+        slice_(slice)
       {
       }
 
-      virtual void NotifyGeometryReady(const ISlicedVolume& volume) = 0;
-      
-      virtual void NotifyGeometryError(const ISlicedVolume& volume) = 0;
-      
-      // Triggered if the content of several slices in the volume has
-      // changed
-      virtual void NotifyContentChange(const ISlicedVolume& volume) = 0;
+      size_t GetSliceIndex() const
+      {
+        return sliceIndex_;
+      }
 
-      // Triggered if the content of some individual slice in the
-      // source volume has changed
-      virtual void NotifySliceContentChange(const ISlicedVolume& volume,
-                                     const size_t& sliceIndex,
-                                     const Slice& slice) = 0;
+      const Slice& GetSlice() const
+      {
+        return slice_;
+      }
+    };
 
-      // Triggered when the geometry *and* the content of the volume are available
-      virtual void NotifyVolumeReady(const ISlicedVolume& volume) = 0;
-    };
-    
-    virtual ~ISlicedVolume()
+
+    ISlicedVolume(MessageBroker& broker) :
+      IObservable(broker)
     {
     }
-
-    virtual void Register(IObserver& observer) = 0;
-
+    
     virtual size_t GetSliceCount() const = 0;
 
     virtual const Slice& GetSlice(size_t slice) const = 0;
--- a/Framework/Volumes/SlicedVolumeBase.cpp	Sun Nov 11 13:02:38 2018 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,51 +0,0 @@
-/**
- * Stone of Orthanc
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2018 Osimis S.A., Belgium
- *
- * This program is free software: you can redistribute it and/or
- * modify it under the terms of the GNU Affero General Public License
- * as published by the Free Software Foundation, either version 3 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Affero General Public License for more details.
- * 
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- **/
-
-
-#include "SlicedVolumeBase.h"
-
-namespace OrthancStone
-{
-  void SlicedVolumeBase::NotifyGeometryReady()
-  {
-    observers_.Apply(*this, &IObserver::NotifyGeometryReady);
-  }
-      
-  void SlicedVolumeBase::NotifyGeometryError()
-  {
-    observers_.Apply(*this, &IObserver::NotifyGeometryError);
-  }
-    
-  void SlicedVolumeBase::NotifyContentChange()
-  {
-    observers_.Apply(*this, &IObserver::NotifyContentChange);
-  }
-
-  void SlicedVolumeBase::NotifySliceContentChange(const size_t& sliceIndex,
-                                           const Slice& slice)
-  {
-    observers_.Apply(*this, &IObserver::NotifySliceContentChange, sliceIndex, slice);
-  }
-
-  void SlicedVolumeBase::NotifyVolumeReady()
-  {
-    observers_.Apply(*this, &IObserver::NotifyVolumeReady);
-  }
-}
--- a/Framework/Volumes/SlicedVolumeBase.h	Sun Nov 11 13:02:38 2018 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,54 +0,0 @@
-/**
- * Stone of Orthanc
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2018 Osimis S.A., Belgium
- *
- * This program is free software: you can redistribute it and/or
- * modify it under the terms of the GNU Affero General Public License
- * as published by the Free Software Foundation, either version 3 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Affero General Public License for more details.
- * 
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- **/
-
-
-#pragma once
-
-#include "ISlicedVolume.h"
-#include "../Toolbox/ObserversRegistry.h"
-
-namespace OrthancStone
-{
-  class SlicedVolumeBase : public ISlicedVolume
-  {
-  private:
-    typedef ObserversRegistry<ISlicedVolume, IObserver>  Observers;
-
-    Observers  observers_;
-
-  protected:
-    virtual void NotifyGeometryReady();
-      
-    virtual void NotifyGeometryError();
-    
-    virtual void NotifyContentChange();
-
-    virtual void NotifySliceContentChange(const size_t& sliceIndex,
-                                   const Slice& slice);
-
-    virtual void NotifyVolumeReady();
-
-  public:
-    virtual void Register(IObserver& observer)
-    {
-      observers_.Register(observer);
-    }
-  };
-}
--- a/Framework/dev.h	Sun Nov 11 13:02:38 2018 +0100
+++ b/Framework/dev.h	Sun Nov 11 17:50:11 2018 +0100
@@ -28,11 +28,12 @@
 #include "Toolbox/GeometryToolbox.h"
 #include "Toolbox/OrthancSlicesLoader.h"
 #include "Volumes/ImageBuffer3D.h"
-#include "Volumes/SlicedVolumeBase.h"
+#include "Volumes/ISlicedVolume.h"
 #include "Widgets/SliceViewerWidget.h"
 
 #include <Core/Logging.h>
 #include <Core/Images/ImageProcessing.h>
+#include <Core/OrthancException.h>
 
 #include <boost/math/special_functions/round.hpp>
 
@@ -41,8 +42,8 @@
 {
   // TODO: Handle errors while loading
   class OrthancVolumeImage :
-    public SlicedVolumeBase,
-    public OrthancStone::IObserver
+    public ISlicedVolume,
+    public IObserver
   {
   private:
     OrthancSlicesLoader           loader_;
@@ -110,7 +111,7 @@
       if (loader.GetSliceCount() == 0)
       {
         LOG(ERROR) << "Empty volume image";
-        SlicedVolumeBase::NotifyGeometryError();
+        EmitMessage(ISlicedVolume::GeometryErrorMessage(*this));
         return;
       }
 
@@ -118,7 +119,7 @@
       {
         if (!IsCompatible(loader.GetSlice(0), loader.GetSlice(i)))
         {
-          SlicedVolumeBase::NotifyGeometryError();
+          EmitMessage(ISlicedVolume::GeometryErrorMessage(*this));
           return;
         }
       }
@@ -142,7 +143,7 @@
                                    0.001 /* this is expressed in mm */))
         {
           LOG(ERROR) << "The distance between successive slices is not constant in a volume image";
-          SlicedVolumeBase::NotifyGeometryError();
+          EmitMessage(ISlicedVolume::GeometryErrorMessage(*this));
           return;
         }
       }
@@ -169,25 +170,25 @@
 
       // TODO Check the DicomFrameConverter are constant
 
-      SlicedVolumeBase::NotifyGeometryReady();
+      EmitMessage(ISlicedVolume::GeometryReadyMessage(*this));
     }
 
-    virtual void OnSliceImageReady(const OrthancSlicesLoader& loader,
-                                   unsigned int sliceIndex,
-                                   const Slice& slice,
-                                   const Orthanc::ImageAccessor& image,
-                                   SliceImageQuality quality)
+    void OnSliceImageReady(const OrthancSlicesLoader& loader,
+                           unsigned int sliceIndex,
+                           const Slice& slice,
+                           const Orthanc::ImageAccessor& image,
+                           SliceImageQuality quality)
     {
       {
         ImageBuffer3D::SliceWriter writer(*image_, VolumeProjection_Axial, sliceIndex);
         Orthanc::ImageProcessing::Copy(writer.GetAccessor(), image);
       }
 
-      SlicedVolumeBase::NotifySliceContentChange(sliceIndex, slice);
+      EmitMessage(ISlicedVolume::SliceContentChangedMessage(*this, sliceIndex, slice));
 
       if (pendingSlices_ == 1)
       {
-        SlicedVolumeBase::NotifyVolumeReady();
+        EmitMessage(ISlicedVolume::VolumeReadyMessage(*this));
         pendingSlices_ = 0;
       }
       else if (pendingSlices_ > 1)
@@ -208,7 +209,7 @@
         
         case MessageType_SliceLoader_GeometryError:
           LOG(ERROR) << "Unable to download a volume image";
-          SlicedVolumeBase::NotifyGeometryError();
+          EmitMessage(ISlicedVolume::GeometryErrorMessage(*this));
           break;
         
         case MessageType_SliceLoader_ImageReady:
@@ -241,7 +242,8 @@
     OrthancVolumeImage(MessageBroker& broker,
                        OrthancApiClient& orthanc,
                        bool computeRange) :
-      OrthancStone::IObserver(broker),
+      ISlicedVolume(broker),
+      IObserver(broker),
       loader_(broker, orthanc),
       computeRange_(computeRange),
       pendingSlices_(0)
@@ -495,7 +497,7 @@
 
   class VolumeImageMPRSlicer :
     public IVolumeSlicer,
-    private ISlicedVolume::IObserver
+    public IObserver
   {
   private:
     class RendererFactory : public LayerReadyMessage::IRendererFactory
@@ -532,10 +534,11 @@
     {
       return axialGeometry_.get() != NULL;
     }
-
     
-    virtual void NotifyGeometryReady(const ISlicedVolume& volume) ORTHANC_OVERRIDE
+    void OnGeometryReady(const ISlicedVolume::GeometryReadyMessage& message)
     {
+      assert(&message.GetOrigin() == &volume_);
+      
       // These 3 values are only used to speed up the IVolumeSlicer
       axialGeometry_.reset(new VolumeImageGeometry(volume_, VolumeProjection_Axial));
       coronalGeometry_.reset(new VolumeImageGeometry(volume_, VolumeProjection_Coronal));
@@ -544,30 +547,30 @@
       EmitMessage(IVolumeSlicer::GeometryReadyMessage(*this));
     }
 
-    virtual void NotifyGeometryError(const ISlicedVolume& volume) ORTHANC_OVERRIDE
+    void OnGeometryError(const ISlicedVolume::GeometryErrorMessage& message)
     {
+      assert(&message.GetOrigin() == &volume_);
+      
       EmitMessage(IVolumeSlicer::GeometryErrorMessage(*this));
     }
 
-    virtual void NotifyContentChange(const ISlicedVolume& volume) ORTHANC_OVERRIDE
+    void OnContentChanged(const ISlicedVolume::ContentChangedMessage& message)
     {
+      assert(&message.GetOrigin() == &volume_);
+      
       EmitMessage(IVolumeSlicer::ContentChangedMessage(*this));
     }
 
-    virtual void NotifySliceContentChange(const ISlicedVolume& volume,
-                                          const size_t& sliceIndex,
-                                          const Slice& slice) ORTHANC_OVERRIDE
+    void OnSliceContentChanged(const ISlicedVolume::SliceContentChangedMessage& message)
     {
-      //IVolumeSlicer::NotifySliceContentChange(slice);
+      assert(&message.GetOrigin() == &volume_);
+
+      //IVolumeSlicer::OnSliceContentChange(slice);
 
       // TODO Improve this?
       EmitMessage(IVolumeSlicer::ContentChangedMessage(*this));
     }
 
-    virtual void NotifyVolumeReady(const ISlicedVolume& volume) ORTHANC_OVERRIDE
-    {
-    }
-
     const VolumeImageGeometry& GetProjectionGeometry(VolumeProjection projection)
     {
       if (!IsGeometryReady())
@@ -629,13 +632,24 @@
     VolumeImageMPRSlicer(MessageBroker& broker, 
                          OrthancVolumeImage&  volume) :
       IVolumeSlicer(broker),
+      IObserver(broker),
       volume_(volume)
     {
-      volume_.Register(*this);
-    }
+      volume_.RegisterObserverCallback(
+        new Callable<VolumeImageMPRSlicer, ISlicedVolume::GeometryReadyMessage>
+        (*this, &VolumeImageMPRSlicer::OnGeometryReady));
+
+      volume_.RegisterObserverCallback(
+        new Callable<VolumeImageMPRSlicer, ISlicedVolume::GeometryErrorMessage>
+        (*this, &VolumeImageMPRSlicer::OnGeometryError));
 
-    virtual ~VolumeImageMPRSlicer()
-    {
+      volume_.RegisterObserverCallback(
+        new Callable<VolumeImageMPRSlicer, ISlicedVolume::ContentChangedMessage>
+        (*this, &VolumeImageMPRSlicer::OnContentChanged));
+
+      volume_.RegisterObserverCallback(
+        new Callable<VolumeImageMPRSlicer, ISlicedVolume::SliceContentChangedMessage>
+        (*this, &VolumeImageMPRSlicer::OnSliceContentChanged));
     }
 
     virtual bool GetExtent(std::vector<Vector>& points,
@@ -702,20 +716,21 @@
 
   class VolumeImageInteractor :
     public IWorldSceneInteractor,
-    protected ISlicedVolume::IObserver
+    public IObserver
   {
   private:
-    SliceViewerWidget&                        widget_;
+    SliceViewerWidget&                  widget_;
     VolumeProjection                    projection_;
     std::auto_ptr<VolumeImageGeometry>  slices_;
     size_t                              slice_;
 
   protected:
-    virtual void NotifyGeometryReady(const ISlicedVolume& volume)
+    void OnGeometryReady(const ISlicedVolume::GeometryReadyMessage& message)
     {
       if (slices_.get() == NULL)
       {
-        const OrthancVolumeImage& image = dynamic_cast<const OrthancVolumeImage&>(volume);
+        const OrthancVolumeImage& image =
+          dynamic_cast<const OrthancVolumeImage&>(message.GetOrigin());
 
         slices_.reset(new VolumeImageGeometry(image, projection_));
         SetSlice(slices_->GetSliceCount() / 2);
@@ -724,24 +739,6 @@
       }
     }
 
-    virtual void NotifyGeometryError(const ISlicedVolume& volume)
-    {
-    }
-
-    virtual void NotifyContentChange(const ISlicedVolume& volume)
-    {
-    }
-
-    virtual void NotifySliceContentChange(const ISlicedVolume& volume,
-                                          const size_t& sliceIndex,
-                                          const Slice& slice)
-    {
-    }
-
-    virtual void NotifyVolumeReady(const ISlicedVolume& volume)
-    {
-    }
-
     virtual IWorldSceneMouseTracker* CreateMouseTracker(WorldSceneWidget& widget,
                                                         const ViewportGeometry& view,
                                                         MouseButton button,
@@ -801,14 +798,19 @@
     }
 
   public:
-    VolumeImageInteractor(OrthancVolumeImage& volume,
+    VolumeImageInteractor(MessageBroker& broker,
+                          OrthancVolumeImage& volume,
                           SliceViewerWidget& widget,
                           VolumeProjection projection) :
+      IObserver(broker),
       widget_(widget),
       projection_(projection)
     {
-      volume.Register(*this);
       widget.SetInteractor(*this);
+
+      volume.RegisterObserverCallback(
+        new Callable<VolumeImageInteractor, ISlicedVolume::GeometryReadyMessage>
+        (*this, &VolumeImageInteractor::OnGeometryReady));
     }
 
     bool IsGeometryReady() const
--- a/Resources/CMake/OrthancStoneConfiguration.cmake	Sun Nov 11 13:02:38 2018 +0100
+++ b/Resources/CMake/OrthancStoneConfiguration.cmake	Sun Nov 11 17:50:11 2018 +0100
@@ -276,7 +276,6 @@
   ${ORTHANC_STONE_ROOT}/Framework/Viewport/IViewport.h
   ${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/VolumeReslicer.cpp
   ${ORTHANC_STONE_ROOT}/Framework/Widgets/CairoWidget.cpp
--- a/UnitTestsSources/UnitTestsMain.cpp	Sun Nov 11 13:02:38 2018 +0100
+++ b/UnitTestsSources/UnitTestsMain.cpp	Sun Nov 11 17:50:11 2018 +0100
@@ -28,7 +28,6 @@
 #include "../Framework/Toolbox/MessagingToolbox.h"
 #include "../Framework/Toolbox/OrthancSlicesLoader.h"
 #include "../Framework/Volumes/ImageBuffer3D.h"
-#include "../Framework/Volumes/SlicedVolumeBase.h"
 #include "../Platforms/Generic/OracleWebService.h"
 
 #include <Core/HttpClient.h>