diff --git a/Modules/Annotation/include/mitkAnnotationFactory.h b/Modules/Annotation/include/mitkAnnotationFactory.h index b9d2825281..59565b9038 100644 --- a/Modules/Annotation/include/mitkAnnotationFactory.h +++ b/Modules/Annotation/include/mitkAnnotationFactory.h @@ -1,98 +1,81 @@ #pragma once #include "MitkAnnotationExports.h" #include "mitkAnnotation.h" #include "mitkCommon.h" +#include "mitkDynamicAnnotation.h" #include "mitkLayoutAnnotationRenderer.h" #include #include #include -#include "DynamicAnnotationWrapper.h" -#include "mitkDynamicAnnotation.h" namespace mitk { - namespace AnnotationConstants - { - const std::string NAME = "name"; - const std::string DEFAULT = "defaultValue"; - const std::string PREFIX = "prefix"; - const std::string SUFFIX = "suffix"; - const std::string LAYOUT = "layout"; - const std::string TYPE = "type"; - const std::string PROVIDER = "provider"; - const std::string EVENT = "event"; - const std::string ACTION = "action"; - const std::string WINDOW = "window"; - const std::string SLICENAVIGATIONCONTROLLER = "SliceNavigationController"; - } // namespace AnnotationConstants - /* * Responsibilities * Read json configuration * Create Annotations * Listen to slice change events * Observe (relevant) property modification and deletion * Data container for dynamic annotations */ class MITKANNOTATION_EXPORT AnnotationFactory : public itk::Object { public: - public: mitkClassMacroNoParent(AnnotationFactory); itkFactorylessNewMacro(AnnotationFactory); using ActionFunctionMap = std::unordered_map; using EventMap = std::unordered_map; void CreateAnnotationsFromJson(const std::string &fileName, ActionFunctionMap actionFunctionMap = ActionFunctionMap(), EventMap eventMap = EventMap()); void SetProviderForAnnotation(itk::Object::Pointer provider, DynamicAnnotation &annotation); void AddSingleAnnotation(DynamicAnnotation annotation); + Annotation::Pointer GetAnnotationByName(const std::string &name); void SetProvider(const std::string &providerJsonKey, itk::Object::Pointer provider); void SetProviderForAllPropertyAnnotations(BaseData *provider); std::vector GetManagedAnnotationIds(); unsigned int GetAmountOfPendingAnnotations(); void SaveConfigurationToJsonFile(const std::string &fileName); bool Update(); - void SliceChanged(const Object *caller, const itk::EventObject &event); + void SliceChanged(Object *caller, const itk::EventObject &event); private: using AnnotationVector = std::vector; - static std::vector JsonToAnnotationInfoVector( - boost::property_tree::ptree const &root); + static std::vector JsonToAnnotationInfoVector(boost::property_tree::ptree const &root); LayoutAnnotationRenderer::Alignment GetAlignment(const std::string alignmentName) const; - void ObserveSliceChangedEvents(BaseRenderer* renderer); + void ObserveSliceChangedEvents(BaseRenderer *renderer); bool RegisterAnnotation(DynamicAnnotation dynamicAnnotation); void OnPropertyDeleted(const itk::Object *caller, const itk::EventObject &event); void OnPropertyModified(const itk::Object *caller, const itk::EventObject &event); AnnotationVector m_Annotations; AnnotationVector m_WaitingAnnotations; std::unordered_map m_SliceNavigationControllerTags; std::weak_ptr m_PropertyListOwner; WeakPointer m_PropertyProvider; unsigned m_Slice; unsigned m_TimeStep; const std::unordered_map m_Defaults = { {AnnotationConstants::NAME, "Unnamed Annotation"}, {AnnotationConstants::DEFAULT, "NA"}, {AnnotationConstants::PREFIX, ""}, {AnnotationConstants::SUFFIX, ""}, {AnnotationConstants::TYPE, "text"}, {AnnotationConstants::PROVIDER, ""}, {AnnotationConstants::EVENT, ""}, {AnnotationConstants::ACTION, ""}, {AnnotationConstants::WINDOW, "stdmulti.widget1"}, {AnnotationConstants::LAYOUT, "TopLeft"}, }; }; } // namespace mitk diff --git a/Modules/Annotation/include/mitkDynamicAnnotation.h b/Modules/Annotation/include/mitkDynamicAnnotation.h index d349e79dba..9ae4e8d5cb 100644 --- a/Modules/Annotation/include/mitkDynamicAnnotation.h +++ b/Modules/Annotation/include/mitkDynamicAnnotation.h @@ -1,136 +1,158 @@ #pragma once #include "mitkAnnotation.h" #include "mitkLogMacros.h" #include #include #include #include #include -//namespace mitk +// namespace mitk //{ // class DataProvider : public itk::Object // { // public: // using OnEventAction = std::function; // mitkClassMacroItkParent(DataProvider, itk::Object); // mitkNewMacro4Param(DataProvider, std::string, WeakPointer, itk::EventObject *, OnEventAction); // // std::string Fetch() { return m_Result; }; // template // std::string Fetch(Args...); // // protected: -// DataProvider(std::string name, WeakPointer provider, itk::EventObject *trigger, OnEventAction action); +// DataProvider(std::string name, WeakPointer provider, itk::EventObject *trigger, OnEventAction +// action); // // std::string m_Name; // WeakPointer m_Provider; // const itk::EventObject *m_Trigger; // OnEventAction m_Action; // std::string m_Result; // // std::vector tags; // }; // class SliceProvider : public DataProvider // { // SliceProvider(WeakPointer sliceNavigationController) // : DataProvider("slice", // sliceNavigationController.Lock().GetPointer(), // SliceNavigationController::GeometrySliceEvent(nullptr, 0).MakeObject(), // [](const itk::Object *caller, const itk::EventObject &event) { // auto sliceEvent = dynamic_cast(&event); // if (sliceEvent) // { // return std::to_string(sliceEvent->GetPos()); // } // return std::string{"Slice Error"}; // }){}; // }; // class TimeProvider : public DataProvider // { // TimeProvider(WeakPointer sliceNavigationController) // : DataProvider("timeStep", // sliceNavigationController.Lock().GetPointer(), // SliceNavigationController::GeometryTimeEvent(nullptr, 0).MakeObject(), // [](const itk::Object *caller, const itk::EventObject &event) { // auto timeEvent = dynamic_cast(&event); // if (timeEvent) // { // return std::to_string(timeEvent->GetPos()); // } // return std::string{"Time Error"}; // }){}; // }; // template // class DependantProvider : public DataProvider // { // DependantProvider(); // // void SetProviders(Providers... providers) { m_Providers = std::tuple{providers...}; } // // virtual std::string Fetch(Providers... providers) = 0; // // std::tuple m_Providers; // }; // // class DicomProvider : public DependantProvider // { // std::string Fetch(SliceProvider sliceProvider, TimeProvider timeProvider) override // { -// +// // }; // }; // // // SetText("Nr. " + DicomProvider.fetch(SliceProvider.fetch(), TimeProvider.fetch(), // // BaseData->GetProp("DICOM.0010.0010")); // // class DynamicAnnotation : public itk::Object // { // using Config = std::unordered_map; // using ProviderCollection = std::vector; // using TextSetter = std::function)>; // // public: // mitkClassMacroItkParent(DynamicAnnotation, itk::Object); // mitkNewMacro2Param(DynamicAnnotation, Annotation::Pointer, Config); // // void AddProvider(DataProvider::Pointer provider); // void SetTextAssemblyFunction(TextSetter function); // // private: // DynamicAnnotation(Annotation::Pointer annotation, std::unordered_map config); // // mitk::Annotation::Pointer m_Annotation; // Config m_Config; // ProviderCollection m_Providers; // }; //} // namespace mitk - namespace mitk +namespace mitk { + namespace AnnotationConstants + { + const std::string NAME = "name"; + const std::string DEFAULT = "defaultValue"; + const std::string PREFIX = "prefix"; + const std::string SUFFIX = "suffix"; + const std::string LAYOUT = "layout"; + const std::string TYPE = "type"; + const std::string PROVIDER = "provider"; + const std::string EVENT = "event"; + const std::string ACTION = "action"; + const std::string WINDOW = "window"; + const std::string SLICENAVIGATIONCONTROLLER = "SliceNavigationController"; + } // namespace AnnotationConstants + struct DynamicAnnotation { - using OnEventAction = - std::function; + using OnEventAction = std::function; using OnSliceChanged = std::function; using OnTimeStepChanged = std::function; DynamicAnnotation() : ptr(nullptr), config({}), providerInfo(DataProvider()) { MITK_INFO << "DynamicAnnotation constructor"; }; mitk::Annotation::Pointer ptr; std::unordered_map config; struct DataProvider { DataProvider() : object(nullptr), dataChangedEvent(nullptr) { MITK_INFO << "DataProvider constructor"; }; itk::Object::Pointer object; const itk::EventObject *dataChangedEvent; OnEventAction dataRetrievalAction; OnSliceChanged sliceChanged; OnTimeStepChanged timeStepChanged; std::vector tags; } providerInfo; + void SetText(const std::string &text) + { + const auto &prefix = this->config[AnnotationConstants::PREFIX]; + const auto &suffix = this->config[AnnotationConstants::SUFFIX]; + this->ptr->SetText(prefix + text + suffix); + } }; } // namespace mitk \ No newline at end of file diff --git a/Modules/Annotation/src/mitkAnnotationFactory.cpp b/Modules/Annotation/src/mitkAnnotationFactory.cpp index b433457823..3c94062526 100644 --- a/Modules/Annotation/src/mitkAnnotationFactory.cpp +++ b/Modules/Annotation/src/mitkAnnotationFactory.cpp @@ -1,366 +1,396 @@ #include "mitkAnnotationFactory.h" -#include "DynamicAnnotationWrapper.h" #include "mitkAnnotationUtils.h" +#include "mitkColorBarAnnotation.h" +#include "mitkDynamicAnnotation.h" #include "mitkLayoutAnnotationRenderer.h" +#include "mitkLogoAnnotation.h" +#include "mitkScaleLegendAnnotation.h" #include "mitkTemporoSpatialStringProperty.h" #include "mitkTextAnnotation2D.h" #include #include -#include "mitkDynamicAnnotation.h" class PropertyDeletedCommand : public itk::Command { public: void Execute(Object *caller, const itk::EventObject &event) override { Execute(const_cast(caller), event); }; void Execute(const Object *caller, const itk::EventObject &event) override { MITK_INFO << "Property " << caller->GetNameOfClass() << " deleted"; }; }; class ItkRetrievalCommand : public itk::Command { mitk::DynamicAnnotation::OnEventAction m_OnEventAction; std::string m_AnnotationId; public: ItkRetrievalCommand(mitk::DynamicAnnotation::OnEventAction dataRetrievalAction, const std::string &annotationId) : m_OnEventAction(dataRetrievalAction), m_AnnotationId(annotationId){}; void Execute(Object *caller, const itk::EventObject &event) override { Execute(const_cast(caller), event); }; void Execute(const Object *caller, const itk::EventObject &event) override { auto annotation = mitk::AnnotationUtils::GetAnnotation(m_AnnotationId); if (annotation) { // TODO remove hardcoded 0 slice and time auto updatedText = m_OnEventAction(caller, event, 0, 0); MITK_INFO << "Annotation " << annotation->GetName() << " set to " << updatedText; annotation->SetText(updatedText); } }; }; std::vector mitk::AnnotationFactory::JsonToAnnotationInfoVector( boost::property_tree::ptree const &root) { std::vector elements; auto annotations = root.begin(); if (annotations->first == "annotations") { for (const auto &window : annotations->second) { for (const auto &layout : window.second) { for (const auto &object : layout.second) { DynamicAnnotation annotation; annotation.config[AnnotationConstants::WINDOW] = window.first; annotation.config[AnnotationConstants::LAYOUT] = layout.first; for (const auto &property : object.second) { annotation.config[property.first] = property.second.get_value(); } if (annotation.config[AnnotationConstants::DEFAULT].empty()) { annotation.config[AnnotationConstants::DEFAULT] = annotation.config[AnnotationConstants::NAME]; } elements.push_back(annotation); } } } } return elements; } mitk::LayoutAnnotationRenderer::Alignment mitk::AnnotationFactory::GetAlignment(const std::string alignmentName) const { static const auto alignmentMap = std::unordered_map{ {"TopLeft", LayoutAnnotationRenderer::TopLeft}, {"Top", LayoutAnnotationRenderer::Top}, {"TopRight", LayoutAnnotationRenderer::TopRight}, {"Left", LayoutAnnotationRenderer::Left}, {"Right", LayoutAnnotationRenderer::Right}, {"BottomLeft", LayoutAnnotationRenderer::BottomLeft}, {"Bottom", LayoutAnnotationRenderer::Bottom}, {"BottomRight", LayoutAnnotationRenderer::BottomRight}}; const auto alignment = alignmentMap.find(alignmentName); const auto &defaultFallback = m_Defaults.at(AnnotationConstants::LAYOUT); return alignment != std::end(alignmentMap) ? alignment->second : alignmentMap.at(defaultFallback); } void mitk::AnnotationFactory::ObserveSliceChangedEvents(BaseRenderer *renderer) { if (!renderer) return; auto name = renderer->GetName(); if (m_SliceNavigationControllerTags.find(name) == std::end(m_SliceNavigationControllerTags)) { auto sliceCommand = itk::MemberCommand::New(); sliceCommand->SetCallbackFunction(this, &AnnotationFactory::SliceChanged); auto sliceController = renderer->GetSliceNavigationController(); auto tag = sliceController->AddObserver(SliceNavigationController::GeometrySliceEvent(nullptr, 0), sliceCommand); m_SliceNavigationControllerTags.insert({name, tag}); } } bool mitk::AnnotationFactory::RegisterAnnotation(DynamicAnnotation dynamicAnnotation) { const auto alignment = GetAlignment(dynamicAnnotation.config[AnnotationConstants::LAYOUT]); dynamicAnnotation.ptr->SetName(dynamicAnnotation.config[AnnotationConstants::NAME]); dynamicAnnotation.ptr->SetText(dynamicAnnotation.config[AnnotationConstants::DEFAULT]); MITK_INFO << dynamicAnnotation.config[AnnotationConstants::NAME]; const auto renderer = BaseRenderer::GetByName(dynamicAnnotation.config[AnnotationConstants::WINDOW]); if (renderer) { ObserveSliceChangedEvents(renderer); LayoutAnnotationRenderer::AddAnnotation(dynamicAnnotation.ptr, renderer, alignment); m_Annotations.push_back(dynamicAnnotation); // TODO wait so each annotation gets a unique id see T25927 std::this_thread::sleep_for(std::chrono::seconds(2)); if (dynamicAnnotation.config[AnnotationConstants::PROVIDER] == AnnotationConstants::SLICENAVIGATIONCONTROLLER) { SetProviderForAnnotation(renderer->GetSliceNavigationController(), dynamicAnnotation); } return true; } return false; } -void mitk::AnnotationFactory::SliceChanged(const Object *caller, const itk::EventObject &event) +void mitk::AnnotationFactory::SliceChanged(Object *caller, const itk::EventObject &event) { auto geometryEvent = dynamic_cast(&event); if (!geometryEvent) return; m_Slice = geometryEvent->GetPos(); auto sliceNavController = dynamic_cast(caller); if (!sliceNavController) return; auto renderer = sliceNavController->GetRenderer(); if (!renderer) return; auto rendererName = renderer->GetName(); for (auto &annotation : m_Annotations) { if (annotation.config[AnnotationConstants::TYPE] == "property" && annotation.config[AnnotationConstants::WINDOW] == rendererName) { - annotation.ptr->SetText(annotation.providerInfo.dataRetrievalAction( + annotation.SetText(annotation.providerInfo.dataRetrievalAction( annotation.providerInfo.object, *annotation.providerInfo.dataChangedEvent, m_Slice, m_TimeStep)); } } } void mitk::AnnotationFactory::CreateAnnotationsFromJson(const std::string &fileName, ActionFunctionMap actionFunctionMap, EventMap eventMap) { boost::property_tree::ptree root; read_json(R"(D:\Arbeit\Programming\mitk_m\Plugins\org.mitk.annotations\resources\annotations.json)", root); auto annotations = JsonToAnnotationInfoVector(root); for (auto annotation : annotations) { - auto type = annotation.config[AnnotationConstants::TYPE]; - if (type == "text" || type == "property") + const auto &type = annotation.config[AnnotationConstants::TYPE]; + if (type == "text") + { + annotation.ptr = mitk::TextAnnotation2D::New(); + } + else if (type == "property") { annotation.ptr = mitk::TextAnnotation2D::New(); annotation.providerInfo.dataChangedEvent = itk::ModifiedEvent().MakeObject(); - auto defaultName = annotation.config[AnnotationConstants::DEFAULT]; + const auto &defaultName = annotation.config[AnnotationConstants::DEFAULT]; annotation.providerInfo.dataRetrievalAction = [defaultName](const itk::Object *caller, const itk::EventObject &, unsigned int slice, unsigned int timeStep) { auto dicomProperty = dynamic_cast(caller); if (dicomProperty) { return dicomProperty->GetValueBySlice(slice); } auto property = dynamic_cast(caller); if (property) { return property->GetValueAsString(); } return defaultName + " (NA)"; }; } else if (type == "custom") { if (annotation.config[AnnotationConstants::EVENT].empty() || annotation.config[AnnotationConstants::ACTION].empty()) { throw std::logic_error("A custom annotation needs to have an event and an action specified"); } annotation.ptr = TextAnnotation2D::New(); annotation.providerInfo.dataChangedEvent = eventMap[annotation.config[AnnotationConstants::EVENT]]; annotation.providerInfo.dataRetrievalAction = actionFunctionMap[annotation.config[AnnotationConstants::ACTION]]; } + else if (type == "colorBar") + { + annotation.ptr = ColorBarAnnotation::New(); + } + else if (type == "scaleLegend") + { + annotation.ptr = ScaleLegendAnnotation::New(); + } + else if (type == "logo") + { + annotation.ptr = LogoAnnotation::New(); + } else { throw std::logic_error("Unknown or missing annotation type"); } if (!RegisterAnnotation(annotation)) { - // Registration of annotation failed propbably due to missing base renderer + // Registration of annotation failed probably due to missing base renderer // Store annotation for delayed registration m_WaitingAnnotations.push_back(annotation); } } } void mitk::AnnotationFactory::SetProviderForAnnotation(itk::Object::Pointer provider, DynamicAnnotation &annotation) { if (provider.IsNotNull() && provider != annotation.providerInfo.object) { if (annotation.providerInfo.object) { for (const auto &tag : annotation.providerInfo.tags) { annotation.providerInfo.object->RemoveObserver(tag); } } annotation.providerInfo.object = provider; if (annotation.providerInfo.dataChangedEvent) { annotation.providerInfo.tags.push_back(annotation.providerInfo.object->AddObserver( *annotation.providerInfo.dataChangedEvent, new ItkRetrievalCommand(annotation.providerInfo.dataRetrievalAction, annotation.ptr->GetMicroserviceID()))); } if (annotation.config[AnnotationConstants::TYPE] == "property") { annotation.providerInfo.tags.push_back( annotation.providerInfo.object->AddObserver(itk::DeleteEvent(), new PropertyDeletedCommand())); } } } void mitk::AnnotationFactory::AddSingleAnnotation(DynamicAnnotation annotation) { if (annotation.ptr) { try { auto id = annotation.ptr->GetMicroserviceID(); if (AnnotationUtils::GetAnnotation(id)) { // The annotation has already been fully set up so just add it to the managed annotations m_Annotations.push_back(annotation); } else { MITK_ERROR << "An annotation with a valid ID can't be fetched through the microservice registry. Not adding it " "to the managed annotations"; } } catch (const std::logic_error &e) { MITK_ERROR << e.what() << "\nWhen adding single annotations they should already be registered through a layout renderer. " "Trying this for you now."; // The annotation probably hasn't been registered yet so try it if (!RegisterAnnotation(annotation)) { m_WaitingAnnotations.push_back(annotation); } } } } +mitk::Annotation::Pointer mitk::AnnotationFactory::GetAnnotationByName(const std::string &name) +{ + for (const auto &annotation : m_Annotations) + { + if (annotation.ptr->GetName() == name) + { + return annotation.ptr; + } + } + return nullptr; +} + void mitk::AnnotationFactory::SetProvider(const std::string &providerJsonKey, itk::Object::Pointer provider) { - for (auto annotation : m_Annotations) + for (auto &annotation : m_Annotations) { if (providerJsonKey == annotation.config[AnnotationConstants::PROVIDER]) { SetProviderForAnnotation(provider, annotation); } } } void mitk::AnnotationFactory::SetProviderForAllPropertyAnnotations(BaseData *provider) { Update(); // TODO temporary semi fix if (provider) { if (!m_PropertyProvider.IsExpired()) { // TODO unsubscribe } m_PropertyProvider = provider->GetPropertyList(); if (!m_PropertyProvider.IsExpired()) { m_PropertyProvider.Lock()->AddObserver(itk::ModifiedEvent(), new PropertyDeletedCommand()); m_PropertyProvider.Lock()->AddObserver(itk::DeleteEvent(), new PropertyDeletedCommand()); } } for (auto &annotation : m_Annotations) { if (annotation.config[AnnotationConstants::TYPE] != "property") continue; // if provider has property auto propertyName = annotation.config[AnnotationConstants::PROVIDER]; auto property = provider->GetProperty(propertyName.c_str()); if (property) { // set provider (in case the property exists but is empty state this in the annotations text SetProviderForAnnotation(property.GetPointer(), annotation); annotation.ptr->SetColor(0, 200, 0); - annotation.ptr->SetText(annotation.providerInfo.dataRetrievalAction( + annotation.SetText(annotation.providerInfo.dataRetrievalAction( annotation.providerInfo.object, *annotation.providerInfo.dataChangedEvent, 0, 0)); if (annotation.ptr->GetText().empty()) { annotation.ptr->SetColor(0, 0, 200); - annotation.ptr->SetText(annotation.config[AnnotationConstants::DEFAULT] + " (empty)"); + annotation.SetText(annotation.config[AnnotationConstants::DEFAULT] + " (empty)"); } } else { annotation.ptr->SetColor(200, 0, 0); - annotation.ptr->SetText(annotation.config[AnnotationConstants::DEFAULT] + " (NA)"); + annotation.SetText(annotation.config[AnnotationConstants::DEFAULT] + " (NA)"); } } } std::vector mitk::AnnotationFactory::GetManagedAnnotationIds() { auto ids = std::vector{}; for (const auto &annotation : m_Annotations) { ids.push_back(annotation.ptr->GetMicroserviceID()); } return ids; } unsigned mitk::AnnotationFactory::GetAmountOfPendingAnnotations() { return m_WaitingAnnotations.size(); } bool mitk::AnnotationFactory::Update() { const auto firstElementToErase = std::remove_if(m_WaitingAnnotations.begin(), m_WaitingAnnotations.end(), [this](DynamicAnnotation da) { return RegisterAnnotation(da); }); m_WaitingAnnotations.erase(firstElementToErase, m_WaitingAnnotations.end()); return m_WaitingAnnotations.empty(); } diff --git a/Plugins/org.mitk.annotations/resources/annotations.json b/Plugins/org.mitk.annotations/resources/annotations.json index fde0c1e59e..7b39499469 100644 --- a/Plugins/org.mitk.annotations/resources/annotations.json +++ b/Plugins/org.mitk.annotations/resources/annotations.json @@ -1,141 +1,154 @@ { "annotations" : { + "stdmulti.widget3" : { + "Right": + [ + { + "name": "colorBar", + "type": "colorBar" + }, + { + "name": "scaleLegend", + "type": "scaleLegend" + } + ] + }, "stdmulti.widget1" : { "TopLeft": [ { "name": "Slice Number", "defaultValue": "Slice / MaxSlice", "prefix": "Im: ", "type": "property", "provider": "DICOM.0020.0013" - }, + }, { "name": "Sequence Number", "defaultValue": "Sequence ?", "prefix": "Se: ", "type": "property", "provider": "DICOM.0020.0011" }, { "name": "SliceNavigationControllerNumber", "defaultValue": "Slice Nr. ?", "prefix": "Se: ", "type": "custom", "provider": "SliceNavigationController", "event": "GeometrySliceEvent", "action": "SliceNumberAction" } ], "Top": [{ "name": "A", "type": "text" }], "TopRight": [ { "name": "Patient Name", "type": "property", "provider": "DICOM.0010.0010" }, { "name": "Patient ID", "type": "property", "provider": "DICOM.0010.0020" }, { "name": "Patient Birth Date", "type": "property", "provider": "DICOM.0010.0030" }, { "name": "Patient Sex", "type": "property", "provider": "DICOM.0010.0040" }, { "name": "Institution Name", "type": "property", "provider": "DICOM.0008.0080" }, { "name": "Study ID", "type": "property", "provider": "DICOM.0020.0010" }, { "name": "Study Description", "type": "property", "provider": "DICOM.0008.1030" }, { "name": "Series Description", "type": "property", "provider": "DICOM.0008.103E" } ], "Left": [{ "name": "R", "type": "text" }], "Right":[{ "name": "L", "type": "text" }], "BottomLeft": [ { "name": "Pixel(x,y,Val)", "type": "text" }, { "name": "Slice Thickness", "defaultValue": "Unknown Thickness", "prefix": "T: ", "suffix": " mm", "type": "property", "provider": "DICOM.0018.0050" }, { "name": "Image Z Position", "prefix": "L: ", "type": "property", "provider": "DICOM.0020.0032" } ], "BottomRight": [ { "name": "FS: 1", "type": "text" }, { "name": "Repetition Time", "prefix": "TR: ", "type": "property", "provider": "DICOM.0018.0080" }, { "name": "Echo Time", "prefix": "TE: ", "type": "property", "provider": "DICOM.0018.0081" }, { "name": "Acquisition Date", "type": "property", "provider": "DICOM.0008.0022" }, { "name": "Acquisition Time", "type": "property", "provider": "DICOM.0008.0032" } ], "Bottom":[{ "name": "P", "type": "text" }] } } } \ No newline at end of file diff --git a/Plugins/org.mitk.annotations/src/internal/mitkAnnotationsActivator.cpp b/Plugins/org.mitk.annotations/src/internal/mitkAnnotationsActivator.cpp index 33da8876f3..403d9472b5 100644 --- a/Plugins/org.mitk.annotations/src/internal/mitkAnnotationsActivator.cpp +++ b/Plugins/org.mitk.annotations/src/internal/mitkAnnotationsActivator.cpp @@ -1,77 +1,86 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkAnnotationsActivator.h" #include "berryISelectionService.h" #include "berryPlatformUI.h" #include "mitkAnnotationFactory.h" #include "mitkDataNodeSelection.h" -void mitk::AnnotationsActivator::start(ctkPluginContext * /*context*/) +void mitk::AnnotationsActivator::start(ctkPluginContext *context) { m_AnnotationFactory = AnnotationFactory::New(); - auto sliceNumberAction = [](const itk::Object *caller, const itk::EventObject &event, unsigned int slice, unsigned int timeStep) { - auto sliceEvent = dynamic_cast(&event); - if (sliceEvent) - { - return std::to_string(sliceEvent->GetPos()); - } - return std::string(); - }; + auto sliceNumberAction = + [](const itk::Object *caller, const itk::EventObject &event, unsigned int slice, unsigned int timeStep) { + auto sliceEvent = dynamic_cast(&event); + if (sliceEvent) + { + return std::to_string(sliceEvent->GetPos()); + } + return std::string(); + }; AnnotationFactory::ActionFunctionMap actions{{"SliceNumberAction", sliceNumberAction}}; AnnotationFactory::EventMap events{ {"GeometrySliceEvent", SliceNavigationController::GeometrySliceEvent(nullptr, 0).MakeObject()}}; - //TODO throw comprehensible exceptions on parse error - m_AnnotationFactory->CreateAnnotationsFromJson( - R"(D:\Arbeit\Programming\mitk_m\Plugins\org.mitk.annotations\resources\annotations.json)", actions, events); + // TODO throw comprehensible exceptions on parse error + try + { + m_AnnotationFactory->CreateAnnotationsFromJson( + R"(D:\Arbeit\Programming\mitk_m\Plugins\org.mitk.annotations\resources\annotations.json)", actions, events); + } + catch (const std::exception& e) + { + MITK_ERROR << e.what(); + std::rethrow_exception(std::current_exception()); + } m_AnnotationFuture = std::async(std::launch::async, [this]() { std::this_thread::sleep_for(std::chrono::seconds(10)); - //m_AnnotationFactory->Update(); leads to crash in vtk (maybe threading issue) + // m_AnnotationFactory->Update(); leads to crash in vtk (maybe threading issue) - auto windows = berry::PlatformUI::GetWorkbench()->GetWorkbenchWindows(); - auto activeWindow = berry::PlatformUI::GetWorkbench()->GetActiveWorkbenchWindow(); - auto selectionService = activeWindow->GetSelectionService(); - class NodeSelectionListener : public berry::ISelectionListener + auto windows = berry::PlatformUI::GetWorkbench()->GetWorkbenchWindows(); + auto activeWindow = berry::PlatformUI::GetWorkbench()->GetActiveWorkbenchWindow(); + auto selectionService = activeWindow->GetSelectionService(); + class NodeSelectionListener : public berry::ISelectionListener { - public: + public: NodeSelectionListener(AnnotationFactory *factory) : m_Factory(factory){}; - void SelectionChanged(const berry::IWorkbenchPart::Pointer& part, - const berry::ISelection::ConstPointer& selection) override + void SelectionChanged(const berry::IWorkbenchPart::Pointer &part, + const berry::ISelection::ConstPointer &selection) override { - const auto nodeSelection = dynamic_cast(selection.GetPointer()); + const auto nodeSelection = dynamic_cast(selection.GetPointer()); if (nodeSelection) { auto nodes = nodeSelection->GetSelectedDataNodes(); if (!nodes.empty()) { m_Factory->SetProviderForAllPropertyAnnotations(nodes.front()->GetData()); } } }; AnnotationFactory *m_Factory; }; - selectionService->AddPostSelectionListener(new NodeSelectionListener(m_AnnotationFactory)); - - //RenderingManager::GetInstance()->RequestUpdateAll(); + selectionService->AddPostSelectionListener(new NodeSelectionListener(m_AnnotationFactory)); + + // RenderingManager::GetInstance()->RequestUpdateAll(); }); } void mitk::AnnotationsActivator::stop(ctkPluginContext * /*context*/) {}