Mercurial > hg > orthanc-stone
changeset 2312:ae031ceb217e refactoring
StoneApplication now manages the lifetime of the application
| author | Sebastien Jodogne <s.jodogne@gmail.com> |
|---|---|
| date | Tue, 29 Sep 2026 17:52:35 +0200 |
| parents | 448a74566925 |
| children | 46e57967b285 |
| files | Applications/Samples/Sdl/SingleFrameViewer/SdlSimpleViewer.cpp OrthancStone/Sources/Loaders/OracleScheduler.cpp OrthancStone/Sources/Loaders/OracleScheduler.h OrthancStone/Sources/StoneApplication.cpp OrthancStone/Sources/StoneApplication.h |
| diffstat | 5 files changed, 346 insertions(+), 79 deletions(-) [+] |
line wrap: on
line diff
--- a/Applications/Samples/Sdl/SingleFrameViewer/SdlSimpleViewer.cpp Tue Sep 29 12:10:57 2026 +0200 +++ b/Applications/Samples/Sdl/SingleFrameViewer/SdlSimpleViewer.cpp Tue Sep 29 17:52:35 2026 +0200 @@ -60,6 +60,7 @@ #include "../../../../OrthancStone/Sources/Oracle/SleepOracleCommand.h" #include "../../../../OrthancStone/Sources/StoneApplication.h" + class Toto : public OrthancStone::IOracleClient { public: @@ -89,7 +90,203 @@ } }; -static boost::shared_ptr<Toto> toto_(new Toto); +static boost::shared_ptr<Toto> toto_(new Toto); // TODO REMOVE + + +namespace OrthancStone +{ + class SingleWindowSdlApplication : public StoneApplication + { + private: + boost::shared_ptr<SdlViewport> viewport_; + + protected: + virtual void RunInternal(const boost::shared_ptr<Context>& context) + { + CreateComponents(context, viewport_); + + int scancodeCount = 0; + const uint8_t* keyboardState = SDL_GetKeyboardState(&scancodeCount); + + // SDL event loop + bool stop = false; + while (!stop) + { + bool paint = false; + SDL_Event event; + + while (SDL_PollEvent(&event)) + { + if (event.type == SDL_QUIT) + { + stop = true; + break; + } + else if (viewport_->IsRefreshEvent(event)) + { + paint = true; + } + else if (event.type == SDL_WINDOWEVENT && + (event.window.event == SDL_WINDOWEVENT_RESIZED || + event.window.event == SDL_WINDOWEVENT_SIZE_CHANGED)) + { + viewport_->UpdateSize(event.window.data1, event.window.data2); + } + else if (event.type == SDL_WINDOWEVENT && + (event.window.event == SDL_WINDOWEVENT_SHOWN || + event.window.event == SDL_WINDOWEVENT_EXPOSED)) + { + std::unique_ptr<OrthancStone::IViewport::ILock> lock(viewport_->Lock()); + lock->RefreshCanvasSize(); + } + else if (event.type == SDL_KEYDOWN && + event.key.repeat == 0 /* Ignore key bounce */) + { + switch (event.key.keysym.sym) + { + case SDLK_f: + viewport_->ToggleMaximize(); + break; + + case SDLK_q: + stop = true; + break; + + default: + HandleKeyDown(context, event.key); + } + } + else if (event.type == SDL_MOUSEBUTTONDOWN || + event.type == SDL_MOUSEMOTION || + event.type == SDL_MOUSEBUTTONUP) + { + std::unique_ptr<OrthancStone::IViewport::ILock> lock(viewport_->Lock()); + + if (lock->HasCompositor()) + { + OrthancStone::PointerEvent p; + OrthancStoneHelpers::GetPointerEvent(p, lock->GetCompositor(), event, keyboardState, scancodeCount); + + switch (event.type) + { + case SDL_MOUSEBUTTONDOWN: + // TODO + break; + + case SDL_MOUSEMOTION: + // TODO + break; + + case SDL_MOUSEBUTTONUP: + lock->GetController().HandleMouseRelease(p); + lock->Invalidate(); + break; + + default: + throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); + } + } + } + } + + if (paint) + { + viewport_->Paint(); + } + + // Small delay to avoid using 100% of CPU + SDL_Delay(1); + } + } + + virtual void CreateComponents(const boost::shared_ptr<Context>& context, + const boost::shared_ptr<IViewport>& viewport) = 0; + + virtual void HandleKeyDown(const boost::shared_ptr<Context>& context, + const SDL_KeyboardEvent& key) = 0; + + public: + SingleWindowSdlApplication(const Configuration& configuration, + const std::string& title, + unsigned int width, + unsigned int height) : + StoneApplication(configuration) + { +#if SAMPLE_USE_OPENGL == 1 + viewport_ = OrthancStone::SdlOpenGLViewport::Create(title, width, height); +#else + viewport_ = OrthancStone::SdlCairoViewport::Create(title, width, height); +#endif + + std::string font; + Orthanc::EmbeddedResources::GetFileResource(font, Orthanc::EmbeddedResources::UBUNTU_FONT); + + { + std::unique_ptr<OrthancStone::IViewport::ILock> lock(viewport_->Lock()); + lock->GetCompositor().SetFont(0, font, 16, Orthanc::Encoding_Latin1); + } + } + }; + + + class SimpleViewerApp : public SingleWindowSdlApplication + { + private: + boost::shared_ptr<Toto> toto_; + + protected: + virtual void CreateComponents(const boost::shared_ptr<Context>& context, + const boost::shared_ptr<IViewport>& viewport) ORTHANC_OVERRIDE + { + toto_.reset(new Toto); + } + + virtual void HandleKeyDown(const boost::shared_ptr<Context>& context, + const SDL_KeyboardEvent& key) ORTHANC_OVERRIDE + { + switch (key.keysym.sym) + { + case SDLK_b: + { + // TODO Refactoring + OrthancStone::IEnvironment& environment = context->GetEnvironment(); + OrthancStone::IOracle& oracle = context->GetOracle(); + + oracle.Submit(environment, toto_, new OrthancStone::SleepOracleCommand(1000)); + + { + std::unique_ptr<OrthancStone::HttpCommand> command(new OrthancStone::HttpCommand); + command->SetUrl("http://ip-api.com/json/"); + oracle.Submit(environment, toto_, command.release()); + } + + { + std::unique_ptr<OrthancStone::OrthancRestApiCommand> command(new OrthancStone::OrthancRestApiCommand); + command->SetUri("/system/"); + oracle.Submit(environment, toto_, command.release()); + } + + for (unsigned int i = 0; i < 10; i++) + { + DicomSource source; + source.SetDicomDirSource(); + oracle.Submit(environment, toto_, new OrthancStone::ParseDicomFromFileCommand(source, "hand.dcm")); + } + break; + } + + default: + break; + } + } + + public: + SimpleViewerApp(const Configuration& configuration) : + SingleWindowSdlApplication(configuration, "Stone of Orthanc", 800, 600) + { + } + }; +} // END TODO Refactoring @@ -204,7 +401,23 @@ //Orthanc::Logging::EnableInfoLevel(true); //Orthanc::Logging::EnableTraceLevel(true); + Orthanc::WebServiceParameters orthancWebService; + orthancWebService.SetUrl(orthancUrl); + + OrthancStone::StoneApplication::Configuration configuration; + configuration.SetRemoteOrthancParameters(orthancWebService); + configuration.SetDicomCacheSize(128 * 1024 * 1024); // TODO Refactoring - Remove this + configuration.SetRootDirectory("/tmp"); // TODO Refactoring - Remove this + + if (false) { + OrthancStone::SimpleViewerApp app(configuration); + app.Run(); + } + else + { + OrthancStone::StoneApplication::Initialize(configuration); + #if SAMPLE_USE_OPENGL == 1 boost::shared_ptr<OrthancStone::SdlViewport> viewport = OrthancStone::SdlOpenGLViewport::Create("Stone of Orthanc", 800, 600); @@ -213,20 +426,6 @@ OrthancStone::SdlCairoViewport::Create("Stone of Orthanc", 800, 600); #endif -#if SAMPLE_USE_ANNOTATIONS_LAYER != 1 - boost::shared_ptr<OrthancStone::UndoStack> undoStack(new OrthancStone::UndoStack); -#endif - - Orthanc::WebServiceParameters orthancWebService; - orthancWebService.SetUrl(orthancUrl); - - OrthancStone::StoneApplication::Configuration configuration; - configuration.SetRemoteOrthancParameters(orthancWebService); - configuration.SetDicomCacheSize(128 * 1024 * 1024); // TODO Refactoring - Remove this - configuration.SetRootDirectory("/tmp"); // TODO Refactoring - Remove this - - OrthancStone::StoneApplication::Initialize(configuration); - OrthancStone::GenericLoadersContext context(1, 4, 1); { @@ -238,7 +437,7 @@ lock->GetCompositor().SetFont(0, font, 16, Orthanc::Encoding_Latin1); #if SAMPLE_USE_ANNOTATIONS_LAYER != 1 - lock->GetController().SetUndoStack(undoStack); + lock->GetController().SetUndoStack(new OrthancStone::UndoStack); #endif } @@ -596,6 +795,8 @@ } } } + + OrthancStone::StoneApplication::Finalize(); } } catch (Orthanc::OrthancException& e) @@ -620,7 +821,6 @@ } OrthancStone::SdlWindow::GlobalFinalize(); - OrthancStone::StoneApplication::Finalize(); OrthancStone::StoneFinalize(); return status;
--- a/OrthancStone/Sources/Loaders/OracleScheduler.cpp Tue Sep 29 12:10:57 2026 +0200 +++ b/OrthancStone/Sources/Loaders/OracleScheduler.cpp Tue Sep 29 17:52:35 2026 +0200 @@ -424,7 +424,7 @@ } - OracleScheduler::OracleScheduler(StoneApplication& application, + OracleScheduler::OracleScheduler(StoneApplication::Context& application, unsigned int maxHighPriority, unsigned int maxStandardPriority, unsigned int maxLowPriority) : @@ -449,7 +449,7 @@ } - boost::shared_ptr<OracleScheduler> OracleScheduler::Create(StoneApplication& application, + boost::shared_ptr<OracleScheduler> OracleScheduler::Create(StoneApplication::Context& application, unsigned int maxHighPriority, unsigned int maxStandardPriority, unsigned int maxLowPriority)
--- a/OrthancStone/Sources/Loaders/OracleScheduler.h Tue Sep 29 12:10:57 2026 +0200 +++ b/OrthancStone/Sources/Loaders/OracleScheduler.h Tue Sep 29 17:52:35 2026 +0200 @@ -66,7 +66,7 @@ typedef std::multimap<int, ScheduledCommand*> Queue; - StoneApplication& application_; + StoneApplication::Context& application_; Queue standardPriorityQueue_; Queue highPriorityQueue_; Queue lowPriorityQueue_; @@ -112,18 +112,18 @@ void Handle(const OracleCommandExceptionMessage& message); - OracleScheduler(StoneApplication& application, + OracleScheduler(StoneApplication::Context& application, unsigned int maxHighPriority, unsigned int maxStandardPriority, unsigned int maxLowPriority); public: - static boost::shared_ptr<OracleScheduler> Create(StoneApplication& application) + static boost::shared_ptr<OracleScheduler> Create(StoneApplication::Context& application) { return Create(application, 1, 4, 1); } - static boost::shared_ptr<OracleScheduler> Create(StoneApplication& application, + static boost::shared_ptr<OracleScheduler> Create(StoneApplication::Context& application, unsigned int maxHighPriority, unsigned int maxStandardPriority, unsigned int maxLowPriority);
--- a/OrthancStone/Sources/StoneApplication.cpp Tue Sep 29 12:10:57 2026 +0200 +++ b/OrthancStone/Sources/StoneApplication.cpp Tue Sep 29 17:52:35 2026 +0200 @@ -23,6 +23,8 @@ #include "StoneApplication.h" +#include "StoneException.h" + #include <Compatibility.h> #include <Logging.h> #include <MultiThreading/Mutex.h> @@ -117,7 +119,7 @@ #if ORTHANC_STONE_TARGET_PLATFORM_WASM == 1 - class StoneApplication::PImpl + class StoneApplication::Context::PImpl { private: class Emitter : public IMessageEmitter // TODO Refactoring - Remove this @@ -180,7 +182,7 @@ #if ORTHANC_STONE_TARGET_PLATFORM_NATIVE == 1 - class StoneApplication::PImpl + class StoneApplication::Context::PImpl { private: class Emitter : public IMessageEmitter // TODO Refactoring - Remove this @@ -262,10 +264,7 @@ #endif - static Orthanc::Mutex applicationMutex_; - static std::unique_ptr<StoneApplication> application_; - - StoneApplication::StoneApplication(const Configuration& configuration) + StoneApplication::Context::Context(const Configuration& configuration) { #if ORTHANC_STONE_TARGET_PLATFORM_WASM == 1 pimpl_ = new PImpl(configuration); @@ -277,14 +276,86 @@ } - StoneApplication::~StoneApplication() + StoneApplication::Context::~Context() { assert(pimpl_ != NULL); delete pimpl_; } - StoneApplication& StoneApplication::GetInstance() + IEnvironment& StoneApplication::Context::GetEnvironment() + { + assert(pimpl_ != NULL); + return pimpl_->GetEnvironment(); + } + + + IOracle& StoneApplication::Context::GetOracle() + { + assert(pimpl_ != NULL); + return pimpl_->GetOracle(); + } + + + void StoneApplication::Context::EmitMessage(boost::weak_ptr<IObserver> observer, + const IMessage& message) + { + assert(pimpl_ != NULL); + return pimpl_->GetMessageEmitter().EmitMessage(observer, message); + } + + + IObservable& StoneApplication::Context::GetOracleObservable() + { + assert(pimpl_ != NULL); + return pimpl_->GetOracleObservable(); + } + + + bool StoneApplication::Run() + { + try + { + boost::shared_ptr<Context> context(new Context(configuration_)); + + assert(context.get() != NULL); + assert(context->pimpl_ != NULL); + + context->pimpl_->Start(); + + RunInternal(context); + + context->pimpl_->Stop(); + + return true; + } + catch (Orthanc::OrthancException& e) + { + LOG(ERROR) << "OrthancException: " << e.What(); + return false; + } + catch (StoneException& e) + { + LOG(ERROR) << "StoneException: " << e.What(); + return false; + } + catch (std::runtime_error& e) + { + LOG(ERROR) << "Runtime error: " << e.what(); + return false; + } + catch (...) + { + LOG(ERROR) << "Native exception"; + return false; + } + } + + + static Orthanc::Mutex applicationMutex_; // TODO Refactoring - Remove this + static std::unique_ptr<StoneApplication::Context> application_; // TODO Refactoring - Remove this + + StoneApplication::Context& StoneApplication::GetInstance() { Orthanc::Mutex::ScopedLock lock(applicationMutex_); @@ -303,7 +374,7 @@ if (application_.get() == NULL) { - application_.reset(new StoneApplication(configuration)); + application_.reset(new StoneApplication::Context(configuration)); application_->pimpl_->Start(); } else @@ -323,33 +394,4 @@ application_.reset(NULL); } } - - - IEnvironment& StoneApplication::GetEnvironment() - { - assert(pimpl_ != NULL); - return pimpl_->GetEnvironment(); - } - - - IOracle& StoneApplication::GetOracle() - { - assert(pimpl_ != NULL); - return pimpl_->GetOracle(); - } - - - void StoneApplication::EmitMessage(boost::weak_ptr<IObserver> observer, - const IMessage& message) - { - assert(pimpl_ != NULL); - return pimpl_->GetMessageEmitter().EmitMessage(observer, message); - } - - - IObservable& StoneApplication::GetOracleObservable() - { - assert(pimpl_ != NULL); - return pimpl_->GetOracleObservable(); - } }
--- a/OrthancStone/Sources/StoneApplication.h Tue Sep 29 12:10:57 2026 +0200 +++ b/OrthancStone/Sources/StoneApplication.h Tue Sep 29 17:52:35 2026 +0200 @@ -34,7 +34,7 @@ namespace OrthancStone { - class StoneApplication : public IMessageEmitter // TODO Refactoring - Remove this + class StoneApplication : public boost::noncopyable { public: class Configuration @@ -102,30 +102,55 @@ } }; - private: - class Emitter; // TODO Refactoring - Remove this + + class Context : public IMessageEmitter // TODO Refactoring - Remove this + { + friend class StoneApplication; + + private: + class Emitter; // TODO Refactoring - Remove this + + class PImpl; + PImpl* pimpl_; + + public: + Context(const Configuration& configuration); + + ~Context(); - class PImpl; - PImpl* pimpl_; + IEnvironment& GetEnvironment(); + + IOracle& GetOracle(); + + virtual void EmitMessage(boost::weak_ptr<IObserver> observer, + const IMessage& message) ORTHANC_OVERRIDE; - StoneApplication(const Configuration& configuration); + IObservable& GetOracleObservable(); // TODO Refactoring - Remove this + }; + + + private: + Configuration configuration_; + + protected: + virtual void RunInternal(const boost::shared_ptr<Context>& context) = 0; public: - static void Initialize(const Configuration& configuration); - - static StoneApplication& GetInstance(); - - static void Finalize(); - - ~StoneApplication(); + StoneApplication(const Configuration& configuration) : + configuration_(configuration) + { + } - IEnvironment& GetEnvironment(); + virtual ~StoneApplication() + { + } - IOracle& GetOracle(); + bool Run(); - virtual void EmitMessage(boost::weak_ptr<IObserver> observer, - const IMessage& message) ORTHANC_OVERRIDE; + static void Initialize(const Configuration& configuration); // TODO Refactoring - Remove this - IObservable& GetOracleObservable(); // TODO Refactoring - Remove this + static StoneApplication::Context& GetInstance(); // TODO Refactoring - Remove this + + static void Finalize(); // TODO Refactoring - Remove this }; }
