Mercurial > hg > orthanc-stone
changeset 251:192e6e349e69 am-2
first usage of new message system (in SDL only)
line wrap: on
line diff
--- a/Applications/Samples/SampleMainSdl.cpp Mon Jul 02 16:36:17 2018 +0200 +++ b/Applications/Samples/SampleMainSdl.cpp Mon Jul 02 18:13:46 2018 +0200 @@ -21,10 +21,12 @@ #include "SampleList.h" #include "../Sdl/BasicSdlApplication.h" +#include "../../Framework/Messages/MessageBroker.h" int main(int argc, char* argv[]) { - Application application; + OrthancStone::MessageBroker broker; + Application application(broker); - return OrthancStone::BasicSdlApplication::ExecuteWithSdl(application, argc, argv); + return OrthancStone::BasicSdlApplication::ExecuteWithSdl(broker, application, argc, argv); }
--- a/Applications/Samples/SimpleViewerApplication.h Mon Jul 02 16:36:17 2018 +0200 +++ b/Applications/Samples/SimpleViewerApplication.h Mon Jul 02 18:13:46 2018 +0200 @@ -26,6 +26,7 @@ #include "../../Framework/Layers/OrthancFrameLayerSource.h" #include "../../Framework/Widgets/LayerWidget.h" #include "../../Framework/Widgets/LayoutWidget.h" +#include "../../Framework/Messages/IObserver.h" #include <Core/Logging.h> @@ -35,7 +36,7 @@ { class SimpleViewerApplication : public SampleApplicationBase, - private ILayerSource::IObserver + public IObserver { private: class Interactor : public IWorldSceneInteractor @@ -172,38 +173,13 @@ // } // } - - virtual void NotifyGeometryReady(const ILayerSource& source) - { - // 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) - { - //SetSlice(source_->GetSliceCount() / 2); + + virtual void HandleMessage(IObservable& from, const IMessage& message) { + switch (message.GetType()) { + case MessageType_GeometryReady: + mainLayout_->SetDefaultView(); + break; } - - mainLayout_->SetDefaultView(); - } - - virtual void NotifyGeometryError(const ILayerSource& source) - { - } - - virtual void NotifyContentChange(const ILayerSource& source) - { - } - - virtual void NotifySliceChange(const ILayerSource& source, - const Slice& slice) - { - } - - virtual void NotifyLayerReady(std::auto_ptr<ILayerRenderer>& layer, - const ILayerSource& source, - const CoordinateSystem3D& slice, - bool isError) - { } std::unique_ptr<Interactor> interactor_; @@ -218,18 +194,19 @@ OrthancFrameLayerSource* source_; unsigned int slice_; - + public: - SimpleViewerApplication() : + SimpleViewerApplication(MessageBroker& broker) : mainLayout_(NULL), currentInstanceIndex_(0), source_(NULL), slice_(0), wasmViewport1_(NULL), - wasmViewport2_(NULL) + wasmViewport2_(NULL), + IObserver(broker) { } - + virtual void Finalize() {} virtual IWidget* GetCentralWidget() {return mainLayout_;} @@ -282,9 +259,9 @@ thumbnailsLayout_->SetBackgroundColor(50, 50, 50); thumbnailsLayout_->SetVertical(); - mainViewport_ = new LayerWidget(); - thumbnails_.push_back(new LayerWidget()); - thumbnails_.push_back(new LayerWidget()); + mainViewport_ = new LayerWidget(broker_); + thumbnails_.push_back(new LayerWidget(broker_)); + thumbnails_.push_back(new LayerWidget(broker_)); // hierarchy mainLayout_->AddWidget(thumbnailsLayout_); @@ -293,15 +270,15 @@ thumbnailsLayout_->AddWidget(thumbnails_[1]); // sources - source_ = new OrthancFrameLayerSource(context_->GetWebService()); + source_ = new OrthancFrameLayerSource(broker_, context_->GetWebService()); source_->LoadFrame(instances_[currentInstanceIndex_], 0); source_->Register(*this); mainViewport_->AddLayer(source_); - OrthancFrameLayerSource* thumb0 = new OrthancFrameLayerSource(context_->GetWebService()); + OrthancFrameLayerSource* thumb0 = new OrthancFrameLayerSource(broker_, context_->GetWebService()); thumb0->LoadFrame(instances_[0], 0); - OrthancFrameLayerSource* thumb1 = new OrthancFrameLayerSource(context_->GetWebService()); + OrthancFrameLayerSource* thumb1 = new OrthancFrameLayerSource(broker_, context_->GetWebService()); thumb1->LoadFrame(instances_[1], 0); thumbnails_[0]->AddLayer(thumb0); @@ -326,7 +303,7 @@ currentInstanceIndex_ = (currentInstanceIndex_ + 1) % instances_.size(); std::auto_ptr<OrthancFrameLayerSource> layer - (new OrthancFrameLayerSource(context_->GetWebService())); + (new OrthancFrameLayerSource(broker_, context_->GetWebService())); layer->LoadFrame(instances_[currentInstanceIndex_], 0); mainViewport_->ReplaceLayer(0, layer.release());
--- a/Applications/Sdl/BasicSdlApplication.cpp Mon Jul 02 16:36:17 2018 +0200 +++ b/Applications/Sdl/BasicSdlApplication.cpp Mon Jul 02 18:13:46 2018 +0200 @@ -80,7 +80,8 @@ } - int BasicSdlApplication::ExecuteWithSdl(IBasicApplication& application, + int BasicSdlApplication::ExecuteWithSdl(MessageBroker& broker, + IBasicApplication& application, int argc, char* argv[]) { @@ -224,7 +225,7 @@ boost::mutex stoneGlobalMutex; Oracle oracle(stoneGlobalMutex, 4); // use 4 threads to download content - OracleWebService webService(oracle, webServiceParameters); + OracleWebService webService(broker, oracle, webServiceParameters); BasicSdlApplicationContext context(webService); application.Initialize(&context, statusBar, parameters);
--- a/Applications/Sdl/BasicSdlApplication.h Mon Jul 02 16:36:17 2018 +0200 +++ b/Applications/Sdl/BasicSdlApplication.h Mon Jul 02 18:13:46 2018 +0200 @@ -35,7 +35,8 @@ { public: - static int ExecuteWithSdl(IBasicApplication& application, + static int ExecuteWithSdl(MessageBroker& broker, + IBasicApplication& application, int argc, char* argv[]); };
--- a/Framework/Layers/DicomStructureSetRendererFactory.h Mon Jul 02 16:36:17 2018 +0200 +++ b/Framework/Layers/DicomStructureSetRendererFactory.h Mon Jul 02 18:13:46 2018 +0200 @@ -37,21 +37,22 @@ { LayerSourceBase::NotifyGeometryReady(); } - + virtual void NotifyGeometryError(const IVolumeLoader& loader) { LayerSourceBase::NotifyGeometryError(); } - + virtual void NotifyContentChange(const IVolumeLoader& loader) { LayerSourceBase::NotifyContentChange(); } - + StructureSetLoader& loader_; public: - DicomStructureSetRendererFactory(StructureSetLoader& loader) : + DicomStructureSetRendererFactory(MessageBroker& broker, StructureSetLoader& loader) : + LayerSourceBase(broker), loader_(loader) { loader_.Register(*this);
--- a/Framework/Layers/ILayerSource.h Mon Jul 02 16:36:17 2018 +0200 +++ b/Framework/Layers/ILayerSource.h Mon Jul 02 18:13:46 2018 +0200 @@ -13,7 +13,7 @@ * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Affero General Public License for more details. - * + * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. **/ @@ -23,47 +23,80 @@ #include "ILayerRenderer.h" #include "../Toolbox/Slice.h" +#include "../../Framework/Messages/IObservable.h" +#include "../../Framework/Messages/IMessage.h" namespace OrthancStone { - class ILayerSource : public boost::noncopyable + class ILayerSource : public boost::noncopyable, public IObservable { public: - class IObserver : public boost::noncopyable + struct SliceChangedMessage : public IMessage + { + const Slice& slice; + SliceChangedMessage(const Slice& slice) + : IMessage(MessageType_SliceChanged), + slice(slice) + { + } + }; + + struct LayerReadyMessage : public IMessage { - public: - virtual ~IObserver() + std::auto_ptr<ILayerRenderer>& layer; + const CoordinateSystem3D& slice; + bool isError; + + LayerReadyMessage(std::auto_ptr<ILayerRenderer>& layer, + const CoordinateSystem3D& slice, + bool isError) // TODO Shouldn't this be separate as NotifyLayerError? + : IMessage(MessageType_LayerReady), + layer(layer), + slice(slice), + isError(isError) { } + }; - // Triggered as soon as the source has enough information to - // answer to "GetExtent()" - virtual void NotifyGeometryReady(const ILayerSource& source) = 0; - - virtual void NotifyGeometryError(const ILayerSource& source) = 0; - - // Triggered if the content of several slices in the source - // volume has changed - virtual void NotifyContentChange(const ILayerSource& source) = 0; + // class IObserver : public boost::noncopyable + // { + // public: + // virtual ~IObserver() + // { + // } + + // // Triggered as soon as the source has enough information to + // // answer to "GetExtent()" + // virtual void NotifyGeometryReady(const ILayerSource& source) = 0; + + // virtual void NotifyGeometryError(const ILayerSource& source) = 0; - // Triggered if the content of some individual slice in the - // source volume has changed - virtual void NotifySliceChange(const ILayerSource& source, - const Slice& slice) = 0; - - // The layer must be deleted by the observer that releases the - // std::auto_ptr - virtual void NotifyLayerReady(std::auto_ptr<ILayerRenderer>& layer, - const ILayerSource& source, - const CoordinateSystem3D& slice, - bool isError) = 0; // TODO Shouldn't this be separate as NotifyLayerError? - }; + // // Triggered if the content of several slices in the source + // // volume has changed + // virtual void NotifyContentChange(const ILayerSource& source) = 0; + + // // Triggered if the content of some individual slice in the + // // source volume has changed + // virtual void NotifySliceChange(const ILayerSource& source, + // const Slice& slice) = 0; + + // // The layer must be deleted by the observer that releases the + // // std::auto_ptr + // virtual void NotifyLayerReady(std::auto_ptr<ILayerRenderer>& layer, + // const ILayerSource& source, + // const CoordinateSystem3D& slice, + // bool isError) = 0; // TODO Shouldn't this be separate as NotifyLayerError? + // }; + ILayerSource(MessageBroker& broker) + : IObservable(broker) + {} + virtual ~ILayerSource() { } - virtual void Register(IObserver& observer) = 0; + // virtual void Register(IObserver& observer) = 0; virtual bool GetExtent(std::vector<Vector>& points, const CoordinateSystem3D& viewportSlice) = 0;
--- a/Framework/Layers/LayerSourceBase.cpp Mon Jul 02 16:36:17 2018 +0200 +++ b/Framework/Layers/LayerSourceBase.cpp Mon Jul 02 18:13:46 2018 +0200 @@ -25,63 +25,65 @@ namespace OrthancStone { - namespace - { - class LayerReadyFunctor : public boost::noncopyable - { - private: - std::auto_ptr<ILayerRenderer> layer_; - const CoordinateSystem3D& slice_; - bool isError_; +// namespace +// { +// 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() { - observers_.Apply(*this, &IObserver::NotifyGeometryReady); + Emit(IMessage(MessageType_GeometryReady)); } void LayerSourceBase::NotifyGeometryError() { - observers_.Apply(*this, &IObserver::NotifyGeometryError); - } + Emit(IMessage(MessageType_GeometryError)); + } void LayerSourceBase::NotifyContentChange() { - observers_.Apply(*this, &IObserver::NotifyContentChange); + Emit(IMessage(MessageType_ContentChanged)); } void LayerSourceBase::NotifySliceChange(const Slice& slice) { - observers_.Apply(*this, &IObserver::NotifySliceChange, slice); + Emit(ILayerSource::SliceChangedMessage(slice)); } void LayerSourceBase::NotifyLayerReady(ILayerRenderer* layer, const CoordinateSystem3D& slice, bool isError) { - LayerReadyFunctor functor(layer, slice, isError); - observers_.Notify(*this, functor); + std::auto_ptr<ILayerRenderer> renderer(layer); + Emit(ILayerSource::LayerReadyMessage(renderer, slice, isError)); +// LayerReadyFunctor functor(layer, slice, isError); +// observers_.Notify(*this, functor); } void LayerSourceBase::Register(IObserver& observer) { - observers_.Register(observer); + RegisterObserver(observer); } }
--- a/Framework/Layers/LayerSourceBase.h Mon Jul 02 16:36:17 2018 +0200 +++ b/Framework/Layers/LayerSourceBase.h Mon Jul 02 18:13:46 2018 +0200 @@ -28,11 +28,6 @@ { class LayerSourceBase : public ILayerSource { - private: - typedef ObserversRegistry<ILayerSource, IObserver> Observers; - - Observers observers_; - protected: void NotifyGeometryReady(); @@ -46,6 +41,10 @@ const CoordinateSystem3D& slice, bool isError); + LayerSourceBase(MessageBroker& broker) + : ILayerSource(broker) + {} + public: virtual void Register(IObserver& observer); };
--- a/Framework/Layers/OrthancFrameLayerSource.cpp Mon Jul 02 16:36:17 2018 +0200 +++ b/Framework/Layers/OrthancFrameLayerSource.cpp Mon Jul 02 18:13:46 2018 +0200 @@ -68,8 +68,9 @@ } - OrthancFrameLayerSource::OrthancFrameLayerSource(IWebService& orthanc) : - loader_(*this, orthanc), + OrthancFrameLayerSource::OrthancFrameLayerSource(MessageBroker& broker, IWebService& orthanc) : + LayerSourceBase(broker), + loader_(broker, *this, orthanc), quality_(SliceImageQuality_Full) { }
--- a/Framework/Layers/OrthancFrameLayerSource.h Mon Jul 02 16:36:17 2018 +0200 +++ b/Framework/Layers/OrthancFrameLayerSource.h Mon Jul 02 18:13:46 2018 +0200 @@ -51,7 +51,7 @@ SliceImageQuality quality); public: - OrthancFrameLayerSource(IWebService& orthanc); + OrthancFrameLayerSource(MessageBroker& broker, IWebService& orthanc); void LoadSeries(const std::string& seriesId);
--- a/Framework/Messages/IMessage.h Mon Jul 02 16:36:17 2018 +0200 +++ b/Framework/Messages/IMessage.h Mon Jul 02 18:13:46 2018 +0200 @@ -23,15 +23,18 @@ #include "MessageType.h" +#include <boost/noncopyable.hpp> + namespace OrthancStone { - class IMessage : public boost::noncopyable + struct IMessage : public boost::noncopyable { MessageType messageType_; public: IMessage(const MessageType& messageType) : messageType_(messageType) {} + virtual ~IMessage() {} MessageType GetType() const {return messageType_;} };
--- a/Framework/Messages/IObserver.h Mon Jul 02 16:36:17 2018 +0200 +++ b/Framework/Messages/IObserver.h Mon Jul 02 18:13:46 2018 +0200 @@ -22,14 +22,16 @@ #pragma once #include "MessageBroker.h" +#include "IMessage.h" +#include "IObservable.h" namespace OrthancStone { class IObservable; - class IMessage; class IObserver : public boost::noncopyable { + protected: MessageBroker& broker_; public:
--- a/Framework/Messages/MessageBroker.h Mon Jul 02 16:36:17 2018 +0200 +++ b/Framework/Messages/MessageBroker.h Mon Jul 02 18:13:46 2018 +0200 @@ -27,6 +27,7 @@ #include <map> #include <list> #include <set> + namespace OrthancStone { class IObserver;
--- a/Framework/Messages/MessageType.h Mon Jul 02 16:36:17 2018 +0200 +++ b/Framework/Messages/MessageType.h Mon Jul 02 18:13:46 2018 +0200 @@ -18,6 +18,7 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. **/ +#pragma once namespace OrthancStone { @@ -25,6 +26,14 @@ { MessageType_Generic, - MessageType_GeometryReady + MessageType_GeometryReady, + MessageType_GeometryError, + MessageType_ContentChanged, + MessageType_SliceChanged, + MessageType_LayerReady, + + MessageType_HttpRequestSuccess, + MessageType_HttpRequestError + }; }
--- a/Framework/Toolbox/IWebService.h Mon Jul 02 16:36:17 2018 +0200 +++ b/Framework/Toolbox/IWebService.h Mon Jul 02 18:13:46 2018 +0200 @@ -13,7 +13,7 @@ * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Affero General Public License for more details. - * + * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. **/ @@ -22,41 +22,102 @@ #pragma once #include <Core/IDynamicObject.h> - +#include "../../Framework/Messages/IObserver.h" #include <string> namespace OrthancStone { - class IWebService : public boost::noncopyable - { - public: - class ICallback : public boost::noncopyable + class IWebService { + protected: + MessageBroker& broker_; public: - virtual ~ICallback() - { - } + class ICallback : public IObserver + { + public: + struct HttpRequestSuccessMessage: public IMessage + { + const std::string& Uri; + const void* Answer; + size_t AnswerSize; + Orthanc::IDynamicObject* Payload; + HttpRequestSuccessMessage(const std::string& uri, + const void* answer, + size_t answerSize, + Orthanc::IDynamicObject* payload) + : IMessage(MessageType_HttpRequestSuccess), + Uri(uri), + Answer(answer), + AnswerSize(answerSize), + Payload(payload) + {} + }; - virtual void NotifyError(const std::string& uri, - Orthanc::IDynamicObject* payload) = 0; + struct HttpRequestErrorMessage: public IMessage + { + const std::string& Uri; + Orthanc::IDynamicObject* Payload; + HttpRequestErrorMessage(const std::string& uri, + Orthanc::IDynamicObject* payload) + : IMessage(MessageType_HttpRequestError), + Uri(uri), + Payload(payload) + {} + }; + + ICallback(MessageBroker& broker) + : IObserver(broker) + {} + virtual ~ICallback() + { + } - virtual void NotifySuccess(const std::string& uri, - const void* answer, - size_t answerSize, - Orthanc::IDynamicObject* payload) = 0; - }; - - virtual ~IWebService() - { - } + virtual void HandleMessage(IObservable& from, const IMessage& message) + { + switch(message.GetType()) + { + case MessageType_HttpRequestError: + { const HttpRequestErrorMessage& msg = dynamic_cast<const HttpRequestErrorMessage&>(message); + OnHttpRequestError(msg.Uri, + msg.Payload); + }; break; + + case MessageType_HttpRequestSuccess: + { + const HttpRequestSuccessMessage& msg = dynamic_cast<const HttpRequestSuccessMessage&>(message); + OnHttpRequestSuccess(msg.Uri, + msg.Answer, + msg.AnswerSize, + msg.Payload); + }; break; + + } + } + + virtual void OnHttpRequestError(const std::string& uri, + Orthanc::IDynamicObject* payload) = 0; - virtual void ScheduleGetRequest(ICallback& callback, - const std::string& uri, - Orthanc::IDynamicObject* payload) = 0; + virtual void OnHttpRequestSuccess(const std::string& uri, + const void* answer, + size_t answerSize, + Orthanc::IDynamicObject* payload) = 0; + }; + + IWebService(MessageBroker& broker) + : broker_(broker) + {} - virtual void SchedulePostRequest(ICallback& callback, - const std::string& uri, - const std::string& body, - Orthanc::IDynamicObject* payload) = 0; - }; + virtual ~IWebService() + { + } + + virtual void ScheduleGetRequest(ICallback& callback, + const std::string& uri, + Orthanc::IDynamicObject* payload) = 0; + + virtual void SchedulePostRequest(ICallback& callback, + const std::string& uri, + const std::string& body, + Orthanc::IDynamicObject* payload) = 0; + }; }
--- a/Framework/Toolbox/OrthancSlicesLoader.cpp Mon Jul 02 16:36:17 2018 +0200 +++ b/Framework/Toolbox/OrthancSlicesLoader.cpp Mon Jul 02 18:13:46 2018 +0200 @@ -175,12 +175,13 @@ OrthancSlicesLoader& that_; public: - WebCallback(OrthancSlicesLoader& that) : + WebCallback(MessageBroker& broker, OrthancSlicesLoader& that) : + IWebService::ICallback(broker), that_(that) { } - virtual void NotifySuccess(const std::string& uri, + virtual void OnHttpRequestSuccess(const std::string& uri, const void* answer, size_t answerSize, Orthanc::IDynamicObject* payload) @@ -230,7 +231,7 @@ } } - virtual void NotifyError(const std::string& uri, + virtual void OnHttpRequestError(const std::string& uri, Orthanc::IDynamicObject* payload) { std::auto_ptr<Operation> operation(dynamic_cast<Operation*>(payload)); @@ -715,9 +716,10 @@ } - OrthancSlicesLoader::OrthancSlicesLoader(ICallback& callback, + OrthancSlicesLoader::OrthancSlicesLoader(MessageBroker& broker, + ICallback& callback, IWebService& orthanc) : - webCallback_(new WebCallback(*this)), + webCallback_(new WebCallback(broker, *this)), userCallback_(callback), orthanc_(orthanc), state_(State_Initialization)
--- a/Framework/Toolbox/OrthancSlicesLoader.h Mon Jul 02 16:36:17 2018 +0200 +++ b/Framework/Toolbox/OrthancSlicesLoader.h Mon Jul 02 18:13:46 2018 +0200 @@ -122,7 +122,8 @@ void SortAndFinalizeSlices(); public: - OrthancSlicesLoader(ICallback& callback, + OrthancSlicesLoader(MessageBroker& broker, + ICallback& callback, IWebService& orthanc); void ScheduleLoadSeries(const std::string& seriesId);
--- a/Framework/Volumes/StructureSetLoader.cpp Mon Jul 02 16:36:17 2018 +0200 +++ b/Framework/Volumes/StructureSetLoader.cpp Mon Jul 02 18:13:46 2018 +0200 @@ -61,14 +61,14 @@ }; - void StructureSetLoader::NotifyError(const std::string& uri, + void StructureSetLoader::OnHttpRequestError(const std::string& uri, Orthanc::IDynamicObject* payload) { // TODO } - void StructureSetLoader::NotifySuccess(const std::string& uri, + void StructureSetLoader::OnHttpRequestSuccess(const std::string& uri, const void* answer, size_t answerSize, Orthanc::IDynamicObject* payload) @@ -145,7 +145,8 @@ } - StructureSetLoader::StructureSetLoader(IWebService& orthanc) : + StructureSetLoader::StructureSetLoader(MessageBroker& broker, IWebService& orthanc) : + IWebService::ICallback(broker), orthanc_(orthanc) { }
--- a/Framework/Volumes/StructureSetLoader.h Mon Jul 02 16:36:17 2018 +0200 +++ b/Framework/Volumes/StructureSetLoader.h Mon Jul 02 18:13:46 2018 +0200 @@ -34,10 +34,10 @@ private: class Operation; - virtual void NotifyError(const std::string& uri, + virtual void OnHttpRequestError(const std::string& uri, Orthanc::IDynamicObject* payload); - virtual void NotifySuccess(const std::string& uri, + virtual void OnHttpRequestSuccess(const std::string& uri, const void* answer, size_t answerSize, Orthanc::IDynamicObject* payload); @@ -46,7 +46,7 @@ std::auto_ptr<DicomStructureSet> structureSet_; public: - StructureSetLoader(IWebService& orthanc); + StructureSetLoader(MessageBroker& broker, IWebService& orthanc); void ScheduleLoadInstance(const std::string& instance);
--- a/Framework/Widgets/LayerWidget.cpp Mon Jul 02 16:36:17 2018 +0200 +++ b/Framework/Widgets/LayerWidget.cpp Mon Jul 02 18:13:46 2018 +0200 @@ -13,7 +13,7 @@ * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Affero General Public License for more details. - * + * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. **/ @@ -55,7 +55,7 @@ countMissing_++; } } - + public: Scene(const CoordinateSystem3D& slice, double thickness, @@ -184,7 +184,7 @@ #endif cairo_set_line_width(cr, 2.0 / view.GetZoom()); - cairo_set_source_rgb(cr, 1, 1, 1); + cairo_set_source_rgb(cr, 1, 1, 1); cairo_stroke_preserve(cr); cairo_set_source_rgb(cr, 1, 0, 0); cairo_fill(cr); @@ -215,7 +215,7 @@ { double z = (slice_.ProjectAlongNormal(slice.GetOrigin()) - slice_.ProjectAlongNormal(slice_.GetOrigin())); - + if (z < 0) { z = -z; @@ -249,7 +249,7 @@ return true; } } - + void LayerWidget::GetLayerExtent(Extent2D& extent, ILayerSource& source) const @@ -268,7 +268,7 @@ } } - + Extent2D LayerWidget::GetSceneExtent() { Extent2D sceneExtent; @@ -359,7 +359,8 @@ } - LayerWidget::LayerWidget() : + LayerWidget::LayerWidget(MessageBroker& broker) : + IObserver(broker), started_(false) { SetBackgroundCleared(true); @@ -388,7 +389,7 @@ layersIndex_[layer] = index; ResetPendingScene(); - layer->Register(*this); + layer->RegisterObserver(*this); ResetChangedLayers(); @@ -412,7 +413,7 @@ layersIndex_[layer] = index; ResetPendingScene(); - layer->Register(*this); + layer->RegisterObserver(*this); InvalidateLayer(index); } @@ -479,8 +480,35 @@ } } + void LayerWidget::HandleMessage(IObservable& from, const IMessage& message) + { + switch (message.GetType()) { + case MessageType_GeometryReady: + OnGeometryReady(dynamic_cast<ILayerSource&>(from)); + break; + case MessageType_GeometryError: + LOG(ERROR) << "Cannot get geometry"; + break; + case MessageType_ContentChanged: + OnContentChanged(dynamic_cast<ILayerSource&>(from)); + break; + case MessageType_SliceChanged: + OnSliceChanged(dynamic_cast<ILayerSource&>(from), dynamic_cast<const ILayerSource::SliceChangedMessage&>(message).slice); + break; + case MessageType_LayerReady: + { + const ILayerSource::LayerReadyMessage& layerReadyMessage = dynamic_cast<const ILayerSource::LayerReadyMessage&>(message); + OnLayerReady(layerReadyMessage.layer, + dynamic_cast<ILayerSource&>(from), + layerReadyMessage.slice, + layerReadyMessage.isError); + }; break; + default: + throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented); + } + } - void LayerWidget::NotifyGeometryReady(const ILayerSource& source) + void LayerWidget::OnGeometryReady(const ILayerSource& source) { size_t i; if (LookupLayer(i, source)) @@ -492,13 +520,6 @@ } } - - void LayerWidget::NotifyGeometryError(const ILayerSource& source) - { - LOG(ERROR) << "Cannot get geometry"; - } - - void LayerWidget::InvalidateAllLayers() { for (size_t i = 0; i < layers_.size(); i++) @@ -525,7 +546,7 @@ } - void LayerWidget::NotifyContentChange(const ILayerSource& source) + void LayerWidget::OnContentChanged(const ILayerSource& source) { size_t index; if (LookupLayer(index, source)) @@ -535,8 +556,8 @@ } - void LayerWidget::NotifySliceChange(const ILayerSource& source, - const Slice& slice) + void LayerWidget::OnSliceChanged(const ILayerSource& source, + const Slice& slice) { if (slice.ContainsPlane(slice_)) { @@ -549,10 +570,10 @@ } - void LayerWidget::NotifyLayerReady(std::auto_ptr<ILayerRenderer>& renderer, - const ILayerSource& source, - const CoordinateSystem3D& slice, - bool isError) + void LayerWidget::OnLayerReady(std::auto_ptr<ILayerRenderer>& renderer, + const ILayerSource& source, + const CoordinateSystem3D& slice, + bool isError) { size_t index; if (LookupLayer(index, source))
--- a/Framework/Widgets/LayerWidget.h Mon Jul 02 16:36:17 2018 +0200 +++ b/Framework/Widgets/LayerWidget.h Mon Jul 02 18:13:46 2018 +0200 @@ -24,6 +24,7 @@ #include "WorldSceneWidget.h" #include "../Layers/ILayerSource.h" #include "../Toolbox/Extent2D.h" +#include "../../Framework/Messages/IObserver.h" #include <map> @@ -31,7 +32,7 @@ { class LayerWidget : public WorldSceneWidget, - private ILayerSource::IObserver + public IObserver { private: class Scene; @@ -53,23 +54,26 @@ void GetLayerExtent(Extent2D& extent, ILayerSource& source) const; - virtual void NotifyGeometryReady(const ILayerSource& source); - - virtual void NotifyGeometryError(const ILayerSource& source); + void OnGeometryReady(const ILayerSource& source); - virtual void NotifyContentChange(const ILayerSource& source); + virtual void OnContentChanged(const ILayerSource& source); - virtual void NotifySliceChange(const ILayerSource& source, + virtual void OnSliceChanged(const ILayerSource& source, const Slice& slice); - virtual void NotifyLayerReady(std::auto_ptr<ILayerRenderer>& renderer, + virtual void OnLayerReady(std::auto_ptr<ILayerRenderer>& renderer, const ILayerSource& source, const CoordinateSystem3D& slice, bool isError); + void ResetChangedLayers(); public: + LayerWidget(MessageBroker& broker); + + virtual void HandleMessage(IObservable& from, const IMessage& message); + virtual Extent2D GetSceneExtent(); protected:
--- a/Framework/dev.h Mon Jul 02 16:36:17 2018 +0200 +++ b/Framework/dev.h Mon Jul 02 18:13:46 2018 +0200 @@ -215,9 +215,10 @@ } public: - OrthancVolumeImage(IWebService& orthanc, + OrthancVolumeImage(MessageBroker& broker, + IWebService& orthanc, bool computeRange) : - loader_(*this, orthanc), + loader_(broker, *this, orthanc), computeRange_(computeRange), pendingSlices_(0) { @@ -576,7 +577,8 @@ public: - VolumeImageSource(OrthancVolumeImage& volume) : + VolumeImageSource(MessageBroker& broker, OrthancVolumeImage& volume) : + LayerSourceBase(broker), volume_(volume) { volume_.Register(*this); @@ -814,7 +816,8 @@ LayerWidget& otherPlane_; public: - SliceLocationSource(LayerWidget& otherPlane) : + SliceLocationSource(MessageBroker& broker, LayerWidget& otherPlane) : + LayerSourceBase(broker), otherPlane_(otherPlane) { NotifyGeometryReady();
--- a/Platforms/Generic/OracleWebService.h Mon Jul 02 16:36:17 2018 +0200 +++ b/Platforms/Generic/OracleWebService.h Mon Jul 02 18:13:46 2018 +0200 @@ -35,8 +35,10 @@ Orthanc::WebServiceParameters parameters_; public: - OracleWebService(Oracle& oracle, + OracleWebService(MessageBroker& broker, + Oracle& oracle, const Orthanc::WebServiceParameters& parameters) : + IWebService(broker), oracle_(oracle), parameters_(parameters) { @@ -46,7 +48,7 @@ const std::string& uri, Orthanc::IDynamicObject* payload) { - oracle_.Submit(new WebServiceGetCommand(callback, parameters_, uri, payload)); + oracle_.Submit(new WebServiceGetCommand(broker_, callback, parameters_, uri, payload)); } virtual void SchedulePostRequest(ICallback& callback, @@ -54,7 +56,7 @@ const std::string& body, Orthanc::IDynamicObject* payload) { - oracle_.Submit(new WebServicePostCommand(callback, parameters_, uri, body, payload)); + oracle_.Submit(new WebServicePostCommand(broker_, callback, parameters_, uri, body, payload)); } void Start()
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Platforms/Generic/WebServiceCommandBase.cpp Mon Jul 02 18:13:46 2018 +0200 @@ -0,0 +1,56 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2018 Osimis S.A., Belgium + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU Affero General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + **/ + + +#include "WebServiceCommandBase.h" + +#include <Core/HttpClient.h> + +namespace OrthancStone +{ + WebServiceCommandBase::WebServiceCommandBase(MessageBroker& broker, + IWebService::ICallback& callback, + const Orthanc::WebServiceParameters& parameters, + const std::string& uri, + Orthanc::IDynamicObject* payload /* takes ownership */) : + IObservable(broker), + callback_(callback), + parameters_(parameters), + uri_(uri), + payload_(payload) + { + RegisterObserver(callback); + } + + + void WebServiceCommandBase::Commit() + { + if (success_) + { + IWebService::ICallback::HttpRequestSuccessMessage message(uri_, answer_.c_str(), answer_.size(), payload_.release()); + Emit(message); + } + else + { + IWebService::ICallback::HttpRequestErrorMessage message(uri_, payload_.release()); + Emit(message); + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Platforms/Generic/WebServiceCommandBase.h Mon Jul 02 18:13:46 2018 +0200 @@ -0,0 +1,56 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2018 Osimis S.A., Belgium + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU Affero General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + **/ + + +#pragma once + +#include "IOracleCommand.h" + +#include "../../Framework/Toolbox/IWebService.h" +#include "../../Framework/Messages/IObservable.h" + +#include <Core/WebServiceParameters.h> + +#include <memory> + +namespace OrthancStone +{ + class WebServiceCommandBase : public IOracleCommand, IObservable + { + protected: + IWebService::ICallback& callback_; + Orthanc::WebServiceParameters parameters_; + std::string uri_; + std::auto_ptr<Orthanc::IDynamicObject> payload_; + bool success_; + std::string answer_; + + public: + WebServiceCommandBase(MessageBroker& broker, + IWebService::ICallback& callback, + const Orthanc::WebServiceParameters& parameters, + const std::string& uri, + Orthanc::IDynamicObject* payload /* takes ownership */); + + virtual void Execute() = 0; + + virtual void Commit(); + }; +}
--- a/Platforms/Generic/WebServiceGetCommand.cpp Mon Jul 02 16:36:17 2018 +0200 +++ b/Platforms/Generic/WebServiceGetCommand.cpp Mon Jul 02 18:13:46 2018 +0200 @@ -25,14 +25,12 @@ namespace OrthancStone { - WebServiceGetCommand::WebServiceGetCommand(IWebService::ICallback& callback, + WebServiceGetCommand::WebServiceGetCommand(MessageBroker& broker, + IWebService::ICallback& callback, const Orthanc::WebServiceParameters& parameters, const std::string& uri, Orthanc::IDynamicObject* payload /* takes ownership */) : - callback_(callback), - parameters_(parameters), - uri_(uri), - payload_(payload) + WebServiceCommandBase(broker, callback, parameters, uri, payload) { } @@ -45,16 +43,4 @@ success_ = client.Apply(answer_); } - - void WebServiceGetCommand::Commit() - { - if (success_) - { - callback_.NotifySuccess(uri_, answer_.c_str(), answer_.size(), payload_.release()); - } - else - { - callback_.NotifyError(uri_, payload_.release()); - } - } }
--- a/Platforms/Generic/WebServiceGetCommand.h Mon Jul 02 16:36:17 2018 +0200 +++ b/Platforms/Generic/WebServiceGetCommand.h Mon Jul 02 18:13:46 2018 +0200 @@ -21,34 +21,19 @@ #pragma once -#include "IOracleCommand.h" - -#include "../../Framework/Toolbox/IWebService.h" - -#include <Core/WebServiceParameters.h> - -#include <memory> +#include "WebServiceCommandBase.h" namespace OrthancStone { - class WebServiceGetCommand : public IOracleCommand + class WebServiceGetCommand : public WebServiceCommandBase { - private: - IWebService::ICallback& callback_; - Orthanc::WebServiceParameters parameters_; - std::string uri_; - std::auto_ptr<Orthanc::IDynamicObject> payload_; - bool success_; - std::string answer_; - public: - WebServiceGetCommand(IWebService::ICallback& callback, + WebServiceGetCommand(MessageBroker& broker, + IWebService::ICallback& callback, const Orthanc::WebServiceParameters& parameters, const std::string& uri, Orthanc::IDynamicObject* payload /* takes ownership */); virtual void Execute(); - - virtual void Commit(); }; }
--- a/Platforms/Generic/WebServicePostCommand.cpp Mon Jul 02 16:36:17 2018 +0200 +++ b/Platforms/Generic/WebServicePostCommand.cpp Mon Jul 02 18:13:46 2018 +0200 @@ -25,16 +25,14 @@ namespace OrthancStone { - WebServicePostCommand::WebServicePostCommand(IWebService::ICallback& callback, + WebServicePostCommand::WebServicePostCommand(MessageBroker& broker, + IWebService::ICallback& callback, const Orthanc::WebServiceParameters& parameters, const std::string& uri, const std::string& body, Orthanc::IDynamicObject* payload /* takes ownership */) : - callback_(callback), - parameters_(parameters), - uri_(uri), - body_(body), - payload_(payload) + WebServiceCommandBase(broker, callback, parameters, uri, payload), + body_(body) { } @@ -47,15 +45,4 @@ success_ = client.Apply(answer_); } - void WebServicePostCommand::Commit() - { - if (success_) - { - callback_.NotifySuccess(uri_, answer_.c_str(), answer_.size(), payload_.release()); - } - else - { - callback_.NotifyError(uri_, payload_.release()); - } - } }
--- a/Platforms/Generic/WebServicePostCommand.h Mon Jul 02 16:36:17 2018 +0200 +++ b/Platforms/Generic/WebServicePostCommand.h Mon Jul 02 18:13:46 2018 +0200 @@ -21,36 +21,23 @@ #pragma once -#include "IOracleCommand.h" - -#include "../../Framework/Toolbox/IWebService.h" - -#include <Core/WebServiceParameters.h> - -#include <memory> +#include "WebServiceCommandBase.h" namespace OrthancStone { - class WebServicePostCommand : public IOracleCommand + class WebServicePostCommand : public WebServiceCommandBase { - private: - IWebService::ICallback& callback_; - Orthanc::WebServiceParameters parameters_; - std::string uri_; + protected: std::string body_; - std::auto_ptr<Orthanc::IDynamicObject> payload_; - bool success_; - std::string answer_; public: - WebServicePostCommand(IWebService::ICallback& callback, + WebServicePostCommand(MessageBroker& broker, + IWebService::ICallback& callback, const Orthanc::WebServiceParameters& parameters, const std::string& uri, const std::string& body, Orthanc::IDynamicObject* payload /* takes ownership */); virtual void Execute(); - - virtual void Commit(); }; }
--- a/Resources/CMake/OrthancStoneConfiguration.cmake Mon Jul 02 16:36:17 2018 +0200 +++ b/Resources/CMake/OrthancStoneConfiguration.cmake Mon Jul 02 18:13:46 2018 +0200 @@ -142,6 +142,7 @@ if (NOT ORTHANC_SANDBOXED) set(PLATFORM_SOURCES + ${ORTHANC_STONE_ROOT}/Platforms/Generic/WebServiceCommandBase.cpp ${ORTHANC_STONE_ROOT}/Platforms/Generic/WebServiceGetCommand.cpp ${ORTHANC_STONE_ROOT}/Platforms/Generic/WebServicePostCommand.cpp ${ORTHANC_STONE_ROOT}/Platforms/Generic/Oracle.cpp
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/UnitTestsSources/TestMessageBroker.cpp Mon Jul 02 18:13:46 2018 +0200 @@ -0,0 +1,109 @@ +/** + * 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 "gtest/gtest.h" + +#include "../Framework/Messages/MessageBroker.h" +#include "../Framework/Messages/IMessage.h" +#include "../Framework/Messages/IObservable.h" +#include "../Framework/Messages/IObserver.h" +#include "../Framework/StoneEnumerations.h" + + +static int globalCounter = 0; +class MyObserver : public OrthancStone::IObserver +{ + +public: + MyObserver(OrthancStone::MessageBroker& broker) + : OrthancStone::IObserver(broker) + {} + + + void HandleMessage(OrthancStone::IObservable& from, const OrthancStone::IMessage& message) { + if (message.GetType() == OrthancStone::MessageType_Generic) { + globalCounter++; + } + + } + +}; + + +TEST(MessageBroker, NormalUsage) +{ + OrthancStone::MessageBroker broker; + OrthancStone::IObservable observable(broker); + + globalCounter = 0; + + OrthancStone::IMessage genericMessage(OrthancStone::MessageType_Generic); + + // no observers have been registered -> nothing shall happen + observable.Emit(genericMessage); + + ASSERT_EQ(0, globalCounter); + + // register an observer, check it is called + MyObserver observer(broker); + observable.RegisterObserver(observer); + + observable.Emit(genericMessage); + + ASSERT_EQ(1, globalCounter); + + // check the observer is not called when another message is issued + OrthancStone::IMessage wrongMessage(OrthancStone::MessageType_GeometryReady); + // no observers have been registered + observable.Emit(wrongMessage); + + ASSERT_EQ(1, globalCounter); + + // unregister the observer, make sure nothing happens afterwards + observable.UnregisterObserver(observer); + observable.Emit(genericMessage); + ASSERT_EQ(1, globalCounter); +} + +TEST(MessageBroker, DeleteObserverWhileRegistered) +{ + OrthancStone::MessageBroker broker; + OrthancStone::IObservable observable(broker); + + globalCounter = 0; + + OrthancStone::IMessage genericMessage(OrthancStone::MessageType_Generic); + + { + // register an observer, check it is called + MyObserver observer(broker); + observable.RegisterObserver(observer); + + observable.Emit(genericMessage); + + ASSERT_EQ(1, globalCounter); + } + + // at this point, the observer has been deleted, the handle shall not be called again (and it shall not crash !) + observable.Emit(genericMessage); + + ASSERT_EQ(1, globalCounter); +}