diff --git a/Modules/OpenIGTLink/mitkIGTLDevice.cpp b/Modules/OpenIGTLink/mitkIGTLDevice.cpp index d7a925a11f..4614d218b2 100644 --- a/Modules/OpenIGTLink/mitkIGTLDevice.cpp +++ b/Modules/OpenIGTLink/mitkIGTLDevice.cpp @@ -1,486 +1,502 @@ /*=================================================================== 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 "mitkIGTLDevice.h" +//#include "mitkIGTException.h" //#include "mitkIGTTimeStamp.h" #include #include #include #include #include #include //remove later #include #include static const int SOCKET_SEND_RECEIVE_TIMEOUT_MSEC = 1; typedef itk::MutexLockHolder MutexLockHolder; mitk::IGTLDevice::IGTLDevice() : // m_Data(mitk::DeviceDataUnspecified), m_State(mitk::IGTLDevice::Setup), m_Name("Unspecified Device"), m_StopCommunication(false), m_Hostname("127.0.0.1"), m_PortNumber(-1), m_MultiThreader(NULL), m_ThreadID(0) { m_StopCommunicationMutex = itk::FastMutexLock::New(); m_StateMutex = itk::FastMutexLock::New(); // m_LatestMessageMutex = itk::FastMutexLock::New(); m_CommunicationFinishedMutex = itk::FastMutexLock::New(); // execution rights are owned by the application thread at the beginning m_CommunicationFinishedMutex->Lock(); m_MultiThreader = itk::MultiThreader::New(); // m_Data = mitk::DeviceDataUnspecified; // m_LatestMessage = igtl::MessageBase::New(); m_MessageFactory = mitk::IGTLMessageFactory::New(); m_SendQueue = mitk::IGTLMessageQueue::New(); m_ReceiveQueue = mitk::IGTLMessageQueue::New(); m_CommandQueue = mitk::IGTLMessageQueue::New(); } mitk::IGTLDevice::~IGTLDevice() { /* stop communication and disconnect from igtl device */ if (GetState() == Running) { this->StopCommunication(); } if (GetState() == Ready) { this->CloseConnection(); } /* cleanup tracking thread */ if ((m_ThreadID != 0) && (m_MultiThreader.IsNotNull())) { m_MultiThreader->TerminateThread(m_ThreadID); } m_MultiThreader = NULL; } mitk::IGTLDevice::IGTLDeviceState mitk::IGTLDevice::GetState() const { MutexLockHolder lock(*m_StateMutex); return m_State; } void mitk::IGTLDevice::SetState( IGTLDeviceState state ) { itkDebugMacro("setting m_State to " << state); m_StateMutex->Lock(); // MutexLockHolder lock(*m_StateMutex); // lock and unlock the mutex if (m_State == state) { m_StateMutex->Unlock(); return; } m_State = state; m_StateMutex->Unlock(); this->Modified(); } bool mitk::IGTLDevice::TestConnection() { return true; } unsigned int mitk::IGTLDevice::ReceivePrivate(igtl::Socket* socket) { // Create a message buffer to receive header igtl::MessageHeader::Pointer headerMsg; headerMsg = igtl::MessageHeader::New(); // Initialize receive buffer headerMsg->InitPack(); // Receive generic header from the socket int r = socket->Receive(headerMsg->GetPackPointer(), headerMsg->GetPackSize(), 1); if (r == 0) //connection error { // an error was received, therefor the communication with this socket // must be stopped return IGTL_STATUS_NOT_PRESENT; } else if (r == -1 ) //timeout { // a timeout was received, this is no error state, thus, do nothing return IGTL_STATUS_TIME_OUT; } else if (r == headerMsg->GetPackSize()) { // Deserialize the header and check the CRC int crcCheck = headerMsg->Unpack(1); if (crcCheck & igtl::MessageHeader::UNPACK_HEADER) { // Allocate a time stamp igtl::TimeStamp::Pointer ts; ts = igtl::TimeStamp::New(); // Get time stamp igtlUint32 sec; igtlUint32 nanosec; headerMsg->GetTimeStamp(ts); ts->GetTimeStamp(&sec, &nanosec); // std::cerr << "Time stamp: " // << sec << "." // << nanosec << std::endl; // std::cerr << "Dev type and name: " << headerMsg->GetDeviceType() << " " // << headerMsg->GetDeviceName() << std::endl; // headerMsg->Print(std::cout); //check the type of the received message //if it is a GET_, STP_ or RTS_ command push it into the command queue //otherwise continue reading the whole message from the socket const char* curDevType = headerMsg->GetDeviceType(); if ( std::strstr( curDevType, "GET_" ) != NULL || std::strstr( curDevType, "STP_" ) != NULL || std::strstr( curDevType, "RTS_" ) != NULL) { this->m_CommandQueue->PushMessage(headerMsg); this->InvokeEvent(CommandReceivedEvent()); return IGTL_STATUS_OK; } //Create a message according to the header message igtl::MessageBase::Pointer curMessage; curMessage = m_MessageFactory->CreateInstance(headerMsg); //check if the curMessage is created properly, if not the message type is //not supported and the message has to be skipped if ( curMessage.IsNull() ) { socket->Skip(headerMsg->GetBodySizeToRead(), 0); MITK_ERROR("IGTLDevice") << "The received type is not supported. Please " "add it to the message factory."; return IGTL_STATUS_NOT_FOUND; } //insert the header to the message and allocate the pack curMessage->SetMessageHeader(headerMsg); curMessage->AllocatePack(); // Receive transform data from the socket int receiveCheck = 0; receiveCheck = socket->Receive(curMessage->GetPackBodyPointer(), curMessage->GetPackBodySize()); if ( receiveCheck > 0 ) { int c = curMessage->Unpack(1); if ( !(c & igtl::MessageHeader::UNPACK_BODY) ) { // mitkThrow() << "crc error"; return IGTL_STATUS_CHECKSUM_ERROR; } //check the type of the received message //if it is a command push it into the command queue //otherwise into the normal receive queue //STP_ commands are handled here because they implemented additional //member variables that are not stored in the header message if ( std::strstr( curDevType, "STT_" ) != NULL ) { this->m_CommandQueue->PushMessage(curMessage); this->InvokeEvent(CommandReceivedEvent()); } else { this->m_ReceiveQueue->PushMessage(curMessage); this->InvokeEvent(MessageReceivedEvent()); } return IGTL_STATUS_OK; } else { MITK_ERROR("IGTLDevice") << "Received a valid header but could not " << "read the whole message."; return IGTL_STATUS_UNKNOWN_ERROR; } } else { //CRC check failed return IGTL_STATUS_CHECKSUM_ERROR; } } else { //Message size information and actual data size don't match. //this state is not suppossed to be reached, return unknown error return IGTL_STATUS_UNKNOWN_ERROR; } } void mitk::IGTLDevice::SendMessage(const mitk::IGTLMessage* msg) { this->SendMessage(msg->GetMessage()); } void mitk::IGTLDevice::SendMessage(igtl::MessageBase::Pointer msg) { //add the message to the queue m_SendQueue->PushMessage(msg); } unsigned int mitk::IGTLDevice::SendMessagePrivate(igtl::MessageBase::Pointer msg, igtl::Socket::Pointer socket) { //check the input message if ( msg.IsNull() ) { MITK_ERROR("IGTLDevice") << "Could not send message because message is not " "valid. Please check."; return false; } // add the name of this device to the message msg->SetDeviceName(this->GetName().c_str()); // Pack (serialize) and send msg->Pack(); int sendSuccess = socket->Send(msg->GetPackPointer(), msg->GetPackSize()); if (sendSuccess) - return IGTL_STATUS_OK; + { + this->InvokeEvent(MessageSentEvent()); + return IGTL_STATUS_OK; + } else - return IGTL_STATUS_UNKNOWN_ERROR; + { + return IGTL_STATUS_UNKNOWN_ERROR; + } } void mitk::IGTLDevice::RunCommunication() { if (this->GetState() != Running) return; - // keep lock until end of scope - MutexLockHolder communicationFinishedLockHolder(*m_CommunicationFinishedMutex); - - // Because m_StopCommunication is used by two threads, access has to be guarded - // by a mutex. To minimize thread locking, a local copy is used here - bool localStopCommunication; - - // update the local copy of m_StopCommunication - this->m_StopCommunicationMutex->Lock(); - localStopCommunication = this->m_StopCommunication; - this->m_StopCommunicationMutex->Unlock(); - while ((this->GetState() == Running) && (localStopCommunication == false)) + try { - // Check if other igtl devices want to connect with this one. This method - // is overwritten for igtl servers but is doing nothing in case of a igtl - // client - this->Connect(); - - // Check if there is something to receive and store it in the message queue - this->Receive(); - - // Check if there is something to send - this->Send(); - - /* Update the local copy of m_StopCommunication */ - this->m_StopCommunicationMutex->Lock(); - localStopCommunication = m_StopCommunication; - this->m_StopCommunicationMutex->Unlock(); - - // time to relax -// itksys::SystemTools::Delay(1); + // keep lock until end of scope + MutexLockHolder communicationFinishedLockHolder(*m_CommunicationFinishedMutex); + + // Because m_StopCommunication is used by two threads, access has to be guarded + // by a mutex. To minimize thread locking, a local copy is used here + bool localStopCommunication; + + // update the local copy of m_StopCommunication + this->m_StopCommunicationMutex->Lock(); + localStopCommunication = this->m_StopCommunication; + this->m_StopCommunicationMutex->Unlock(); + while ((this->GetState() == Running) && (localStopCommunication == false)) + { + // Check if other igtl devices want to connect with this one. This method + // is overwritten for igtl servers but is doing nothing in case of a igtl + // client + this->Connect(); + + // Check if there is something to receive and store it in the message queue + this->Receive(); + + // Check if there is something to send + this->Send(); + + /* Update the local copy of m_StopCommunication */ + this->m_StopCommunicationMutex->Lock(); + localStopCommunication = m_StopCommunication; + this->m_StopCommunicationMutex->Unlock(); + + // time to relax + // itksys::SystemTools::Delay(1); + } + } + catch (...) + { + m_CommunicationFinishedMutex->Unlock(); + this->StopCommunication(); + MITK_ERROR("IGTLDevice::RunCommunication") << "Error while communicating. Thread stopped."; + //mitkThrowException(mitk::IGTException) << "Error while communicating. Thread stopped."; } // StopCommunication was called, thus the mode should be changed back to Ready now // that the tracking loop has ended. - this->SetState(Ready); + //this->SetState(Ready); MITK_DEBUG("IGTLDevice::RunCommunication") << "Reached end of communication."; // returning from this function (and ThreadStartCommunication()) // this will end the thread return; } bool mitk::IGTLDevice::StartCommunication() { if (this->GetState() != Ready) return false; // go to mode Running this->SetState(Running); // set a timeout for the sending and receiving this->m_Socket->SetTimeout(SOCKET_SEND_RECEIVE_TIMEOUT_MSEC); // update the local copy of m_StopCommunication this->m_StopCommunicationMutex->Lock(); this->m_StopCommunication = false; this->m_StopCommunicationMutex->Unlock(); // transfer the execution rights to tracking thread m_CommunicationFinishedMutex->Unlock(); // start a new thread that executes the communication m_ThreadID = m_MultiThreader->SpawnThread(this->ThreadStartCommunication, this); // mitk::IGTTimeStamp::GetInstance()->Start(this); return true; } bool mitk::IGTLDevice::StopCommunication() { if (this->GetState() == Running) // Only if the object is in the correct state { // m_StopCommunication is used by two threads, so we have to ensure correct // thread handling m_StopCommunicationMutex->Lock(); m_StopCommunication = true; m_StopCommunicationMutex->Unlock(); // we have to wait here that the other thread recognizes the STOP-command // and executes it m_CommunicationFinishedMutex->Lock(); // mitk::IGTTimeStamp::GetInstance()->Stop(this); // notify realtime clock // StopCommunication was called, thus the mode should be changed back // to Ready now that the tracking loop has ended. this->SetState(Ready); } return true; } bool mitk::IGTLDevice::CloseConnection() { if (this->GetState() == Setup) { return true; } else if (this->GetState() == Running) { this->StopCommunication(); } m_Socket->CloseSocket(); /* return to setup mode */ this->SetState(Setup); // this->InvokeEvent(mitk::LostConnectionEvent()); return true; } bool mitk::IGTLDevice::SendRTSMessage(const char* type) { //construct the device type for the return message, it starts with RTS_ and //continues with the requested type std::string returnType("RTS_"); returnType.append(type); //create a return message igtl::MessageBase::Pointer rtsMsg = this->m_MessageFactory->CreateInstance(returnType); //if retMsg is NULL there is no return message defined and thus it is not //necessary to send one back if ( rtsMsg.IsNotNull() ) { this->SendMessage(rtsMsg); return true; } else { return false; } } void mitk::IGTLDevice::Connect() { } igtl::MessageBase::Pointer mitk::IGTLDevice::GetNextMessage() { //copy the next message into the given msg igtl::MessageBase::Pointer msg = this->m_ReceiveQueue->PullMessage(); return msg; } igtl::MessageBase::Pointer mitk::IGTLDevice::GetNextCommand() { //copy the next command into the given msg igtl::MessageBase::Pointer msg = this->m_CommandQueue->PullMessage(); return msg; } void mitk::IGTLDevice::EnableInfiniteBufferingMode( mitk::IGTLMessageQueue::Pointer queue, bool enable) { queue->EnableInfiniteBuffering(enable); } //std::string mitk::IGTLDevice::GetNextMessageInformation() //{ // return this->m_ReceiveQueue->GetNextMsgInformationString(); //} //std::string mitk::IGTLDevice::GetNextMessageDeviceType() //{ // return this->m_ReceiveQueue->GetNextMsgDeviceType(); //} //std::string mitk::IGTLDevice::GetNextCommandInformation() //{ // return this->m_CommandQueue->GetNextMsgInformationString(); //} //std::string mitk::IGTLDevice::GetNextCommandDeviceType() //{ // return this->m_CommandQueue->GetNextMsgDeviceType(); //} ITK_THREAD_RETURN_TYPE mitk::IGTLDevice::ThreadStartCommunication(void* pInfoStruct) { /* extract this pointer from Thread Info structure */ struct itk::MultiThreader::ThreadInfoStruct * pInfo = (struct itk::MultiThreader::ThreadInfoStruct*)pInfoStruct; if (pInfo == NULL) { return ITK_THREAD_RETURN_VALUE; } if (pInfo->UserData == NULL) { return ITK_THREAD_RETURN_VALUE; } IGTLDevice *igtlDevice = (IGTLDevice*)pInfo->UserData; if (igtlDevice != NULL) { igtlDevice->RunCommunication(); } igtlDevice->m_ThreadID = 0; // erase thread id because thread will end. return ITK_THREAD_RETURN_VALUE; } diff --git a/Modules/OpenIGTLink/mitkIGTLDevice.h b/Modules/OpenIGTLink/mitkIGTLDevice.h index 5d4cb64dee..98678f19c2 100644 --- a/Modules/OpenIGTLink/mitkIGTLDevice.h +++ b/Modules/OpenIGTLink/mitkIGTLDevice.h @@ -1,384 +1,392 @@ /*=================================================================== 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 MITKIGTLDEVICE_H #define MITKIGTLDEVICE_H #include "mitkCommon.h" //itk #include "itkObject.h" #include "itkFastMutexLock.h" #include "itkMultiThreader.h" //igtl #include "igtlSocket.h" #include "igtlMessageBase.h" #include "igtlTransformMessage.h" //mitkIGTL #include "MitkOpenIGTLinkExports.h" #include "mitkIGTLMessageFactory.h" #include "mitkIGTLMessageQueue.h" #include "mitkIGTLMessage.h" namespace mitk { /** * \brief Interface for all OpenIGTLink Devices * * Defines the methods that are common for all devices using OpenIGTLink. It * can open/close a connection, start/stop a communication and send/receive * messages. * * It uses message queues to store the incoming and outgoing mails. They are * configurable, you can set buffering on and off. * * The device is in one of three different states: Setup, Ready or Running. * Setup is the initial state. From this state on you can call * OpenConnection() and arrive in the Ready state. From the Ready state you * call StartCommunication() to arrive in the Running state. Now the device * is continuosly checking for new connections, receiving messages and * sending messages. This runs in a seperate thread. To stop the communication * call StopCommunication() (to arrive in Ready state) or CloseConnection() * (to arrive in the Setup state). * * \ingroup OpenIGTLink * */ class MITK_OPENIGTLINK_EXPORT IGTLDevice : public itk::Object { public: mitkClassMacro(IGTLDevice, itk::Object) /** * \brief Type for state variable. * The IGTLDevice is always in one of these states. * */ enum IGTLDeviceState {Setup, Ready, Running}; /** * \brief Opens a connection to the device * * This may only be called if there is currently no connection to the * device. If OpenConnection() is successful, the object will change from * Setup state to Ready state. */ virtual bool OpenConnection() = 0; /** * \brief Closes the connection to the device * * This may only be called if there is currently a connection to the * device, but device is not running (e.g. object is in Ready state) */ virtual bool CloseConnection(); /** * \brief Stops the communication between the two devices * * This may only be called if the device is in Running state. */ virtual bool StopCommunication(); /** * \brief Starts the communication between the two devices * * This may only be called if the device is in Ready state. */ bool StartCommunication(); /** * \brief Continuously checks for new connections, receives messages and * sends messages. * * This may only be called if the device is in Running state and only from * a seperate thread. */ void RunCommunication(); /** * \brief Adds the given message to the sending queue * * This may only be called after the connection to the device has been * established with a call to OpenConnection(). Note that the message * is not send directly. This method just adds it to the send queue. * \param msg The message to be added to the sending queue */ void SendMessage(igtl::MessageBase::Pointer msg); /** * \brief Adds the given message to the sending queue * * Convenience function to work with mitk::IGTLMessage directly. * \param msg The message to be added to the sending queue */ void SendMessage(const IGTLMessage* msg); /** * \brief Returns current object state (Setup, Ready or Running) */ IGTLDeviceState GetState() const; /** * \brief Returns the oldest message in the command queue * \return The oldest message from the command queue. */ igtl::MessageBase::Pointer GetNextCommand(); /** * \brief Returns the oldest message in the receive queue * \return The oldest message from the receive queue */ igtl::MessageBase::Pointer GetNextMessage(); /** * \brief Sets the port number of the device */ itkSetMacro(PortNumber,int); /** * \brief Returns the port number of the device */ itkGetMacro(PortNumber,int); /** * \brief Sets the ip/hostname of the device */ itkSetMacro(Hostname,std::string); /** * \brief Returns the ip/hostname of the device */ itkGetMacro(Hostname,std::string); /** * \brief Returns the name of this device */ itkGetConstMacro(Name, std::string); /** * \brief Sets the name of this device */ itkSetMacro(Name, std::string); /** * \brief Returns a const reference to the receive queue */ itkGetConstMacro(ReceiveQueue, mitk::IGTLMessageQueue::Pointer); /** * \brief Returns a const reference to the command queue */ itkGetConstMacro(CommandQueue, mitk::IGTLMessageQueue::Pointer); /** * \brief Returns a const reference to the send queue */ itkGetConstMacro(SendQueue, mitk::IGTLMessageQueue::Pointer); /** * \brief Returns the message factory */ itkGetMacro(MessageFactory, mitk::IGTLMessageFactory::Pointer); /** * \brief static start method for the tracking thread. * \param data a void pointer to the IGTLDevice object. */ static ITK_THREAD_RETURN_TYPE ThreadStartCommunication(void* data); /** * \brief TestConnection() tries to connect to a IGTL device on the current * ip and port * * \todo Implement this method. Send a status message and check the answer. * * TestConnection() tries to connect to a IGTL server on the current * ip and port and returns which device it has found. * \return It returns the type of the device that answers. Throws an * exception * if no device is available on that ip/port. * @throw mitk::Exception Throws an exception if there are errors * while connecting to the device. */ virtual bool TestConnection(); /** * \brief Send RTS message of given type */ bool SendRTSMessage(const char* type); /** * \brief Sets the buffering mode of the given queue */ void EnableInfiniteBufferingMode(mitk::IGTLMessageQueue::Pointer queue, bool enable = true); /** * \brief Returns the number of connections of this device */ virtual unsigned int GetNumberOfConnections() = 0; protected: /** * \brief Sends a message. * * This may only be called after the connection to the device has been * established with a call to OpenConnection(). This method uses the given * socket to send the given MessageReceivedEvent * * \param msg the message to be sent * \param socket the socket used to communicate with the other device * * \retval IGTL_STATUS_OK the message was sent * \retval IGTL_STATUS_UNKONWN_ERROR the message was not sent because an * unknown error occurred */ unsigned int SendMessagePrivate(igtl::MessageBase::Pointer msg, igtl::Socket::Pointer socket); /** * \brief Call this method to receive a message. * * The message will be saved in the receive queue. */ virtual void Receive() = 0; /** * \brief Call this method to receive a message from the given device. * * The message will be saved in the receive queue. * * \param device the socket that connects this device with the other one. * * \retval IGTL_STATUS_OK a message or a command was received * \retval IGTL_STATUS_NOT_PRESENT the socket is not connected anymore * \retval IGTL_STATUS_TIME_OUT the socket timed out * \retval IGTL_STATUS_CHECKSUM_ERROR the checksum of the received msg was * incorrect * \retval IGTL_STATUS_UNKNOWN_ERROR an unknown error occurred */ unsigned int ReceivePrivate(igtl::Socket* device); /** * \brief Call this method to send a message. The message will be read from * the queue. */ virtual void Send() = 0; /** * \brief Call this method to check for other devices that want to connect * to this one. * * In case of a client this method is doing nothing. In case of a server it * is checking for other devices and if there is one it establishes a * connection. */ virtual void Connect(); /** * \brief Stops the communication with the given socket * */ virtual void StopCommunicationWithSocket(igtl::Socket* socket) = 0; /** * \brief change object state */ void SetState(IGTLDeviceState state); IGTLDevice(); virtual ~IGTLDevice(); /** current object state (Setup, Ready or Running) */ IGTLDeviceState m_State; /** the name of this device */ std::string m_Name; /** signal used to stop the thread*/ bool m_StopCommunication; /** mutex to control access to m_StopCommunication */ itk::FastMutexLock::Pointer m_StopCommunicationMutex; /** mutex used to make sure that the thread is just started once */ itk::FastMutexLock::Pointer m_CommunicationFinishedMutex; /** mutex to control access to m_State */ itk::FastMutexLock::Pointer m_StateMutex; /** the hostname or ip of the device */ std::string m_Hostname; /** the port number of the device */ int m_PortNumber; /** the socket used to communicate with other IGTL devices */ igtl::Socket::Pointer m_Socket; /** The message receive queue */ mitk::IGTLMessageQueue::Pointer m_ReceiveQueue; /** The message send queue */ mitk::IGTLMessageQueue::Pointer m_SendQueue; /** A queue that stores just command messages received by this device */ mitk::IGTLMessageQueue::Pointer m_CommandQueue; /** A message factory that provides the New() method for all msg types */ mitk::IGTLMessageFactory::Pointer m_MessageFactory; private: /** creates worker thread that continuously polls interface for new messages */ itk::MultiThreader::Pointer m_MultiThreader; /** ID of polling thread */ int m_ThreadID; }; /** - * \brief connect to this Event to get noticed when a message was received + * \brief connect to this Event to get notified when a message was successfully sent + * + * \note This event is invoked in the communication thread, therefore do not use it to make + * changes in the GUI!!! Use the QT signal slot system to decouple this call from the com thread + * */ + itkEventMacro( MessageSentEvent , itk::AnyEvent ); + + /** + * \brief connect to this Event to get notified when a message was received * * \note Check if you can invoke this events like this or if you have to make * it thread-safe. They are not invoked in the main thread!!! * */ itkEventMacro( MessageReceivedEvent , itk::AnyEvent ); /** - * \brief connect to this Event to get noticed when a command was received + * \brief connect to this Event to get notified when a command was received * * \note Check if you can invoke this events like this or if you have to make * it thread-safe. They are not invoked in the main thread!!! * */ itkEventMacro( CommandReceivedEvent , itk::AnyEvent ); /** - * \brief connect to this Event to get noticed when another igtl device + * \brief connect to this Event to get notified when another igtl device * connects with this device. * * \note Check if you can invoke this events like this or if you have to make * it thread-safe. They are not invoked in the main thread!!! * */ itkEventMacro( NewClientConnectionEvent , itk::AnyEvent ); /** - * \brief connect to this Event to get noticed when this device looses the + * \brief connect to this Event to get notified when this device looses the * connection to a socket. * * \note Check if you can invoke this events like this or if you have to make * it thread-safe. They are not invoked in the main thread!!! * */ itkEventMacro( LostConnectionEvent , itk::AnyEvent ); } // namespace mitk #endif /* MITKIGTLDEVICE_H */ diff --git a/Modules/OpenIGTLink/mitkIGTLMessageProvider.cpp b/Modules/OpenIGTLink/mitkIGTLMessageProvider.cpp index 69942a3288..d2a5202b73 100644 --- a/Modules/OpenIGTLink/mitkIGTLMessageProvider.cpp +++ b/Modules/OpenIGTLink/mitkIGTLMessageProvider.cpp @@ -1,371 +1,374 @@ /*=================================================================== 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 "mitkIGTLMessageProvider.h" #include "mitkIGTLDevice.h" #include "mitkIGTLMessage.h" #include "mitkIGTLMessageFactory.h" #include "mitkCallbackFromGUIThread.h" //Microservices #include "usServiceReference.h" #include "usModuleContext.h" #include "usServiceEvent.h" #include "mitkServiceInterface.h" #include "usGetModuleContext.h" //igt (remove this later) #include "igtlBindMessage.h" #include "igtlQuaternionTrackingDataMessage.h" #include "igtlTrackingDataMessage.h" #ifndef WIN32 #include #endif mitk::IGTLMessageProvider::IGTLMessageProvider() : mitk::IGTLDeviceSource() { this->SetName("IGTLMessageProvider"); m_MultiThreader = itk::MultiThreader::New(); m_StreamingTimeMutex = itk::FastMutexLock::New(); m_StopStreamingThreadMutex = itk::FastMutexLock::New(); m_ThreadId = 0; m_IsStreaming = false; } mitk::IGTLMessageProvider::~IGTLMessageProvider() { // terminate worker thread on destruction this->m_StopStreamingThreadMutex->Lock(); this->m_StopStreamingThread = true; this->m_StopStreamingThreadMutex->Unlock(); if ( m_ThreadId >= 0) { this->m_MultiThreader->TerminateThread(m_ThreadId); } } void mitk::IGTLMessageProvider::GenerateData() { if (this->m_IGTLDevice.IsNull()) return; for (unsigned int index = 0; index < this->GetNumberOfIndexedInputs(); index++) { const IGTLMessage* msg = this->GetInput(index); - assert(msg); + if (msg == nullptr) + { + continue; + } if ( !msg->IsDataValid() ) { continue; } igtl::MessageBase::Pointer igtlMsg = msg->GetMessage(); if ( igtlMsg.IsNotNull() ) { //send the message this->m_IGTLDevice->SendMessage(igtlMsg); } } } void mitk::IGTLMessageProvider::CreateOutputs() { //if outputs are set then delete them if (this->GetNumberOfOutputs() > 0) { for (int numOP = this->GetNumberOfOutputs() - 1; numOP >= 0; numOP--) this->RemoveOutput(numOP); this->Modified(); } //fill the outputs if a valid OpenIGTLink device is set if (m_IGTLDevice.IsNull()) return; this->SetNumberOfIndexedOutputs(1); if (this->GetOutput(0) == NULL) { DataObjectPointer newOutput = this->MakeOutput(0); this->SetNthOutput(0, newOutput); this->Modified(); } } //void mitk::IGTLMessageProvider::UpdateOutputInformation() //{ // this->Modified(); // make sure that we need to be updated // Superclass::UpdateOutputInformation(); //} void mitk::IGTLMessageProvider::OnIncomingMessage() { } std::string RemoveRequestPrefixes(std::string requestType) { return requestType.substr(4); } void mitk::IGTLMessageProvider::OnIncomingCommand() { //get the next command igtl::MessageBase::Pointer curCommand = this->m_IGTLDevice->GetNextCommand(); //extract the type const char * requestType = curCommand->GetDeviceType(); //check the type std::string reqType(requestType); bool isGetMsg = !reqType.find("GET_"); bool isSTTMsg = !reqType.find("STT_"); bool isSTPMsg = !reqType.find("STP_"); bool isRTSMsg = !reqType.find("RTS_"); //get the type from the request type (remove STT_, STP_, GET_, RTS_) std::string type = RemoveRequestPrefixes(requestType); //check all microservices if there is a fitting source for the requested type mitk::IGTLMessageSource::Pointer source = this->GetFittingSource(type.c_str()); //if there is no fitting source return a RTS message, if there is a RTS //type defined in the message factory send it if ( source.IsNull() ) { if ( !this->GetIGTLDevice()->SendRTSMessage(type.c_str()) ) { //sending RTS message failed, probably because the type is not in the //message factory MITK_WARN("IGTLMessageProvider") << "Tried to send a RTS message but did " "not succeed. Check if this type ( " << type << " ) was added to the message " "factory. "; } } else { if ( isGetMsg ) //if it is a single value push it into sending queue { //first it is necessary to update the source. This needs additional time //but is necessary. But are we really allowed to call this here? In which //thread are we? Is the source thread safe? source->Update(); mitk::IGTLMessage::Pointer sourceOutput = source->GetOutput(); if (sourceOutput.IsNotNull() && sourceOutput->IsDataValid()) { igtl::MessageBase::Pointer sourceMsg = sourceOutput->GetMessage(); if ( source.IsNotNull() ) { this->GetIGTLDevice()->SendMessage(sourceMsg); } } } else if ( isSTTMsg ) { //read the requested frames per second int fps = 10; //read the fps from the command igtl::MessageBase* curCommandPt = curCommand.GetPointer(); if ( std::strcmp( curCommand->GetDeviceType(), "STT_BIND" ) == 0 ) { fps = ((igtl::StartBindMessage*)curCommandPt)->GetResolution(); } else if ( std::strcmp( curCommand->GetDeviceType(), "STT_QTDATA" ) == 0 ) { fps = ((igtl::StartQuaternionTrackingDataMessage*)curCommandPt)->GetResolution(); } else if ( std::strcmp( curCommand->GetDeviceType(), "STT_TDATA" ) == 0 ) { fps = ((igtl::StartTrackingDataMessage*)curCommandPt)->GetResolution(); } this->StartStreamingOfSource(source, fps); } else if ( isSTPMsg ) { this->StopStreamingOfSource(source); } else { //do nothing } } } bool mitk::IGTLMessageProvider::IsStreaming() { return m_IsStreaming; } void mitk::IGTLMessageProvider::StartStreamingOfSource(IGTLMessageSource* src, unsigned int fps) { if ( src == NULL ) return; //so far the provider allows the streaming of a single source only //if the streaming thread is already running return a RTS message if ( !m_IsStreaming ) { //if it is a stream establish a connection between the provider and the //source this->ConnectTo(src); // calculate the streaming time this->m_StreamingTimeMutex->Lock(); this->m_StreamingTime = 1.0 / (double) fps * 1000.0; this->m_StreamingTimeMutex->Unlock(); // Create a command object. The function will be called later from the // main thread this->m_StreamingCommand = ProviderCommand::New(); m_StreamingCommand->SetCallbackFunction(this, &mitk::IGTLMessageProvider::Update); // For streaming we need a continues time signal, since there is no timer // available we start a thread that generates a timing signal // This signal is invoked from the other thread the update of the pipeline // has to be executed from the main thread. Thus, we use the // callbackfromGUIThread class to pass the execution to the main thread this->m_ThreadId = m_MultiThreader->SpawnThread(this->TimerThread, this); this->m_IsStreaming = true; } else { MITK_WARN("IGTLMessageProvider") << "This provider just supports the " "streaming of one source."; } } void mitk::IGTLMessageProvider::StopStreamingOfSource(IGTLMessageSource* src) { //this is something bad!!! The streaming thread has to be stopped before the //source is disconnected otherwise it can cause a crash. This has to be added!! this->DisconnectFrom(src); this->m_StopStreamingThreadMutex->Lock(); this->m_StopStreamingThread = true; this->m_StopStreamingThreadMutex->Unlock(); //does this flag needs a mutex??? this->m_IsStreaming = false; } mitk::IGTLMessageSource::Pointer mitk::IGTLMessageProvider::GetFittingSource(const char* requestedType) { //get the context us::ModuleContext* context = us::GetModuleContext(); //define the interface name std::string interface = mitk::IGTLMessageSource::US_INTERFACE_NAME; //specify a filter that defines the requested type std::string filter = "(" + mitk::IGTLMessageSource::US_PROPKEY_DEVICETYPE + "=" + requestedType + ")"; //find the fitting service std::vector serviceReferences = context->GetServiceReferences(interface, filter); //check if a service reference was found. It is also possible that several //services were found. This is not checked here, just the first one is taken. if ( serviceReferences.size() ) { mitk::IGTLMessageSource::Pointer curSource = context->GetService(serviceReferences.front()); if ( curSource.IsNotNull() ) return curSource; } //no service reference was found or found service reference has no valid source return NULL; } void mitk::IGTLMessageProvider::Send(const mitk::IGTLMessage* msg) { if (msg != NULL) this->m_IGTLDevice->SendMessage(msg); } void mitk::IGTLMessageProvider::ConnectTo( mitk::IGTLMessageSource* UpstreamFilter ) { for (DataObjectPointerArraySizeType i = 0; i < UpstreamFilter->GetNumberOfOutputs(); i++) { this->SetInput(i, UpstreamFilter->GetOutput(i)); } } void mitk::IGTLMessageProvider::DisconnectFrom( mitk::IGTLMessageSource* UpstreamFilter ) { for (DataObjectPointerArraySizeType i = 0; i < UpstreamFilter->GetNumberOfOutputs(); i++) { this->RemoveInput(UpstreamFilter->GetOutput(i)); } } ITK_THREAD_RETURN_TYPE mitk::IGTLMessageProvider::TimerThread(void* pInfoStruct) { // extract this pointer from thread info structure struct itk::MultiThreader::ThreadInfoStruct * pInfo = (struct itk::MultiThreader::ThreadInfoStruct*)pInfoStruct; mitk::IGTLMessageProvider* thisObject = static_cast(pInfo->UserData); itk::SimpleMutexLock mutex; mutex.Lock(); thisObject->m_StopStreamingThreadMutex->Lock(); thisObject->m_StopStreamingThread = false; thisObject->m_StopStreamingThreadMutex->Unlock(); thisObject->m_StreamingTimeMutex->Lock(); unsigned int waitingTime = thisObject->m_StreamingTime; thisObject->m_StreamingTimeMutex->Unlock(); while (true) { thisObject->m_StopStreamingThreadMutex->Lock(); bool stopThread = thisObject->m_StopStreamingThread; thisObject->m_StopStreamingThreadMutex->Unlock(); if (stopThread) { break; } //wait for the time given //I know it is not the nicest solution but we just need an approximate time //sleeps for 20 ms #if defined (WIN32) || defined (_WIN32) Sleep(waitingTime); #else usleep(waitingTime * 1000); #endif // Ask to execute that command from the GUI thread mitk::CallbackFromGUIThread::GetInstance()->CallThisFromGUIThread( thisObject->m_StreamingCommand); } thisObject->m_ThreadId = 0; mutex.Unlock(); return ITK_THREAD_RETURN_VALUE; } diff --git a/Modules/OpenIGTLink/mitkIGTLMessageSource.cpp b/Modules/OpenIGTLink/mitkIGTLMessageSource.cpp index 0ff2b4ae5a..50f8f4fc3b 100644 --- a/Modules/OpenIGTLink/mitkIGTLMessageSource.cpp +++ b/Modules/OpenIGTLink/mitkIGTLMessageSource.cpp @@ -1,196 +1,197 @@ /*=================================================================== 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 "mitkIGTLMessageSource.h" #include "mitkUIDGenerator.h" //Microservices #include #include #include #include const std::string mitk::IGTLMessageSource::US_INTERFACE_NAME = "org.mitk.services.IGTLMessageSource"; const std::string mitk::IGTLMessageSource::US_PROPKEY_DEVICENAME = US_INTERFACE_NAME + ".devicename"; const std::string mitk::IGTLMessageSource::US_PROPKEY_DEVICETYPE = US_INTERFACE_NAME + ".devicetype"; const std::string mitk::IGTLMessageSource::US_PROPKEY_ID = US_INTERFACE_NAME + ".id"; const std::string mitk::IGTLMessageSource::US_PROPKEY_ISACTIVE = US_INTERFACE_NAME + ".isActive"; mitk::IGTLMessageSource::IGTLMessageSource() : itk::ProcessObject(), m_Name("IGTLMessageSource (no defined type)"), m_Type("NONE"), m_StreamingFPS(0) { m_StreamingFPSMutex = itk::FastMutexLock::New(); } mitk::IGTLMessageSource::~IGTLMessageSource() { - this->UnRegisterMicroservice(); + //this->UnRegisterMicroservice(); } mitk::IGTLMessage* mitk::IGTLMessageSource::GetOutput() { if (this->GetNumberOfIndexedOutputs() < 1) - return NULL; + return nullptr; return static_cast(this->ProcessObject::GetPrimaryOutput()); } mitk::IGTLMessage* mitk::IGTLMessageSource::GetOutput( DataObjectPointerArraySizeType idx) { IGTLMessage* out = dynamic_cast( this->ProcessObject::GetOutput(idx) ); - if ( out == NULL && this->ProcessObject::GetOutput(idx) != NULL ) + if ( out == nullptr && this->ProcessObject::GetOutput(idx) != NULL ) { itkWarningMacro (<< "Unable to convert output number " << idx << " to type " << typeid( IGTLMessage ).name () ); } return out; } mitk::IGTLMessage* mitk::IGTLMessageSource::GetOutput( const std::string& messageName) { DataObjectPointerArray outputs = this->GetOutputs(); for (DataObjectPointerArray::iterator it = outputs.begin(); it != outputs.end(); ++it) { if (messageName == (static_cast(it->GetPointer()))->GetName()) { return static_cast(it->GetPointer()); } } - return NULL; + return nullptr; } itk::ProcessObject::DataObjectPointerArraySizeType mitk::IGTLMessageSource::GetOutputIndex( std::string messageName ) { DataObjectPointerArray outputs = this->GetOutputs(); for (DataObjectPointerArray::size_type i = 0; i < outputs.size(); ++i) { if (messageName == (static_cast(outputs.at(i).GetPointer()))->GetName()) { return i; } } throw std::invalid_argument("output name does not exist"); } void mitk::IGTLMessageSource::RegisterAsMicroservice() { // Get Context us::ModuleContext* context = us::GetModuleContext(); // Define ServiceProps us::ServiceProperties props; mitk::UIDGenerator uidGen = mitk::UIDGenerator ("org.mitk.services.IGTLMessageSource.id_", 16); props[ US_PROPKEY_ID ] = uidGen.GetUID(); props[ US_PROPKEY_DEVICENAME ] = m_Name; props[ US_PROPKEY_DEVICETYPE ] = m_Type; m_ServiceRegistration = context->RegisterService(this, props); } void mitk::IGTLMessageSource::UnRegisterMicroservice() { - if (m_ServiceRegistration != NULL) m_ServiceRegistration.Unregister(); + if (m_ServiceRegistration != nullptr) + m_ServiceRegistration.Unregister(); m_ServiceRegistration = 0; } std::string mitk::IGTLMessageSource::GetMicroserviceID() { us::Any referenceProperty = this->m_ServiceRegistration.GetReference().GetProperty(US_PROPKEY_ID); return referenceProperty.ToString(); } void mitk::IGTLMessageSource::GraftOutput(itk::DataObject *graft) { this->GraftNthOutput(0, graft); } void mitk::IGTLMessageSource::GraftNthOutput(unsigned int idx, itk::DataObject *graft) { if ( idx >= this->GetNumberOfIndexedOutputs() ) { itkExceptionMacro(<<"Requested to graft output " << idx << " but this filter" "only has " << this->GetNumberOfIndexedOutputs() << " Outputs."); } if ( !graft ) { itkExceptionMacro(<<"Requested to graft output with a NULL pointer object" ); } itk::DataObject* output = this->GetOutput(idx); if ( !output ) { itkExceptionMacro(<<"Requested to graft output that is a NULL pointer" ); } // Call Graft on IGTLMessage to copy member data output->Graft( graft ); } itk::DataObject::Pointer mitk::IGTLMessageSource::MakeOutput ( DataObjectPointerArraySizeType /*idx*/ ) { return IGTLMessage::New().GetPointer(); } itk::DataObject::Pointer mitk::IGTLMessageSource::MakeOutput( const DataObjectIdentifierType & name ) { itkDebugMacro("MakeOutput(" << name << ")"); if( this->IsIndexedOutputName(name) ) { return this->MakeOutput( this->MakeIndexFromOutputName(name) ); } return static_cast(IGTLMessage::New().GetPointer()); } mitk::PropertyList::ConstPointer mitk::IGTLMessageSource::GetParameters() const { mitk::PropertyList::Pointer p = mitk::PropertyList::New(); // add properties to p like this: //p->SetProperty("MyFilter_MyParameter", mitk::PropertyDataType::New(m_MyParameter)); return mitk::PropertyList::ConstPointer(p); } void mitk::IGTLMessageSource::SetFPS(unsigned int fps) { this->m_StreamingFPSMutex->Lock(); this->m_StreamingFPS = fps; this->m_StreamingFPSMutex->Unlock(); } unsigned int mitk::IGTLMessageSource::GetFPS() { unsigned int fps = 0; this->m_StreamingFPSMutex->Lock(); fps = this->m_StreamingFPS; this->m_StreamingFPSMutex->Unlock(); return fps; } diff --git a/Modules/OpenIGTLink/mitkIGTLServer.cpp b/Modules/OpenIGTLink/mitkIGTLServer.cpp index c747e27cb0..4697f66e16 100644 --- a/Modules/OpenIGTLink/mitkIGTLServer.cpp +++ b/Modules/OpenIGTLink/mitkIGTLServer.cpp @@ -1,194 +1,194 @@ /*=================================================================== 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 "mitkIGTLServer.h" #include #include #include #include #include mitk::IGTLServer::IGTLServer() : IGTLDevice() { } mitk::IGTLServer::~IGTLServer() { } bool mitk::IGTLServer::OpenConnection() { if (this->GetState() != Setup) { mitkThrowException(mitk::Exception) << "Can only try to create a server if in setup mode"; return false; } int portNumber = this->GetPortNumber(); if (portNumber == -1 ) { //port number was not correct return false; } //create a new server socket m_Socket = igtl::ServerSocket::New(); //try to create the igtl server int response = dynamic_cast(m_Socket.GetPointer())-> CreateServer(portNumber); //check the response if ( response != 0 ) { mitkThrowException(mitk::Exception) << "The server could not be created. Port: " << portNumber; return false; } // everything is initialized and connected so the communication can be started this->SetState(Ready); return true; } bool mitk::IGTLServer::CloseConnection() { //remove all registered clients SocketListType allRegisteredSockets = m_RegisteredClients; this->StopCommunicationWithSocket(allRegisteredSockets); return mitk::IGTLDevice::CloseConnection(); } void mitk::IGTLServer::Connect() { igtl::Socket::Pointer socket; //check if another igtl device wants to connect to this socket socket = ((igtl::ServerSocket*)(this->m_Socket.GetPointer()))->WaitForConnection(1); //if there is a new connection the socket is not null if ( socket.IsNotNull() ) { //add the new client socket to the list of registered clients this->m_RegisteredClients.push_back(socket); //inform observers about this new client this->InvokeEvent(NewClientConnectionEvent()); MITK_INFO("IGTLServer") << "Connected to a new client."; } } void mitk::IGTLServer::Receive() { unsigned int status = IGTL_STATUS_OK; SocketListType socketsToBeRemoved; //the server can be connected with several clients, therefore it has to check //all registered clients SocketListIteratorType it; SocketListIteratorType it_end = this->m_RegisteredClients.end(); for ( it = this->m_RegisteredClients.begin(); it != it_end; ++it ) { //it is possible that ReceivePrivate detects that the current socket is //already disconnected. Therefore, it is necessary to remove this socket //from the registered clients list status = this->ReceivePrivate(*it); - if ( status == IGTL_STATUS_NOT_PRESENT ) + if (status == IGTL_STATUS_NOT_PRESENT) { //remember this socket for later, it is not a good idea to remove it //from the list directly because we iterator over the list at this point socketsToBeRemoved.push_back(*it); MITK_WARN("IGTLServer") << "Lost connection to a client socket. "; } } if ( socketsToBeRemoved.size() > 0 ) { //remove the sockets that are not connected anymore this->StopCommunicationWithSocket(socketsToBeRemoved); //inform observers about loosing the connection to these sockets this->InvokeEvent(LostConnectionEvent()); } } void mitk::IGTLServer::Send() { igtl::MessageBase::Pointer curMessage; //get the latest message from the queue curMessage = this->m_SendQueue->PullMessage(); // there is no message => return if ( curMessage.IsNull() ) return; //the server can be connected with several clients, therefore it has to check //all registered clients //sending a message to all registered clients might not be the best solution, //it could be better to store the client together with the requested type. Then //the data would be send to the appropriate client and to noone else. //(I know it is no excuse but PLUS is doing exactly the same, they broadcast //everything) SocketListIteratorType it; SocketListIteratorType it_end = this->m_RegisteredClients.end(); for ( it = this->m_RegisteredClients.begin(); it != it_end; ++it ) { //maybe there should be a check here if the current socket is still active this->SendMessagePrivate(curMessage.GetPointer(), *it); } } void mitk::IGTLServer::StopCommunicationWithSocket( SocketListType& toBeRemovedSockets) { SocketListIteratorType it = toBeRemovedSockets.begin(); SocketListIteratorType itEnd = toBeRemovedSockets.end(); for (; it != itEnd; ++it ) { this->StopCommunicationWithSocket(*it); } } void mitk::IGTLServer::StopCommunicationWithSocket(igtl::Socket* client) { SocketListIteratorType it = this->m_RegisteredClients.begin(); SocketListIteratorType itEnd = this->m_RegisteredClients.end(); for (; it != itEnd; ++it ) { if ( (*it) == client ) { //close the socket (*it)->CloseSocket(); //and remove it from the list this->m_RegisteredClients.remove(*it); break; } } MITK_INFO("IGTLServer") << "Removed client socket from server client list."; } unsigned int mitk::IGTLServer::GetNumberOfConnections() { return this->m_RegisteredClients.size(); } diff --git a/Modules/OpenIGTLinkUI/Qmitk/QmitkIGTLDeviceCommandWidget.cpp b/Modules/OpenIGTLinkUI/Qmitk/QmitkIGTLDeviceCommandWidget.cpp index 74e8505e67..7bd7536c4e 100644 --- a/Modules/OpenIGTLinkUI/Qmitk/QmitkIGTLDeviceCommandWidget.cpp +++ b/Modules/OpenIGTLinkUI/Qmitk/QmitkIGTLDeviceCommandWidget.cpp @@ -1,282 +1,293 @@ /*=================================================================== 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 "QmitkIGTLDeviceCommandWidget.h" //mitk headers #include #include #include #include //qt headers #include #include #include #include //igtl #include #include #include #include //poco headers #include const std::string QmitkIGTLDeviceCommandWidget::VIEW_ID = "org.mitk.views.igtldevicesourcemanagementwidget"; QmitkIGTLDeviceCommandWidget::QmitkIGTLDeviceCommandWidget( QWidget* parent, Qt::WindowFlags f) : QWidget(parent, f), m_IsClient(false) { m_Controls = NULL; this->m_IGTLDevice = NULL; CreateQtPartControl(this); } QmitkIGTLDeviceCommandWidget::~QmitkIGTLDeviceCommandWidget() { + this->m_IGTLDevice->RemoveObserver(m_MessageReceivedObserverTag); + this->m_IGTLDevice->RemoveObserver(m_CommandReceivedObserverTag); + this->m_IGTLDevice->RemoveObserver(m_LostConnectionObserverTag); + this->m_IGTLDevice->RemoveObserver(m_NewConnectionObserverTag); + this->m_IGTLDevice->RemoveObserver(m_StateModifiedObserverTag); } void QmitkIGTLDeviceCommandWidget::CreateQtPartControl(QWidget *parent) { if (!m_Controls) { // create GUI widgets m_Controls = new Ui::QmitkIGTLDeviceCommandWidgetControls; // setup GUI widgets m_Controls->setupUi(parent); } //connect slots with signals CreateConnections(); } void QmitkIGTLDeviceCommandWidget::CreateConnections() { if (m_Controls) { // connect the widget items with the methods connect( m_Controls->butSendCommand, SIGNAL(clicked()), this, SLOT(OnSendCommand())); connect( m_Controls->commandsComboBox, SIGNAL(currentIndexChanged(const QString &)), this, SLOT(OnCommandChanged(const QString &))); } + //this is used for thread seperation, otherwise the worker thread would change the ui elements + //which would cause an exception + connect(this, SIGNAL(AdaptGUIToStateSignal()), this, SLOT(AdaptGUIToState())); } void QmitkIGTLDeviceCommandWidget::OnDeviceStateChanged() { - this->AdaptGUIToState(); + //this->AdaptGUIToState(); + emit AdaptGUIToStateSignal(); } void QmitkIGTLDeviceCommandWidget::AdaptGUIToState() { if (this->m_IGTLDevice.IsNotNull()) { //check the state of the device mitk::IGTLDevice::IGTLDeviceState state = this->m_IGTLDevice->GetState(); switch (state) { case mitk::IGTLDevice::Setup: this->m_Controls->commandsComboBox->setEnabled(false); this->m_Controls->butSendCommand->setEnabled(false); this->m_Controls->fpsSpinBox->setEnabled(false); break; case mitk::IGTLDevice::Ready: this->m_Controls->commandsComboBox->setEnabled(true); this->m_Controls->butSendCommand->setEnabled(true); this->m_Controls->fpsSpinBox->setEnabled(false); break; case mitk::IGTLDevice::Running: if ( this->m_IGTLDevice->GetNumberOfConnections() == 0 ) { //just a server can run and have 0 connections this->m_Controls->butSendCommand->setEnabled(false); this->m_Controls->fpsSpinBox->setEnabled(false); this->m_Controls->commandsComboBox->setEnabled(false); } else { this->m_Controls->commandsComboBox->setEnabled(true); this->m_Controls->butSendCommand->setEnabled(true); // this->m_Controls->fpsSpinBox->setEnabled(true); } break; default: mitkThrow() << "Invalid Device State"; break; } } else { this->DisableSourceControls(); } } void QmitkIGTLDeviceCommandWidget::Initialize(mitk::IGTLDevice::Pointer device) { //reset the GUI DisableSourceControls(); //reset the observers if ( this->m_IGTLDevice.IsNotNull() ) { this->m_IGTLDevice->RemoveObserver(m_MessageReceivedObserverTag); this->m_IGTLDevice->RemoveObserver(m_CommandReceivedObserverTag); this->m_IGTLDevice->RemoveObserver(m_LostConnectionObserverTag); this->m_IGTLDevice->RemoveObserver(m_NewConnectionObserverTag); this->m_IGTLDevice->RemoveObserver(m_StateModifiedObserverTag); } if(device.IsNotNull()) { //get the device this->m_IGTLDevice = device; //check if the device is a server or a client if ( dynamic_cast( this->m_IGTLDevice.GetPointer()) == NULL ) { m_IsClient = false; } else { m_IsClient = true; } typedef itk::SimpleMemberCommand< QmitkIGTLDeviceCommandWidget > CurCommandType; // CurCommandType::Pointer messageReceivedCommand = CurCommandType::New(); // messageReceivedCommand->SetCallbackFunction( // this, &QmitkIGTLDeviceCommandWidget::OnMessageReceived ); // this->m_MessageReceivedObserverTag = // this->m_IGTLDevice->AddObserver(mitk::MessageReceivedEvent(), messageReceivedCommand); // CurCommandType::Pointer commandReceivedCommand = CurCommandType::New(); // commandReceivedCommand->SetCallbackFunction( // this, &QmitkIGTLDeviceCommandWidget::OnCommandReceived ); // this->m_CommandReceivedObserverTag = // this->m_IGTLDevice->AddObserver(mitk::CommandReceivedEvent(), commandReceivedCommand); CurCommandType::Pointer connectionLostCommand = CurCommandType::New(); connectionLostCommand->SetCallbackFunction( this, &QmitkIGTLDeviceCommandWidget::OnLostConnection ); this->m_LostConnectionObserverTag = this->m_IGTLDevice->AddObserver( mitk::LostConnectionEvent(), connectionLostCommand); CurCommandType::Pointer newConnectionCommand = CurCommandType::New(); newConnectionCommand->SetCallbackFunction( this, &QmitkIGTLDeviceCommandWidget::OnNewConnection ); this->m_NewConnectionObserverTag = this->m_IGTLDevice->AddObserver( mitk::NewClientConnectionEvent(), newConnectionCommand); CurCommandType::Pointer stateModifiedCommand = CurCommandType::New(); stateModifiedCommand->SetCallbackFunction( this, &QmitkIGTLDeviceCommandWidget::OnDeviceStateChanged ); this->m_StateModifiedObserverTag = this->m_IGTLDevice->AddObserver( itk::ModifiedEvent(), stateModifiedCommand); //Fill the commands combo box with all available commands FillCommandsComboBox(); } else { m_IGTLDevice = NULL; } this->AdaptGUIToState(); } void QmitkIGTLDeviceCommandWidget::DisableSourceControls() { this->m_Controls->commandsComboBox->setEnabled(false); this->m_Controls->butSendCommand->setEnabled(false); this->m_Controls->fpsSpinBox->setEnabled(false); } void QmitkIGTLDeviceCommandWidget::OnSendCommand() { //Set the frames per second of the current command in case of a STT_ command if ( std::strcmp( m_CurrentCommand->GetDeviceType(), "STT_BIND" ) == 0 ) { ((igtl::StartBindMessage*)this->m_CurrentCommand.GetPointer())-> SetResolution(this->m_Controls->fpsSpinBox->value()); } else if ( std::strcmp( m_CurrentCommand->GetDeviceType(), "STT_QTDATA" ) == 0 ) { ((igtl::StartQuaternionTrackingDataMessage*)m_CurrentCommand.GetPointer())-> SetResolution(this->m_Controls->fpsSpinBox->value()); } else if ( std::strcmp( m_CurrentCommand->GetDeviceType(), "STT_TDATA" ) == 0 ) { ((igtl::StartTrackingDataMessage*)this->m_CurrentCommand.GetPointer())-> SetResolution(this->m_Controls->fpsSpinBox->value()); } m_IGTLDevice->SendMessage(m_CurrentCommand.GetPointer()); } void QmitkIGTLDeviceCommandWidget::OnCommandChanged( const QString & curCommand) { if ( curCommand.isEmpty() ) return; mitk::IGTLMessageFactory::Pointer msgFactory = this->m_IGTLDevice->GetMessageFactory(); //create a new message that fits to the selected get message type command this->m_CurrentCommand = msgFactory->CreateInstance( curCommand.toStdString()); //enable/disable the FPS spinbox this->m_Controls->fpsSpinBox->setEnabled(curCommand.contains("STT_")); } void QmitkIGTLDeviceCommandWidget::OnLostConnection() { //get the IGTL device that invoked this event // mitk::IGTLDevice* dev = (mitk::IGTLDevice*)caller; - this->AdaptGUIToState(); + //this->AdaptGUIToState(); + emit AdaptGUIToStateSignal(); } void QmitkIGTLDeviceCommandWidget::OnNewConnection() { - this->AdaptGUIToState(); + //this->AdaptGUIToState(); + emit AdaptGUIToStateSignal(); } void QmitkIGTLDeviceCommandWidget::FillCommandsComboBox() { //load the msg factory from the client (maybe this will be moved later on) mitk::IGTLMessageFactory::Pointer msgFactory = this->m_IGTLDevice->GetMessageFactory(); //get the available commands as std::list std::list commandsList_ = msgFactory->GetAvailableMessageRequestTypes(); //create a string list to convert the std::list this->m_Controls->commandsComboBox->clear(); while ( commandsList_.size() ) { //fill the combo box with life this->m_Controls->commandsComboBox->addItem( QString::fromStdString(commandsList_.front())); commandsList_.pop_front(); } } diff --git a/Modules/OpenIGTLinkUI/Qmitk/QmitkIGTLDeviceCommandWidget.h b/Modules/OpenIGTLinkUI/Qmitk/QmitkIGTLDeviceCommandWidget.h index b3aa6317ad..e30e0ad2dc 100644 --- a/Modules/OpenIGTLinkUI/Qmitk/QmitkIGTLDeviceCommandWidget.h +++ b/Modules/OpenIGTLinkUI/Qmitk/QmitkIGTLDeviceCommandWidget.h @@ -1,132 +1,139 @@ /*=================================================================== 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 QMITKIGTLDeviceCommandWIDGET_H #define QMITKIGTLDeviceCommandWIDGET_H //QT headers #include #include //mitk headers #include "MitkOpenIGTLinkUIExports.h" #include "mitkIGTLDeviceSource.h" #include "mitkIGTLClient.h" #include "mitkDataStorage.h" //itk #include //ui header #include "ui_QmitkIGTLDeviceCommandWidgetControls.h" /** Documentation: * \brief An object of this class offers an UI to send OpenIGTLink commands. * * * \ingroup OpenIGTLinkUI */ class MITK_OPENIGTLINKUI_EXPORT QmitkIGTLDeviceCommandWidget : public QWidget { Q_OBJECT public: static const std::string VIEW_ID; /** * \brief Initializes the widget with the given device. * * The old device is * dropped, so be careful, if the source is not saved somewhere else it might * be lost. You might want to ask the user if he wants to save the changes * before calling this method. * \param device The widget will be initialized corresponding to the state of * this device. */ void Initialize(mitk::IGTLDevice::Pointer device); QmitkIGTLDeviceCommandWidget(QWidget* parent = 0, Qt::WindowFlags f = 0); ~QmitkIGTLDeviceCommandWidget(); - /** - * \brief Is called when the current device received a message - */ - void OnMessageReceived(); - /** - * \brief Is called when the current device received a command - */ - void OnCommandReceived(); + protected slots: + void OnCommandChanged(const QString& curCommand); + + void OnSendCommand(); + + ///** + //* \brief Is called when the current device received a message + //*/ + //void OnMessageReceived(); + + ///** + //* \brief Is called when the current device received a command + //*/ + //void OnCommandReceived(); /** - * \brief Is called when the current device lost a connection to one of its - * sockets + * \brief Is called when the current device lost a connection to one of its + * sockets */ void OnLostConnection(); /** - * \brief Is called when the current device connected to another device + * \brief Is called when the current device connected to another device */ void OnNewConnection(); + /** + * \brief Adapts the GUI to the state of the device + */ + void AdaptGUIToState(); - protected slots: - void OnCommandChanged(const QString& curCommand); - - void OnSendCommand(); + signals: + /** + * \brief used for thread seperation, the worker thread must not call AdaptGUIToState directly + * QT signals are thread safe and seperate the threads + */ + void AdaptGUIToStateSignal(); protected: - /** - * \brief Adapts the GUI to the state of the device - */ - void AdaptGUIToState(); - /** * \brief Calls AdaptGUIToState() */ void OnDeviceStateChanged(); /// \brief Fills the commands combo box with available commands void FillCommandsComboBox(); /// \brief Creation of the connections virtual void CreateConnections(); virtual void CreateQtPartControl(QWidget *parent); Ui::QmitkIGTLDeviceCommandWidgetControls* m_Controls; /** @brief holds the OpenIGTLink device */ mitk::IGTLDevice::Pointer m_IGTLDevice; igtl::MessageBase::Pointer m_CurrentCommand; /** @brief flag to indicate if the IGTL device is a client or a server */ bool m_IsClient; unsigned long m_MessageReceivedObserverTag; unsigned long m_CommandReceivedObserverTag; unsigned long m_LostConnectionObserverTag; unsigned long m_NewConnectionObserverTag; unsigned long m_StateModifiedObserverTag; //############## private help methods ####################### void DisableSourceControls(); void EnableSourceControls(); }; #endif diff --git a/Modules/OpenIGTLinkUI/Qmitk/QmitkIGTLDeviceSetupConnectionWidget.cpp b/Modules/OpenIGTLinkUI/Qmitk/QmitkIGTLDeviceSetupConnectionWidget.cpp index e5c130a026..3c371041a3 100644 --- a/Modules/OpenIGTLinkUI/Qmitk/QmitkIGTLDeviceSetupConnectionWidget.cpp +++ b/Modules/OpenIGTLinkUI/Qmitk/QmitkIGTLDeviceSetupConnectionWidget.cpp @@ -1,363 +1,346 @@ /*=================================================================== 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 "QmitkIGTLDeviceSetupConnectionWidget.h" //mitk headers #include #include #include #include //qt headers #include #include #include #include //igtl #include #include #include #include //poco headers #include const std::string QmitkIGTLDeviceSetupConnectionWidget::VIEW_ID = "org.mitk.views.igtldevicesetupconnectionwidget"; QmitkIGTLDeviceSetupConnectionWidget::QmitkIGTLDeviceSetupConnectionWidget( QWidget* parent, Qt::WindowFlags f) : QWidget(parent, f), m_IsClient(false) { m_Controls = NULL; this->m_IGTLDevice = NULL; CreateQtPartControl(this); } QmitkIGTLDeviceSetupConnectionWidget::~QmitkIGTLDeviceSetupConnectionWidget() { + this->m_IGTLDevice->RemoveObserver(m_MessageReceivedObserverTag); + this->m_IGTLDevice->RemoveObserver(m_CommandReceivedObserverTag); + this->m_IGTLDevice->RemoveObserver(m_LostConnectionObserverTag); + this->m_IGTLDevice->RemoveObserver(m_NewConnectionObserverTag); + this->m_IGTLDevice->RemoveObserver(m_StateModifiedObserverTag); } void QmitkIGTLDeviceSetupConnectionWidget::CreateQtPartControl(QWidget *parent) { if (!m_Controls) { // create GUI widgets m_Controls = new Ui::QmitkIGTLDeviceSetupConnectionWidgetControls; // setup GUI widgets m_Controls->setupUi(parent); } // set the validator for the ip edit box (values must be between 0 and 255 and // there are four of them, seperated with a point QRegExpValidator *v = new QRegExpValidator(this); QRegExp rx("((1{0,1}[0-9]{0,2}|2[0-4]{1,1}[0-9]{1,1}|25[0-5]{1,1})\\.){3,3}(1{0,1}[0-9]{0,2}|2[0-4]{1,1}[0-9]{1,1}|25[0-5]{1,1})"); v->setRegExp(rx); m_Controls->editIP->setValidator(v); // set the validator for the port edit box (values must be between 1 and 65535) m_Controls->editPort->setValidator(new QIntValidator(1, 65535, this)); //connect slots with signals CreateConnections(); } void QmitkIGTLDeviceSetupConnectionWidget::CreateConnections() { if (m_Controls) { // connect the widget items with the methods connect( m_Controls->butConnect, SIGNAL(clicked()), this, SLOT(OnConnect())); connect( m_Controls->editPort, SIGNAL(editingFinished()), this, SLOT(OnPortChanged()) ); connect( m_Controls->editIP, SIGNAL(editingFinished()), this, SLOT(OnHostnameChanged()) ); connect( m_Controls->bufferMsgCheckBox, SIGNAL(stateChanged(int)), this, SLOT(OnBufferIncomingMessages(int))); } + //this is used for thread seperation, otherwise the worker thread would change the ui elements + //which would cause an exception + connect(this, SIGNAL(AdaptGUIToStateSignal()), this, SLOT(AdaptGUIToState())); } void QmitkIGTLDeviceSetupConnectionWidget::OnDeviceStateChanged() { - this->AdaptGUIToState(); + emit AdaptGUIToStateSignal(); } void QmitkIGTLDeviceSetupConnectionWidget::AdaptGUIToState() { //check the validity of the device if ( this->m_IGTLDevice.IsNull() ) { return; } //check the state of the device mitk::IGTLDevice::IGTLDeviceState state = this->m_IGTLDevice->GetState(); switch (state) { case mitk::IGTLDevice::Setup: if ( !m_IsClient ) { m_Controls->butConnect->setText("Go Online"); this->m_Controls->editIP->setEnabled(false); } else { m_Controls->butConnect->setText("Connect"); this->m_Controls->editIP->setEnabled(true); } this->m_Controls->editPort->setEnabled(true); this->m_Controls->logSendReceiveMsg->setEnabled(false); this->m_Controls->bufferMsgCheckBox->setEnabled(false); this->m_Controls->butConnect->setEnabled(true); break; case mitk::IGTLDevice::Ready: this->m_Controls->butConnect->setText("Disconnect"); this->m_Controls->editIP->setEnabled(false); this->m_Controls->editPort->setEnabled(false); this->m_Controls->logSendReceiveMsg->setEnabled(true); this->m_Controls->bufferMsgCheckBox->setEnabled(true); this->m_Controls->butConnect->setEnabled(true); break; case mitk::IGTLDevice::Running: this->m_Controls->butConnect->setText("Disconnect"); this->m_Controls->editIP->setEnabled(false); this->m_Controls->editPort->setEnabled(false); this->m_Controls->logSendReceiveMsg->setEnabled(true); this->m_Controls->bufferMsgCheckBox->setEnabled(true); this->m_Controls->butConnect->setEnabled(true); break; default: mitkThrow() << "Invalid Device State"; break; } } void QmitkIGTLDeviceSetupConnectionWidget::Initialize( mitk::IGTLDevice::Pointer device) { //reset the GUI DisableSourceControls(); //reset the observers if ( this->m_IGTLDevice.IsNotNull() ) { this->m_IGTLDevice->RemoveObserver(m_MessageReceivedObserverTag); this->m_IGTLDevice->RemoveObserver(m_CommandReceivedObserverTag); this->m_IGTLDevice->RemoveObserver(m_LostConnectionObserverTag); this->m_IGTLDevice->RemoveObserver(m_NewConnectionObserverTag); this->m_IGTLDevice->RemoveObserver(m_StateModifiedObserverTag); } if(device.IsNotNull()) { this->m_IGTLDevice = device; //check if the device is a server or a client if ( dynamic_cast( this->m_IGTLDevice.GetPointer()) == NULL ) { m_IsClient = false; } else { m_IsClient = true; } this->AdaptGUIToState(); typedef itk::SimpleMemberCommand< QmitkIGTLDeviceSetupConnectionWidget > CurCommandType; + CurCommandType::Pointer messageSentCommand = CurCommandType::New(); + messageSentCommand->SetCallbackFunction( + this, &QmitkIGTLDeviceSetupConnectionWidget::OnMessageSent); + this->m_MessageSentObserverTag = this->m_IGTLDevice->AddObserver( + mitk::MessageSentEvent(), messageSentCommand); + CurCommandType::Pointer messageReceivedCommand = CurCommandType::New(); messageReceivedCommand->SetCallbackFunction( - this, &QmitkIGTLDeviceSetupConnectionWidget::OnMessageReceived ); + this, &QmitkIGTLDeviceSetupConnectionWidget::OnMessageReceived); this->m_MessageReceivedObserverTag = this->m_IGTLDevice->AddObserver( - mitk::MessageReceivedEvent(), messageReceivedCommand); + mitk::MessageReceivedEvent(), messageReceivedCommand); CurCommandType::Pointer commandReceivedCommand = CurCommandType::New(); commandReceivedCommand->SetCallbackFunction( this, &QmitkIGTLDeviceSetupConnectionWidget::OnCommandReceived ); this->m_CommandReceivedObserverTag = this->m_IGTLDevice->AddObserver( mitk::CommandReceivedEvent(), commandReceivedCommand); CurCommandType::Pointer connectionLostCommand = CurCommandType::New(); connectionLostCommand->SetCallbackFunction( this, &QmitkIGTLDeviceSetupConnectionWidget::OnLostConnection ); this->m_LostConnectionObserverTag = this->m_IGTLDevice->AddObserver( mitk::LostConnectionEvent(), connectionLostCommand); CurCommandType::Pointer newConnectionCommand = CurCommandType::New(); newConnectionCommand->SetCallbackFunction( this, &QmitkIGTLDeviceSetupConnectionWidget::OnNewConnection ); this->m_NewConnectionObserverTag = this->m_IGTLDevice->AddObserver( mitk::NewClientConnectionEvent(), newConnectionCommand); CurCommandType::Pointer stateModifiedCommand = CurCommandType::New(); stateModifiedCommand->SetCallbackFunction( this, &QmitkIGTLDeviceSetupConnectionWidget::OnDeviceStateChanged ); this->m_StateModifiedObserverTag = this->m_IGTLDevice->AddObserver( itk::ModifiedEvent(), stateModifiedCommand); } else { m_IGTLDevice = NULL; } } void QmitkIGTLDeviceSetupConnectionWidget::DisableSourceControls() { m_Controls->editIP->setEnabled(false); m_Controls->editPort->setEnabled(false); m_Controls->butConnect->setEnabled(false); m_Controls->bufferMsgCheckBox->setEnabled(false); m_Controls->logSendReceiveMsg->setEnabled(false); } void QmitkIGTLDeviceSetupConnectionWidget::OnConnect() { if(m_Controls->butConnect->text() == "Connect" || m_Controls->butConnect->text() == "Go Online" ) { QString port = m_Controls->editPort->text(); m_IGTLDevice->SetPortNumber(port.toInt()); std::string hostname = m_Controls->editIP->text().toStdString(); m_IGTLDevice->SetHostname(hostname); //connect with the other OpenIGTLink device => changes the state from Setup //to Ready if ( m_IGTLDevice->OpenConnection() ) { //starts the communication thread => changes the state from Ready to //Running if ( m_IGTLDevice->StartCommunication() ) { if ( this->m_IsClient ) { MITK_INFO("IGTLDeviceSourceManagementWidget") << "Successfully connected to " << hostname << " on port " << port.toStdString(); } } else { MITK_ERROR("QmitkIGTLDeviceSetupConnectionWidget") << "Could not start a communication with the" "server because the client is in the wrong state"; } } else { MITK_ERROR("QmitkIGTLDeviceSetupConnectionWidget") << "Could not connect to the server. " "Please check the hostname and port."; } } else { m_IGTLDevice->CloseConnection(); MITK_INFO("QmitkIGTLDeviceSetupConnectionWidget") << "Closed connection"; } this->AdaptGUIToState(); } void QmitkIGTLDeviceSetupConnectionWidget::OnPortChanged() { } void QmitkIGTLDeviceSetupConnectionWidget::OnHostnameChanged() { } void QmitkIGTLDeviceSetupConnectionWidget::OnLostConnection() { - //get the IGTL device that invoked this event -// mitk::IGTLDevice* dev = (mitk::IGTLDevice*)caller; - - this->AdaptGUIToState(); - -// unsigned int numConnections = dev->GetNumberOfConnections(); - -// if ( numConnections == 0 ) -// { -// if ( this->m_IsClient ) -// { -// //Setup connection groupbox -// m_Controls->editIP->setEnabled(true); -// m_Controls->editPort->setEnabled(true); -// m_Controls->butConnect->setText("Connect"); -// m_Controls->logSendReceiveMsg->setEnabled(false); -// m_Controls->bufferMsgCheckBox->setEnabled(false); -// } -// } + emit AdaptGUIToStateSignal(); } void QmitkIGTLDeviceSetupConnectionWidget::OnNewConnection() { - this->AdaptGUIToState(); - - //get the IGTL device that invoked this event -// mitk::IGTLDevice* dev = (mitk::IGTLDevice*)caller; - -// unsigned int numConnections = dev->GetNumberOfConnections(); - -// if ( numConnections != 0 ) -// { -// //Setup connection groupbox -// m_Controls->editIP->setEnabled(false); -// m_Controls->editPort->setEnabled(false); -// m_Controls->butConnect->setText("Disconnect"); -// m_Controls->logSendReceiveMsg->setEnabled(true); -// m_Controls->bufferMsgCheckBox->setEnabled(true); -// } + emit AdaptGUIToStateSignal(); } void QmitkIGTLDeviceSetupConnectionWidget::OnMessageReceived() { -// //get the IGTL device that invoked this event -// mitk::IGTLDevice* dev = (mitk::IGTLDevice*)caller; + if (this->m_Controls->logSendReceiveMsg->isChecked()) + { + MITK_INFO("IGTLDeviceSetupConnectionWidget") << "Received a message: " + << this->m_IGTLDevice->GetReceiveQueue()->GetLatestMsgInformationString(); + } +} - if ( this->m_Controls->logSendReceiveMsg->isChecked() ) - { - MITK_INFO("IGTLDeviceSetupConnectionWidget") << "Received a message: " - << this->m_IGTLDevice->GetReceiveQueue()->GetLatestMsgInformationString(); - } +void QmitkIGTLDeviceSetupConnectionWidget::OnMessageSent() +{ + if (this->m_Controls->logSendReceiveMsg->isChecked()) + { + MITK_INFO("IGTLDeviceSetupConnectionWidget") << "Sent a message."; + } } void QmitkIGTLDeviceSetupConnectionWidget::OnCommandReceived() { -// //get the IGTL device that invoked this event -// mitk::IGTLDevice* dev = (mitk::IGTLDevice*)caller; - if ( this->m_Controls->logSendReceiveMsg->isChecked() ) { MITK_INFO("IGTLDeviceSetupConnectionWidget") << "Received a command: " << this->m_IGTLDevice->GetCommandQueue()->GetLatestMsgInformationString(); } } void QmitkIGTLDeviceSetupConnectionWidget::OnBufferIncomingMessages(int state) { if ( this->m_IGTLDevice ) { this->m_IGTLDevice->EnableInfiniteBufferingMode( this->m_IGTLDevice->GetReceiveQueue(), (bool)state); } } diff --git a/Modules/OpenIGTLinkUI/Qmitk/QmitkIGTLDeviceSetupConnectionWidget.h b/Modules/OpenIGTLinkUI/Qmitk/QmitkIGTLDeviceSetupConnectionWidget.h index 488322ea94..0d953e982e 100644 --- a/Modules/OpenIGTLinkUI/Qmitk/QmitkIGTLDeviceSetupConnectionWidget.h +++ b/Modules/OpenIGTLinkUI/Qmitk/QmitkIGTLDeviceSetupConnectionWidget.h @@ -1,142 +1,154 @@ /*=================================================================== 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 QmitkIGTLDeviceSetupConnectionWidget_H #define QmitkIGTLDeviceSetupConnectionWidget_H //QT headers #include #include //mitk headers #include "MitkOpenIGTLinkUIExports.h" #include "mitkIGTLDeviceSource.h" #include "mitkIGTLClient.h" #include "mitkDataStorage.h" //itk #include //ui header #include "ui_QmitkIGTLDeviceSetupConnectionWidgetControls.h" /** Documentation: * \brief An object of this class offers an UI to setup the connection of an * OpenIGTLink device. * * * \ingroup OpenIGTLinkUI */ class MITK_OPENIGTLINKUI_EXPORT QmitkIGTLDeviceSetupConnectionWidget : public QWidget { Q_OBJECT public: static const std::string VIEW_ID; /** * \brief Initializes the widget with the given device. * * The old device is * dropped, so be careful, if the source is not saved somewhere else it might * be lost. You might want to ask the user if he wants to save the changes * before calling this method. * \param device The widget will be initialized corresponding to the state of * this device. */ void Initialize(mitk::IGTLDevice::Pointer device); QmitkIGTLDeviceSetupConnectionWidget(QWidget* parent = 0, Qt::WindowFlags f = 0); ~QmitkIGTLDeviceSetupConnectionWidget(); // /** // * \brief Is called when the current device received a message // */ // void OnMessageReceived(itk::Object* caller, const itk::EventObject&); // /** // * \brief Is called when the current device received a command // */ // void OnCommandReceived(itk::Object* caller, const itk::EventObject&); /** * \brief Is called when the current device lost a connection to one of its * sockets */ void OnLostConnection(); /** * \brief Is called when the current device connected to another device */ void OnNewConnection(); /** * \brief Is called when the current device received a message */ void OnMessageReceived(); + /** + * \brief Is called when the current device received a message + */ + void OnMessageSent(); + /** * \brief Is called when the current device received a command */ void OnCommandReceived(); protected slots: void OnConnect(); void OnPortChanged(); void OnHostnameChanged(); /** * \brief Enables/Disables the buffering of incoming messages */ void OnBufferIncomingMessages(int state); - protected: - /** - * \brief Adapts the GUI to the state of the device - */ + * \brief Adapts the GUI to the state of the device + */ void AdaptGUIToState(); + signals: + /** + * \brief used for thread seperation, the worker thread must not call AdaptGUIToState directly. + * QT signals are thread safe and seperate the threads + */ + void AdaptGUIToStateSignal(); + + protected: /** * \brief Calls AdaptGUIToState() */ void OnDeviceStateChanged(); /** \brief Creation of the connections */ virtual void CreateConnections(); virtual void CreateQtPartControl(QWidget *parent); Ui::QmitkIGTLDeviceSetupConnectionWidgetControls* m_Controls; /** @brief holds the OpenIGTLink device */ mitk::IGTLDevice::Pointer m_IGTLDevice; /** @brief flag to indicate if the IGTL device is a client or a server */ bool m_IsClient; + unsigned long m_MessageSentObserverTag; unsigned long m_MessageReceivedObserverTag; unsigned long m_CommandReceivedObserverTag; unsigned long m_LostConnectionObserverTag; unsigned long m_NewConnectionObserverTag; unsigned long m_StateModifiedObserverTag; //############## private help methods ####################### void DisableSourceControls(); // void EnableSourceControls(); }; #endif diff --git a/Modules/OpenIGTLinkUI/Qmitk/QmitkIGTLDeviceSourceManagementWidget.cpp b/Modules/OpenIGTLinkUI/Qmitk/QmitkIGTLDeviceSourceManagementWidget.cpp index 7fdd56d625..2e0205aeeb 100644 --- a/Modules/OpenIGTLinkUI/Qmitk/QmitkIGTLDeviceSourceManagementWidget.cpp +++ b/Modules/OpenIGTLinkUI/Qmitk/QmitkIGTLDeviceSourceManagementWidget.cpp @@ -1,307 +1,246 @@ /*=================================================================== 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 "QmitkIGTLDeviceSourceManagementWidget.h" //mitk headers #include #include #include #include //qt headers #include #include #include #include //igtl #include #include #include #include //poco headers #include const std::string QmitkIGTLDeviceSourceManagementWidget::VIEW_ID = "org.mitk.views.igtldevicesourcemanagementwidget"; QmitkIGTLDeviceSourceManagementWidget::QmitkIGTLDeviceSourceManagementWidget( QWidget* parent, Qt::WindowFlags f) : QWidget(parent, f), m_IsClient(false) { m_Controls = NULL; this->m_IGTLDevice = NULL; CreateQtPartControl(this); } QmitkIGTLDeviceSourceManagementWidget::~QmitkIGTLDeviceSourceManagementWidget() { + this->m_IGTLDevice->RemoveObserver(m_MessageReceivedObserverTag); + this->m_IGTLDevice->RemoveObserver(m_CommandReceivedObserverTag); + this->m_IGTLDevice->RemoveObserver(m_LostConnectionObserverTag); + this->m_IGTLDevice->RemoveObserver(m_NewConnectionObserverTag); + this->m_IGTLDevice->RemoveObserver(m_StateModifiedObserverTag); } void QmitkIGTLDeviceSourceManagementWidget::CreateQtPartControl(QWidget *parent) { if (!m_Controls) { // create GUI widgets m_Controls = new Ui::QmitkIGTLDeviceSourceManagementWidgetControls; // setup GUI widgets m_Controls->setupUi(parent); } //connect slots with signals CreateConnections(); } void QmitkIGTLDeviceSourceManagementWidget::CreateConnections() { if (m_Controls) { connect( m_Controls->butSend, SIGNAL(clicked()), this, SLOT(OnSendMessage())); } + //this is used for thread seperation, otherwise the worker thread would change the ui elements + //which would cause an exception + connect(this, SIGNAL(AdaptGUIToStateSignal()), this, SLOT(AdaptGUIToState())); } void QmitkIGTLDeviceSourceManagementWidget::OnDeviceStateChanged() { - this->AdaptGUIToState(); + emit AdaptGUIToStateSignal(); } void QmitkIGTLDeviceSourceManagementWidget::AdaptGUIToState() { if (this->m_IGTLDeviceSource.IsNotNull()) { //check the state of the device mitk::IGTLDevice::IGTLDeviceState state = this->m_IGTLDeviceSource->GetIGTLDevice()->GetState(); switch (state) { case mitk::IGTLDevice::Setup: this->m_Controls->editSend->setEnabled(false); this->m_Controls->butSend->setEnabled(false); break; case mitk::IGTLDevice::Ready: this->m_Controls->editSend->setEnabled(false); this->m_Controls->butSend->setEnabled(false); break; case mitk::IGTLDevice::Running: if ( this->m_IGTLDevice->GetNumberOfConnections() == 0 ) { //just a server can run and have 0 connections this->m_Controls->editSend->setEnabled(false); this->m_Controls->butSend->setEnabled(false); } else { this->m_Controls->editSend->setEnabled(true); this->m_Controls->butSend->setEnabled(true); } break; default: mitkThrow() << "Invalid Device State"; break; } m_Controls->selectedSourceLabel->setText( m_IGTLDeviceSource->GetName().c_str()); } else { this->DisableSourceControls(); } } void QmitkIGTLDeviceSourceManagementWidget::LoadSource( mitk::IGTLDeviceSource::Pointer sourceToLoad) { //reset the GUI DisableSourceControls(); //reset the observers if ( this->m_IGTLDevice.IsNotNull() ) { this->m_IGTLDevice->RemoveObserver(m_MessageReceivedObserverTag); this->m_IGTLDevice->RemoveObserver(m_CommandReceivedObserverTag); this->m_IGTLDevice->RemoveObserver(m_LostConnectionObserverTag); this->m_IGTLDevice->RemoveObserver(m_NewConnectionObserverTag); this->m_IGTLDevice->RemoveObserver(m_StateModifiedObserverTag); } if(sourceToLoad.IsNotNull()) { this->m_IGTLDeviceSource = sourceToLoad; //get the device this->m_IGTLDevice = this->m_IGTLDeviceSource->GetIGTLDevice(); //initialize the other GUI elements this->m_Controls->connectionSetupWidget->Initialize(this->m_IGTLDevice); this->m_Controls->commandWidget->Initialize(this->m_IGTLDevice); //check if the device is a server or a client if ( dynamic_cast( this->m_IGTLDeviceSource->GetIGTLDevice()) == NULL ) { m_IsClient = false; } else { m_IsClient = true; } typedef itk::SimpleMemberCommand< QmitkIGTLDeviceSourceManagementWidget > CurCommandType; CurCommandType::Pointer messageReceivedCommand = CurCommandType::New(); messageReceivedCommand->SetCallbackFunction( this, &QmitkIGTLDeviceSourceManagementWidget::OnMessageReceived ); this->m_MessageReceivedObserverTag = this->m_IGTLDevice->AddObserver(mitk::MessageReceivedEvent(), messageReceivedCommand); CurCommandType::Pointer commandReceivedCommand = CurCommandType::New(); commandReceivedCommand->SetCallbackFunction( this, &QmitkIGTLDeviceSourceManagementWidget::OnCommandReceived ); this->m_CommandReceivedObserverTag = this->m_IGTLDevice->AddObserver(mitk::CommandReceivedEvent(), commandReceivedCommand); CurCommandType::Pointer connectionLostCommand = CurCommandType::New(); connectionLostCommand->SetCallbackFunction( this, &QmitkIGTLDeviceSourceManagementWidget::OnLostConnection ); this->m_LostConnectionObserverTag = this->m_IGTLDevice->AddObserver( mitk::LostConnectionEvent(), connectionLostCommand); CurCommandType::Pointer newConnectionCommand = CurCommandType::New(); newConnectionCommand->SetCallbackFunction( this, &QmitkIGTLDeviceSourceManagementWidget::OnNewConnection ); this->m_NewConnectionObserverTag = this->m_IGTLDevice->AddObserver( mitk::NewClientConnectionEvent(), newConnectionCommand); CurCommandType::Pointer stateModifiedCommand = CurCommandType::New(); stateModifiedCommand->SetCallbackFunction( this, &QmitkIGTLDeviceSourceManagementWidget::OnDeviceStateChanged ); this->m_StateModifiedObserverTag = this->m_IGTLDevice->AddObserver( itk::ModifiedEvent(), stateModifiedCommand); } else { m_IGTLDeviceSource = NULL; } this->AdaptGUIToState(); } void QmitkIGTLDeviceSourceManagementWidget::DisableSourceControls() { m_Controls->selectedSourceLabel->setText(""); m_Controls->editSend->setEnabled(false); m_Controls->butSend->setEnabled(false); } void QmitkIGTLDeviceSourceManagementWidget::OnSendMessage() { std::string toBeSend = m_Controls->editSend->text().toStdString(); igtl::StringMessage::Pointer msg = igtl::StringMessage::New(); msg->SetString(toBeSend); this->m_IGTLDevice->SendMessage(msg.GetPointer()); } void QmitkIGTLDeviceSourceManagementWidget::OnMessageReceived() { -// //get the IGTL device that invoked this event -// mitk::IGTLDevice* dev = (mitk::IGTLDevice*)caller; - -// if ( this->m_Controls->logSendReceiveMsg->isChecked() ) -// { -// MITK_INFO("IGTLDeviceSourceManagementWidget") << "Received a message: " -// << dev->GetReceiveQueue()->GetLatestMsgInformationString(); -// } + } void QmitkIGTLDeviceSourceManagementWidget::OnCommandReceived() { -// //get the IGTL device that invoked this event -// mitk::IGTLDevice* dev = (mitk::IGTLDevice*)caller; - -// if ( this->m_Controls->logSendReceiveMsg->isChecked() ) -// { -// MITK_INFO("IGTLDeviceSourceManagementWidget") << "Received a command: " -// << dev->GetCommandQueue()->GetLatestMsgInformationString(); -// } + } void QmitkIGTLDeviceSourceManagementWidget::OnLostConnection() { - this->AdaptGUIToState(); -// //get the IGTL device that invoked this event -// mitk::IGTLDevice* dev = (mitk::IGTLDevice*)caller; - -// unsigned int numConnections = dev->GetNumberOfConnections(); - -// if ( numConnections == 0 ) -// { -// if ( this->m_IsClient ) -// { -// //Setup connection groupbox -// m_Controls->editIP->setEnabled(true); -// m_Controls->editPort->setEnabled(true); -// m_Controls->butConnect->setText("Connect"); -// m_Controls->logSendReceiveMsg->setEnabled(false); -// m_Controls->bufferMsgCheckBox->setEnabled(false); -// //send string messages groupbox -// m_Controls->editSend->setEnabled(false); -// m_Controls->butSend->setEnabled(false); -// //send command messages groupbox -// m_Controls->butSendCommand->setEnabled(false); -// m_Controls->fpsSpinBox->setEnabled(false); -// m_Controls->commandsComboBox->setEnabled(false); -// } -// else -// { -// //send string messages groupbox -// m_Controls->editSend->setEnabled(false); -// m_Controls->butSend->setEnabled(false); -// //send command messages groupbox -// m_Controls->butSendCommand->setEnabled(false); -// m_Controls->fpsSpinBox->setEnabled(false); -// m_Controls->commandsComboBox->setEnabled(false); -// } -// } + emit AdaptGUIToStateSignal(); } void QmitkIGTLDeviceSourceManagementWidget::OnNewConnection() { - this->AdaptGUIToState(); -// //get the IGTL device that invoked this event -// mitk::IGTLDevice* dev = (mitk::IGTLDevice*)caller; - -// unsigned int numConnections = dev->GetNumberOfConnections(); - -// if ( numConnections != 0 ) -// { -// //Setup connection groupbox -// m_Controls->editIP->setEnabled(false); -// m_Controls->editPort->setEnabled(false); -// m_Controls->butConnect->setText("Disconnect"); -// m_Controls->logSendReceiveMsg->setEnabled(true); -// m_Controls->bufferMsgCheckBox->setEnabled(true); -// //send string messages groupbox -// m_Controls->editSend->setEnabled(true); -// m_Controls->butSend->setEnabled(true); -// //send command messages groupbox -// m_Controls->butSendCommand->setEnabled(true); -//// m_Controls->fpsSpinBox->setEnabled(false); -// m_Controls->commandsComboBox->setEnabled(true); -// } + emit AdaptGUIToStateSignal(); } diff --git a/Modules/OpenIGTLinkUI/Qmitk/QmitkIGTLDeviceSourceManagementWidget.h b/Modules/OpenIGTLinkUI/Qmitk/QmitkIGTLDeviceSourceManagementWidget.h index 5d34e22183..19704495be 100644 --- a/Modules/OpenIGTLinkUI/Qmitk/QmitkIGTLDeviceSourceManagementWidget.h +++ b/Modules/OpenIGTLinkUI/Qmitk/QmitkIGTLDeviceSourceManagementWidget.h @@ -1,126 +1,132 @@ /*=================================================================== 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 QMITKIGTLDeviceSourceMANAGEMENTWIDGET_H #define QMITKIGTLDeviceSourceMANAGEMENTWIDGET_H //QT headers #include #include //mitk headers #include "MitkOpenIGTLinkUIExports.h" #include "mitkIGTLDeviceSource.h" #include "mitkIGTLClient.h" #include "mitkDataStorage.h" //itk #include //ui header #include "ui_QmitkIGTLDeviceSourceManagementWidgetControls.h" /** Documentation: * \brief An object of this class offers an UI to manage OpenIGTLink Device * Sources and OpenIGTLink Devices. * * * \ingroup OpenIGTLinkUI */ class MITK_OPENIGTLINKUI_EXPORT QmitkIGTLDeviceSourceManagementWidget : public QWidget { Q_OBJECT public: static const std::string VIEW_ID; /** Loads a source to the widget. The old source is dropped, so be careful, * if the source is not saved somewhere else it might be lost. You might * want to ask the user if he wants to save the changes before calling this * method. * @param sourceToLoad This source will be loaded and might be modified * by the user. */ void LoadSource(mitk::IGTLDeviceSource::Pointer sourceToLoad); QmitkIGTLDeviceSourceManagementWidget(QWidget* parent = 0, Qt::WindowFlags f = 0); ~QmitkIGTLDeviceSourceManagementWidget(); - /** - * \brief Is called when the current device received a message - */ - void OnMessageReceived(); - /** + protected slots: + void OnSendMessage(); + + /** + * \brief Is called when the current device received a message + */ + void OnMessageReceived(); + + /** * \brief Is called when the current device received a command - */ - void OnCommandReceived(); + */ + void OnCommandReceived(); - /** + /** * \brief Is called when the current device lost a connection to one of its * sockets - */ - void OnLostConnection(); + */ + void OnLostConnection(); - /** + /** * \brief Is called when the current device connected to another device - */ - void OnNewConnection(); - - - protected slots: - void OnSendMessage(); - - protected: - /** + */ + void OnNewConnection(); + /** * \brief Adapts the GUI to the state of the device */ - void AdaptGUIToState(); + void AdaptGUIToState(); + signals: + /** + * \brief used for thread seperation, the worker thread must not call AdaptGUIToState directly + * QT signals are thread safe and seperate the threads + */ + void AdaptGUIToStateSignal(); + + protected: /** * \brief Calls AdaptGUIToState() */ void OnDeviceStateChanged(); /// \brief Fills the commands combo box with available commands void FillCommandsComboBox(); /// \brief Creation of the connections virtual void CreateConnections(); virtual void CreateQtPartControl(QWidget *parent); Ui::QmitkIGTLDeviceSourceManagementWidgetControls* m_Controls; /** @brief holds the OpenIGTLink device */ mitk::IGTLDevice::Pointer m_IGTLDevice; /** @brief holds the IGTLDeviceSource we are working with. */ mitk::IGTLDeviceSource::Pointer m_IGTLDeviceSource; /** @brief flag to indicate if the IGTL device is a client or a server */ bool m_IsClient; unsigned long m_MessageReceivedObserverTag; unsigned long m_CommandReceivedObserverTag; unsigned long m_LostConnectionObserverTag; unsigned long m_NewConnectionObserverTag; unsigned long m_StateModifiedObserverTag; //############## private help methods ####################### void DisableSourceControls(); }; #endif diff --git a/Modules/OpenIGTLinkUI/Qmitk/QmitkIGTLStreamingManagementWidget.cpp b/Modules/OpenIGTLinkUI/Qmitk/QmitkIGTLStreamingManagementWidget.cpp index f4608eb86f..e6fc9280b6 100644 --- a/Modules/OpenIGTLinkUI/Qmitk/QmitkIGTLStreamingManagementWidget.cpp +++ b/Modules/OpenIGTLinkUI/Qmitk/QmitkIGTLStreamingManagementWidget.cpp @@ -1,307 +1,321 @@ /*=================================================================== 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 "QmitkIGTLStreamingManagementWidget.h" //mitk headers #include #include #include #include //qt headers #include #include #include #include //igtl #include #include #include #include //poco headers #include const std::string QmitkIGTLStreamingManagementWidget::VIEW_ID = "org.mitk.views.igtldevicesourcemanagementwidget"; QmitkIGTLStreamingManagementWidget::QmitkIGTLStreamingManagementWidget( QWidget* parent, Qt::WindowFlags f) : QWidget(parent, f), m_IsClient(false) { m_Controls = NULL; this->m_IGTLDevice = NULL; CreateQtPartControl(this); } QmitkIGTLStreamingManagementWidget::~QmitkIGTLStreamingManagementWidget() { + // this->m_IGTLDevice->RemoveObserver(m_MessageReceivedObserverTag); + // this->m_IGTLDevice->RemoveObserver(m_CommandReceivedObserverTag); + this->m_IGTLDevice->RemoveObserver(m_LostConnectionObserverTag); + this->m_IGTLDevice->RemoveObserver(m_NewConnectionObserverTag); + this->m_IGTLDevice->RemoveObserver(m_StateModifiedObserverTag); } void QmitkIGTLStreamingManagementWidget::CreateQtPartControl(QWidget *parent) { if (!m_Controls) { // create GUI widgets m_Controls = new Ui::QmitkIGTLStreamingManagementWidgetControls; // setup GUI widgets m_Controls->setupUi(parent); } //connect slots with signals CreateConnections(); } void QmitkIGTLStreamingManagementWidget::CreateConnections() { if (m_Controls) { connect( (QObject*)(m_Controls->messageSourceSelectionWidget), SIGNAL(IGTLMessageSourceSelected(mitk::IGTLMessageSource::Pointer)), this, SLOT(SourceSelected(mitk::IGTLMessageSource::Pointer)) ); connect( m_Controls->startStreamPushButton, SIGNAL(clicked()), this, SLOT(OnStartStreaming())); connect( m_Controls->stopStreamPushButton, SIGNAL(clicked()), this, SLOT(OnStopStreaming())); } + //this is used for thread seperation, otherwise the worker thread would change the ui elements + //which would cause an exception + connect(this, SIGNAL(AdaptGUIToStateSignal()), this, SLOT(AdaptGUIToState())); + connect(this, SIGNAL(SelectSourceAndAdaptGUISignal()), this, SLOT(SelectSourceAndAdaptGUI())); } void QmitkIGTLStreamingManagementWidget::AdaptGUIToState() { if (this->m_IGTLMsgProvider.IsNotNull()) { //get the state of the device mitk::IGTLDevice::IGTLDeviceState state = this->m_IGTLDevice->GetState(); switch (state) { case mitk::IGTLDevice::Setup: case mitk::IGTLDevice::Ready: m_Controls->messageSourceSelectionWidget->setEnabled(false); m_Controls->selectedSourceLabel->setText(""); m_Controls->startStreamPushButton->setEnabled(false); m_Controls->selectedSourceLabel->setEnabled(false); m_Controls->label->setEnabled(false); m_Controls->stopStreamPushButton->setEnabled(false); m_Controls->fpsLabel->setEnabled(false); m_Controls->fpsSpinBox->setEnabled(false); break; case mitk::IGTLDevice::Running: //check the number of connections of the device, a server can be in //the running state even if there is no connected device, this part of //the GUI shall just be available when there is a connection if ( this->m_IGTLDevice->GetNumberOfConnections() == 0 ) { m_Controls->messageSourceSelectionWidget->setEnabled(false); m_Controls->selectedSourceLabel->setText(""); m_Controls->startStreamPushButton->setEnabled(false); m_Controls->selectedSourceLabel->setEnabled(false); m_Controls->label->setEnabled(false); m_Controls->stopStreamPushButton->setEnabled(false); m_Controls->fpsLabel->setEnabled(false); m_Controls->fpsSpinBox->setEnabled(false); } else //there is a connection { //check if the user already selected a source to stream if ( this->m_IGTLMsgSource.IsNull() ) // he did not so far { m_Controls->messageSourceSelectionWidget->setEnabled(true); m_Controls->selectedSourceLabel->setText(""); m_Controls->startStreamPushButton->setEnabled(false); m_Controls->selectedSourceLabel->setEnabled(false); m_Controls->label->setEnabled(false); m_Controls->stopStreamPushButton->setEnabled(false); m_Controls->fpsLabel->setEnabled(false); m_Controls->fpsSpinBox->setEnabled(false); } else //user already selected a source { QString nameOfSource = QString::fromStdString(m_IGTLMsgSource->GetName()); m_Controls->messageSourceSelectionWidget->setEnabled(true); m_Controls->selectedSourceLabel->setText(nameOfSource); m_Controls->selectedSourceLabel->setEnabled(true); m_Controls->label->setEnabled(true); //check if the streaming is already running if (this->m_IGTLMsgProvider->IsStreaming()) { m_Controls->startStreamPushButton->setEnabled(false); m_Controls->stopStreamPushButton->setEnabled(true); m_Controls->fpsLabel->setEnabled(false); m_Controls->fpsSpinBox->setEnabled(false); } else { m_Controls->startStreamPushButton->setEnabled(true); m_Controls->stopStreamPushButton->setEnabled(false); m_Controls->fpsLabel->setEnabled(true); m_Controls->fpsSpinBox->setEnabled(true); } } } break; default: mitkThrow() << "Invalid Device State"; break; } } else { this->DisableSourceControls(); } } void QmitkIGTLStreamingManagementWidget::LoadSource( mitk::IGTLMessageProvider::Pointer provider) { //reset the GUI DisableSourceControls(); if ( provider.IsNull() ) return; //reset the observers if ( this->m_IGTLDevice.IsNotNull() ) { // this->m_IGTLDevice->RemoveObserver(m_MessageReceivedObserverTag); // this->m_IGTLDevice->RemoveObserver(m_CommandReceivedObserverTag); this->m_IGTLDevice->RemoveObserver(m_LostConnectionObserverTag); this->m_IGTLDevice->RemoveObserver(m_NewConnectionObserverTag); this->m_IGTLDevice->RemoveObserver(m_StateModifiedObserverTag); } this->m_IGTLMsgProvider = provider; //get the device this->m_IGTLDevice = this->m_IGTLMsgProvider->GetIGTLDevice(); //check if the device is a server or a client if ( dynamic_cast( this->m_IGTLDevice.GetPointer()) == NULL ) { m_IsClient = false; } else { m_IsClient = true; } typedef itk::SimpleMemberCommand< QmitkIGTLStreamingManagementWidget > CurCommandType; // CurCommandType::Pointer messageReceivedCommand = CurCommandType::New(); // messageReceivedCommand->SetCallbackFunction( // this, &QmitkIGTLStreamingManagementWidget::OnMessageReceived ); // this->m_MessageReceivedObserverTag = // this->m_IGTLDevice->AddObserver(mitk::MessageReceivedEvent(), messageReceivedCommand); // CurCommandType::Pointer commandReceivedCommand = CurCommandType::New(); // commandReceivedCommand->SetCallbackFunction( // this, &QmitkIGTLStreamingManagementWidget::OnCommandReceived ); // this->m_CommandReceivedObserverTag = // this->m_IGTLDevice->AddObserver(mitk::CommandReceivedEvent(), commandReceivedCommand); CurCommandType::Pointer connectionLostCommand = CurCommandType::New(); connectionLostCommand->SetCallbackFunction( this, &QmitkIGTLStreamingManagementWidget::OnLostConnection ); this->m_LostConnectionObserverTag = this->m_IGTLDevice->AddObserver( mitk::LostConnectionEvent(), connectionLostCommand); CurCommandType::Pointer newConnectionCommand = CurCommandType::New(); newConnectionCommand->SetCallbackFunction( this, &QmitkIGTLStreamingManagementWidget::OnNewConnection ); this->m_NewConnectionObserverTag = this->m_IGTLDevice->AddObserver( mitk::NewClientConnectionEvent(), newConnectionCommand); CurCommandType::Pointer stateModifiedCommand = CurCommandType::New(); stateModifiedCommand->SetCallbackFunction( this, &QmitkIGTLStreamingManagementWidget::OnDeviceStateChanged ); this->m_StateModifiedObserverTag = this->m_IGTLDevice->AddObserver( itk::ModifiedEvent(), stateModifiedCommand); this->AdaptGUIToState(); } void QmitkIGTLStreamingManagementWidget::DisableSourceControls() { m_Controls->selectedSourceLabel->setText(""); m_Controls->startStreamPushButton->setEnabled(false); m_Controls->stopStreamPushButton->setEnabled(false); m_Controls->fpsLabel->setEnabled(false); m_Controls->fpsSpinBox->setEnabled(false); m_Controls->selectedSourceLabel->setEnabled(false); m_Controls->label->setEnabled(false); m_Controls->messageSourceSelectionWidget->setEnabled(false); } void QmitkIGTLStreamingManagementWidget::SourceSelected( mitk::IGTLMessageSource::Pointer source) { //reset everything this->DisableSourceControls(); if (source.IsNotNull()) //no source selected { this->m_IGTLMsgSource = source; } this->AdaptGUIToState(); } void QmitkIGTLStreamingManagementWidget::OnStartStreaming() { unsigned int fps = this->m_Controls->fpsSpinBox->value(); this->m_IGTLMsgProvider->StartStreamingOfSource(this->m_IGTLMsgSource, fps); this->AdaptGUIToState(); } void QmitkIGTLStreamingManagementWidget::OnStopStreaming() { this->m_IGTLMsgProvider->StopStreamingOfSource(this->m_IGTLMsgSource); this->AdaptGUIToState(); } void QmitkIGTLStreamingManagementWidget::OnMessageReceived() { } void QmitkIGTLStreamingManagementWidget::OnCommandReceived() { } void QmitkIGTLStreamingManagementWidget::OnDeviceStateChanged() { - this->AdaptGUIToState(); + emit AdaptGUIToStateSignal(); } void QmitkIGTLStreamingManagementWidget::OnLostConnection() { - this->AdaptGUIToState(); + emit AdaptGUIToStateSignal(); } void QmitkIGTLStreamingManagementWidget::OnNewConnection() { - //get the current selection and call SourceSelected which will call AdaptGUI - mitk::IGTLMessageSource::Pointer curSelSrc = + emit SelectSourceAndAdaptGUISignal(); +} + +void QmitkIGTLStreamingManagementWidget::SelectSourceAndAdaptGUI() +{ + //get the current selection and call SourceSelected which will call AdaptGUI + mitk::IGTLMessageSource::Pointer curSelSrc = m_Controls->messageSourceSelectionWidget->GetSelectedIGTLMessageSource(); - SourceSelected(curSelSrc); + SourceSelected(curSelSrc); } diff --git a/Modules/OpenIGTLinkUI/Qmitk/QmitkIGTLStreamingManagementWidget.h b/Modules/OpenIGTLinkUI/Qmitk/QmitkIGTLStreamingManagementWidget.h index b89d5af0bb..d83388c14d 100644 --- a/Modules/OpenIGTLinkUI/Qmitk/QmitkIGTLStreamingManagementWidget.h +++ b/Modules/OpenIGTLinkUI/Qmitk/QmitkIGTLStreamingManagementWidget.h @@ -1,135 +1,154 @@ /*=================================================================== 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 QMITKIGTLStreamingMANAGEMENTWIDGET_H #define QMITKIGTLStreamingMANAGEMENTWIDGET_H //QT headers #include #include //mitk headers #include "MitkOpenIGTLinkUIExports.h" #include "mitkIGTLMessageProvider.h" #include "mitkIGTLClient.h" #include "mitkDataStorage.h" //itk #include //ui header #include "ui_QmitkIGTLStreamingManagementWidgetControls.h" /** Documentation: * \brief An object of this class offers an UI to manage the streaming of * message sources. * * * \ingroup OpenIGTLinkUI */ class MITK_OPENIGTLINKUI_EXPORT QmitkIGTLStreamingManagementWidget : public QWidget { Q_OBJECT public: static const std::string VIEW_ID; /** Loads a provider to the widget. The old source is dropped, so be careful, * if the source is not saved somewhere else it might be lost. You might * want to ask the user if he wants to save the changes before calling this * method. * @param provider This provider will be loaded and might be modified * by the user. */ void LoadSource(mitk::IGTLMessageProvider::Pointer provider); QmitkIGTLStreamingManagementWidget(QWidget* parent = 0, Qt::WindowFlags f = 0); ~QmitkIGTLStreamingManagementWidget(); /** * \brief Is called when the current device received a message */ void OnMessageReceived(); /** * \brief Is called when the current device received a command */ void OnCommandReceived(); /** * \brief Is called when the current device lost a connection to one of its * sockets */ void OnLostConnection(); /** * \brief Is called when the current device connected to another device */ void OnNewConnection(); protected slots: void OnStartStreaming(); void OnStopStreaming(); /** \brief Is called when a new source is selected. * @param source the newly selected source */ void SourceSelected(mitk::IGTLMessageSource::Pointer source); - protected: /** - * \brief Adapts the GUI to the state of the device - */ + * \brief Adapts the GUI to the state of the device + */ void AdaptGUIToState(); + /** + * \brief selects the current source and adapts the GUI according to the selection + */ + void SelectSourceAndAdaptGUI(); + + signals: + /** + * \brief used for thread seperation, the worker thread must not call AdaptGUIToState directly. + * QT signals are thread safe and seperate the threads + */ + void AdaptGUIToStateSignal(); + /** + * \brief used for thread seperation, the worker thread must not call SelectSourceAndAdaptGUI + * directly. + * QT signals are thread safe and seperate the threads + */ + void SelectSourceAndAdaptGUISignal(); + + protected: + /** * \brief Calls AdaptGUIToState() */ void OnDeviceStateChanged(); /// \brief Fills the commands combo box with available commands void FillCommandsComboBox(); /// \brief Creation of the connections virtual void CreateConnections(); virtual void CreateQtPartControl(QWidget *parent); Ui::QmitkIGTLStreamingManagementWidgetControls* m_Controls; /** @brief holds the OpenIGTLink device */ mitk::IGTLDevice::Pointer m_IGTLDevice; /** @brief holds the IGTL Message Provider that will send the stream */ mitk::IGTLMessageProvider::Pointer m_IGTLMsgProvider; /** @brief holds the IGTLDeviceSource we are working with. */ mitk::IGTLMessageSource::Pointer m_IGTLMsgSource; /** @brief flag to indicate if the IGTL device is a client or a server */ bool m_IsClient; unsigned long m_MessageReceivedObserverTag; unsigned long m_CommandReceivedObserverTag; unsigned long m_LostConnectionObserverTag; unsigned long m_NewConnectionObserverTag; unsigned long m_StateModifiedObserverTag; //############## private help methods ####################### void DisableSourceControls(); }; #endif