diff --git a/Modules/USUI/Qmitk/QmitkUSAbstractCustomWidget.cpp b/Modules/USUI/Qmitk/QmitkUSAbstractCustomWidget.cpp index 5e626d7836..e0d9f40086 100644 --- a/Modules/USUI/Qmitk/QmitkUSAbstractCustomWidget.cpp +++ b/Modules/USUI/Qmitk/QmitkUSAbstractCustomWidget.cpp @@ -1,79 +1,131 @@ /*=================================================================== 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 "QmitkUSAbstractCustomWidget.h" #include #include std::string QmitkUSAbstractCustomWidget::US_DEVICE_PROPKEY_CLASS() { static std::string s = "org.mitk.services.UltrasoundCustomWidget.deviceClass"; return s; } QmitkUSAbstractCustomWidget::QmitkUSAbstractCustomWidget(QWidget* parent) : QWidget(parent), m_PrototypeServiceFactory(0), m_IsClonedForQt(false) { + } QmitkUSAbstractCustomWidget::~QmitkUSAbstractCustomWidget() { + this->UnregisterService(); delete m_PrototypeServiceFactory; } void QmitkUSAbstractCustomWidget::SetDevice(mitk::USDevice::Pointer device) { m_Device = device; if ( device ) { this->OnDeviceSet(); } } mitk::USDevice::Pointer QmitkUSAbstractCustomWidget::GetDevice() const { return m_Device; } QmitkUSAbstractCustomWidget* QmitkUSAbstractCustomWidget::CloneForQt(QWidget* parent) const { QmitkUSAbstractCustomWidget* clonedWidget = this->Clone(parent); clonedWidget->Initialize(); // initialize the Qt stuff of the widget clonedWidget->m_IsClonedForQt = true; // set flag that this object was really cloned return clonedWidget; } +//////////// µS Registration & Properties ////////////// + +us::ServiceRegistration QmitkUSAbstractCustomWidget::RegisterService(us::ModuleContext *context) +{ + if (m_PrototypeServiceFactory) + return us::ServiceRegistration(); + + if (context == nullptr) + { + context = us::GetModuleContext(); + } + + // Define a PrototypeServiceFactory for the abstract super class of all custom control widgets of USUI + // This factory is used to register the individual widgets as micro services linked to specific US devices + struct PrototypeFactory : public us::PrototypeServiceFactory + { + QmitkUSAbstractCustomWidget *const m_Prototype; + + PrototypeFactory(QmitkUSAbstractCustomWidget *prototype) : m_Prototype(prototype) {} + us::InterfaceMap GetService(us::Module * /*module*/, + const us::ServiceRegistrationBase & /*registration*/) override + { + return us::MakeInterfaceMap(m_Prototype->Clone()); + } + + void UngetService(us::Module * /*module*/, + const us::ServiceRegistrationBase & /*registration*/, + const us::InterfaceMap &service) override + { + delete us::ExtractInterface(service); + } + }; + + m_PrototypeServiceFactory = new PrototypeFactory(this); // instantiate PrototypeFactory with QmitkUSAbstractCustomWidget as prototype + us::ServiceProperties props = this->GetServiceProperties(); // retrieve the service properties (the device class linked with each custom control widget) + m_Reg = context->RegisterService(m_PrototypeServiceFactory, props); // register service + return m_Reg; +} + +void QmitkUSAbstractCustomWidget::UnregisterService() +{ + try + { + m_Reg.Unregister(); + } + catch (const std::exception &) + { + } +} + us::ServiceProperties QmitkUSAbstractCustomWidget::GetServiceProperties() const { us::ServiceProperties result; result[QmitkUSAbstractCustomWidget::US_DEVICE_PROPKEY_CLASS()] = this->GetDeviceClass(); return result; } void QmitkUSAbstractCustomWidget::showEvent ( QShowEvent * event ) { // using object from micro service directly in Qt without cloning it first // can cause problems when Qt deletes this object -> throw an exception to // show that object should be cloned before if ( ! m_IsClonedForQt ) { MITK_ERROR << "Object wasn't cloned with CloneForQt() before using as QWidget."; mitkThrow() << "Object wasn't cloned with CloneForQt() before using as QWidget."; } QWidget::showEvent(event); } diff --git a/Modules/USUI/Qmitk/QmitkUSAbstractCustomWidget.h b/Modules/USUI/Qmitk/QmitkUSAbstractCustomWidget.h index 7f8eb49674..b475e0795a 100644 --- a/Modules/USUI/Qmitk/QmitkUSAbstractCustomWidget.h +++ b/Modules/USUI/Qmitk/QmitkUSAbstractCustomWidget.h @@ -1,157 +1,165 @@ /*=================================================================== 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. ===================================================================*/ #ifndef QmitkUSAbstractCustomWidget_h #define QmitkUSAbstractCustomWidget_h #include #include #include "mitkUSDevice.h" // Microservices #include #include #include +#include #include namespace us { struct PrototypeServiceFactory; class ModuleContext; } /** * \brief Abstract superclass for all custom control widgets of mitk::USDevice classes. * * The custom control widgets are made available using a us::PrototypeServiceFactory. This means that each * concrete subclass should be registered in the microservice by calling * QmitkUSAbstractCustomWidget::RegisterService() on an object. The best place for doing this would be in * the corresponding module or plugin activator. * * Afterwards a copy of the registered object can be obtained from the microservice as shown in the example * below. Do not forget to call QmitkUSAbstractCustomWidget::CloneForQt() on the object received from the * microservice. This is necessary to allow deleting the object as it is necessary in Qt for removing it from * a layout. * * * Subclasses must implement three methods: * - QmitkUSAbstractCustomWidget::OnDeviceSet() -> should handle initialization when mitk:USDevice was set * - QmitkUSAbstractCustomWidget::GetDeviceClass() -> must return device class of corresponding mitk::USDevice * - QmitkUSAbstractCustomWidget::Clone() -> must create a copy of the current object * * * The code to use a custom control widget in a plugin can look like this: * * \code * ctkPluginContext* pluginContext = // get the plugig context * mitk::USDevice device = // get the ultrasound device * * // get service references for ultrasound device * std::string filter = "(org.mitk.services.UltrasoundCustomWidget.deviceClass=" + device->GetDeviceClass() + ")"; * QString interfaceName ( us_service_interface_iid() ); * QList serviceRefs = pluginContext->getServiceReferences(interfaceName, QString::fromStdString(filter)); * * if (serviceRefs.size() > 0) * { * // get widget from the service and make sure that it is cloned, so that * // it can be deleted if it should be removed from the GUI later * QmitkUSAbstractCustomWidget* widget = pluginContext->getService * (serviceRefs.at(0))->CloneForQt(parentWidget); * // now the widget can be used like any other QWidget * } * \endcode */ class MITKUSUI_EXPORT QmitkUSAbstractCustomWidget : public QWidget { Q_OBJECT public: QmitkUSAbstractCustomWidget(QWidget* parent = 0); virtual ~QmitkUSAbstractCustomWidget(); void SetDevice(mitk::USDevice::Pointer device); mitk::USDevice::Pointer GetDevice() const; /** * \brief Called every time a mitk::USDevice was set with QmitkUSAbstractCustomWidget::SetDevice(). * A sublcass can implement this function to handle initialiation actions * necessary when a device was set. */ virtual void OnDeviceSet() = 0; /** * \brief Subclass must implement this method to return device class of corresponding mitk::USDevice. * * \return same value as mitk::USDevice::GetDeviceClass() of the corresponding mitk::USDevice */ virtual std::string GetDeviceClass() const = 0; /** * \brief Subclass must implement this method to return a pointer to a copy of the object. */ virtual QmitkUSAbstractCustomWidget* Clone(QWidget* parent = 0) const = 0; /** * \brief Method for initializing the Qt stuff of the widget (setupUI, connect). * This method will be called in CloneForQt() and has to be implemented by concrete * subclasses. * \warning All Qt initialization stuff belongs into this method rather than in the constructor. */ virtual void Initialize() = 0; /** * \brief Return pointer to copy of the object. * Internally use of QmitkUSAbstractCustomWidget::Clone() with additionaly * setting an internal flag that the object was really cloned. */ QmitkUSAbstractCustomWidget* CloneForQt(QWidget* parent = 0) const; + /** + * \brief Register this widget as microservice using the us::PrototypeServiceFactory. The registered microservice is linked to the US device + */ + us::ServiceRegistration RegisterService(us::ModuleContext * context = us::GetModuleContext()); + void UnregisterService(); + /** * \brief Returns the properties of the micro service. * Properties consist of just the device class of the corresponding * mitk::USDevice. */ us::ServiceProperties GetServiceProperties() const; /** * \brief Overwritten Qt even method. * It is checked if the object was cloned with * QmitkUSAbstractCustomWidget::CloneForQt() before. An exception is thrown * if not. This is done, because using the object from micro service directly * in Qt without cloning it first can cause problems after Qt deleted the * object. * * \throws mitk::Exception */ void showEvent ( QShowEvent * event ) override; /** * \brief Property key for the class name of corresponding us device object. */ static std::string US_DEVICE_PROPKEY_CLASS(); private: - mitk::USDevice::Pointer m_Device; - us::PrototypeServiceFactory* m_PrototypeServiceFactory; + mitk::USDevice::Pointer m_Device; ///< USDevice related to the specific widgets + us::PrototypeServiceFactory* m_PrototypeServiceFactory; ///< PrototypeServiceFactory used to register the individual widgets as micro services linked to specific US devices + us::ServiceRegistration m_Reg; ///< ServiceRegistration object used to update the service properties or to unregister the service bool m_IsClonedForQt; }; // This is the microservice declaration. Do not meddle! MITK_DECLARE_SERVICE_INTERFACE(QmitkUSAbstractCustomWidget, "org.mitk.QmitkUSAbstractCustomWidget") #endif // QmitkUSAbstractCustomWidget_h