fw4spl
SIOSelector.cpp
1 /* ***** BEGIN LICENSE BLOCK *****
2  * FW4SPL - Copyright (C) IRCAD, 2009-2018.
3  * Distributed under the terms of the GNU Lesser General Public License (LGPL) as
4  * published by the Free Software Foundation.
5  * ****** END LICENSE BLOCK ****** */
6 
7 #include "uiIO/editor/SIOSelector.hpp"
8 
9 #include <fwCom/Signal.hxx>
10 #include <fwCom/Slots.hpp>
11 #include <fwCom/Slots.hxx>
12 
13 #include <fwCore/base.hpp>
14 
15 #include <fwData/Composite.hpp>
16 
17 #include <fwDataTools/helper/Composite.hpp>
18 
19 #include <fwGui/Cursor.hpp>
20 #include <fwGui/dialog/MessageDialog.hpp>
21 #include <fwGui/dialog/SelectorDialog.hpp>
22 
23 #include <fwIO/IReader.hpp>
24 #include <fwIO/IWriter.hpp>
25 
26 #include <fwRuntime/ConfigurationElement.hpp>
27 #include <fwRuntime/helper.hpp>
28 
29 #include <fwServices/macros.hpp>
30 #include <fwServices/op/Add.hpp>
31 #include <fwServices/registry/ServiceConfig.hpp>
32 #include <fwServices/registry/ServiceFactory.hpp>
33 
34 #include <boost/foreach.hpp>
35 
36 #include <sstream>
37 #include <string>
38 
39 namespace uiIO
40 {
41 
42 namespace editor
43 {
44 
45 //------------------------------------------------------------------------------
46 
48 
49 static const ::fwCom::Signals::SignalKeyType JOB_CREATED_SIGNAL = "jobCreated";
50 static const ::fwCom::Slots::SlotKeyType FORWARD_JOB_SLOT = "forwardJob";
51 
52 //------------------------------------------------------------------------------
53 
55  m_mode( READER_MODE ),
56  m_servicesAreExcluded( true )
57 {
58  m_sigJobCreated = newSignal< JobCreatedSignalType >( JOB_CREATED_SIGNAL );
59  m_slotForwardJob = newSlot( FORWARD_JOB_SLOT, &SIOSelector::forwardJob, this );
60 }
61 
62 //------------------------------------------------------------------------------
63 
65 {
66 }
67 
68 //------------------------------------------------------------------------------
69 
71 {
72  const ConfigType srvConfig = this->getConfigTree();
73 
74  const std::string mode = srvConfig.get<std::string>("type.<xmlattr>.mode", "reader");
75  SLM_ASSERT("The xml attribute <mode> must be 'reader' (to open file) or 'writer' (to write a new file).",
76  mode == "writer" || mode == "reader" );
77  m_mode = ( mode == "writer" ) ? WRITER_MODE : READER_MODE;
78  SLM_DEBUG( "mode => " + mode );
79 
80  m_dataClassname = srvConfig.get<std::string>("type.<xmlattr>.class", "");
81 
82  const std::string selectionMode = srvConfig.get<std::string>("selection.<xmlattr>.mode", "exclude");
83  SLM_ASSERT( "The xml attribute <mode> must be 'include' (to add the selection to selector list ) or "
84  "'exclude' (to exclude the selection of the selector list).",
85  selectionMode == "exclude" || selectionMode == "include" );
86  m_servicesAreExcluded = ( selectionMode == "exclude" );
87  SLM_DEBUG( "selection mode => " + selectionMode );
88 
89  const auto selectionCfg = srvConfig.equal_range("addSelection");
90  for (auto itSelection = selectionCfg.first; itSelection != selectionCfg.second; ++itSelection)
91  {
92  const std::string service = itSelection->second.get<std::string>("<xmlattr>.service");
93  m_selectedServices.push_back(service);
94  SLM_DEBUG( "add selection => " + service );
95 
96  const std::string configId = itSelection->second.get<std::string>("<xmlattr>.config", "");
97  if(!configId.empty())
98  {
99  m_serviceToConfig[service] = configId;
100  SLM_DEBUG( "add config '" + configId + "' for service '" + service + "'");
101  }
102  }
103 
104  const auto configCfg = srvConfig.equal_range("config");
105  for (auto itCfg = configCfg.first; itCfg != configCfg.second; ++itCfg)
106  {
107  const std::string service = itCfg->second.get<std::string>("<xmlattr>.service");
108  const std::string configId = itCfg->second.get<std::string>("<xmlattr>.id");
109 
110  m_serviceToConfig[service] = configId;
111  SLM_DEBUG( "add config '" + configId + "' for service '" + service + "'");
112  }
113 }
114 
115 //------------------------------------------------------------------------------
116 
118 {
119 }
120 
121 //------------------------------------------------------------------------------
122 
124 {
125 }
126 
127 //------------------------------------------------------------------------------
128 
130 {
131  bool createOutput = false;
132  ::fwData::Object::sptr obj = this->getInOut< ::fwData::Object>(::fwIO::s_DATA_KEY);
133 
134  // Retrieve implementation of type ::fwIO::IReader for this object
135  std::vector< std::string > availableExtensionsId;
136  if ( m_mode == READER_MODE )
137  {
138  std::string classname = m_dataClassname;
139 
140  // FIXME: support for old version using getObject(): all the 'in' or 'inout' keys were possible
141  if (!obj && classname.empty())
142  {
143  FW_DEPRECATED_KEY(::fwIO::s_DATA_KEY, "inout", "18.0");
144  obj = this->getObject();
145  }
146  if (obj)
147  {
148  SLM_WARN_IF("The 'class' attribute is defined, but the object is set as 'inout', only the object classname "
149  "is used", !classname.empty())
150  classname = obj->getClassname();
151  }
152  createOutput = (!obj && !m_dataClassname.empty());
153  availableExtensionsId =
154  ::fwServices::registry::ServiceFactory::getDefault()->getImplementationIdFromObjectAndType(
155  classname, "::fwIO::IReader");
156  }
157  else // m_mode == WRITER_MODE
158  {
159  // FIXME: support for old version using getObject(): all the 'in' or 'inout' keys were possible
160  if (!obj)
161  {
162  FW_DEPRECATED_KEY(::fwIO::s_DATA_KEY, "inout", "18.0");
163  obj = this->getObject();
164  }
165  availableExtensionsId =
166  ::fwServices::registry::ServiceFactory::getDefault()->getImplementationIdFromObjectAndType(
167  obj->getClassname(), "::fwIO::IWriter");
168  }
169 
170  // Filter available extensions and replace id by service description
171  std::vector< std::pair < std::string, std::string > > availableExtensionsMap;
172  std::vector< std::string > availableExtensionsSelector;
173 
174  for( const std::string& serviceId : availableExtensionsId )
175  {
176  bool serviceIsSelectedByUser =
177  std::find( m_selectedServices.begin(), m_selectedServices.end(),
178  serviceId ) != m_selectedServices.end();
179 
180  // Test if the service is considered here as available by users, if yes push in availableExtensionsSelector
181  // excluded mode => add services that are not selected by users
182  // included mode => add services selected by users
183  if( (m_servicesAreExcluded && !serviceIsSelectedByUser) ||
184  (!m_servicesAreExcluded && serviceIsSelectedByUser) )
185  {
186  // Add this service
187  std::string infoUser =
188  ::fwServices::registry::ServiceFactory::getDefault()->getServiceDescription(serviceId);
189 
190  std::map< std::string, std::string >::const_iterator iter = m_serviceToConfig.find( serviceId );
191  if ( iter != m_serviceToConfig.end() )
192  {
193  infoUser = ::fwServices::registry::ServiceConfig::getDefault()->getConfigDesc(iter->second);
194  }
195 
196  if (infoUser != "")
197  {
198  availableExtensionsMap.push_back( std::pair < std::string, std::string > (serviceId, infoUser) );
199  availableExtensionsSelector.push_back( infoUser );
200  }
201  else
202  {
203  availableExtensionsMap.push_back( std::pair < std::string, std::string > (serviceId, serviceId) );
204  availableExtensionsSelector.push_back( serviceId );
205  }
206  }
207  }
208 
209  // Sort available services (lexical string sort)
210  std::sort( availableExtensionsSelector.begin(), availableExtensionsSelector.end() );
211 
212  // Test if we have an extension
213  if ( !availableExtensionsMap.empty() )
214  {
215  std::string extensionId = availableExtensionsMap[0].first;
216  bool extensionSelectionIsCanceled = false;
217 
218  // Selection of extension when availableExtensions.size() > 1
219  if ( availableExtensionsSelector.size() > 1 )
220  {
221  ::fwGui::dialog::SelectorDialog::sptr selector = ::fwGui::dialog::SelectorDialog::New();
222 
223  if ( m_mode != READER_MODE )
224  {
225  selector->setTitle("Writer to use");
226  }
227  else
228  {
229  selector->setTitle("Reader to use");
230  }
231  selector->setSelections(availableExtensionsSelector);
232  std::string selection = selector->show();
233  if( !selection.empty() )
234  {
235  bool extensionIdFound = false;
236 
237  typedef std::pair < std::string, std::string > PairType;
238  for(PairType pair : availableExtensionsMap)
239  {
240  if (pair.second == selection )
241  {
242  extensionId = pair.first;
243  extensionIdFound = true;
244  }
245  }
246  OSLM_ASSERT("Problem to find the selected string.", extensionIdFound );
247  }
248  else
249  {
250  extensionSelectionIsCanceled = true;
251  }
252  }
253 
254  if ( !extensionSelectionIsCanceled )
255  {
256 
257  // Get Config
258  bool hasConfigForService = false;
259  ::fwRuntime::ConfigurationElement::csptr srvCfg;
260  if ( m_serviceToConfig.find( extensionId ) != m_serviceToConfig.end() )
261  {
262  hasConfigForService = true;
263  srvCfg = ::fwServices::registry::ServiceConfig::getDefault()->getServiceConfig(
264  m_serviceToConfig[extensionId], extensionId );
265  SLM_ASSERT(
266  "No service configuration of type ::fwServices::registry::ServiceConfig was found",
267  srvCfg );
268  }
269 
270  // Configure and start service
271  if ( m_mode == READER_MODE )
272  {
273  if(createOutput)
274  {
275  obj = ::fwData::factory::New(m_dataClassname);
276  SLM_ASSERT("Cannot create object with classname='" + m_dataClassname + "'", obj);
277  }
278 
279  ::fwIO::IReader::sptr reader = ::fwServices::add< ::fwIO::IReader >( extensionId );
280  reader->registerInOut(obj, ::fwIO::s_DATA_KEY);
281  reader->setWorker(m_associatedWorker);
282 
283  if ( hasConfigForService )
284  {
285  reader->setConfiguration( ::fwRuntime::ConfigurationElement::constCast(srvCfg) );
286  reader->configure();
287  }
288 
289  auto jobCreatedSignal = reader->signal("jobCreated");
290  if(jobCreatedSignal)
291  {
292  jobCreatedSignal->connect(m_slotForwardJob);
293  }
294 
295  try
296  {
297  reader->start();
298  reader->configureWithIHM();
299 
300  ::fwGui::Cursor cursor;
301  cursor.setCursor(::fwGui::ICursor::BUSY);
302  reader->update();
303  cursor.setDefaultCursor();
304 
305  reader->stop();
306  ::fwServices::OSR::unregisterService(reader);
307 
308  if (createOutput)
309  {
310  this->setOutput(::fwIO::s_DATA_KEY, obj);
311  }
312  }
313  catch (std::exception& e)
314  {
315  std::string msg = "Failed to read : \n" + std::string(e.what());
317  }
318  }
319  else
320  {
321  // When all writers make use of getObject(), we can use the following code instead:
322  // ::fwIO::IWriter::sptr writer = ::fwServices::add< ::fwIO::IWriter >( extensionId );
323  // writer->registerInput(this->getObject(), ::fwIO::s_DATA_KEY);
324 
326  ::fwIO::IWriter::sptr writer =
327  ::fwIO::IWriter::dynamicCast(factory->create( "::fwIO::IWriter", extensionId));
328  ::fwServices::OSR::registerService(obj, ::fwIO::s_DATA_KEY,
329  ::fwServices::IService::AccessType::INPUT, writer);
330 
331  writer->setWorker(m_associatedWorker);
332 
333  if ( hasConfigForService )
334  {
335  writer->setConfiguration( ::fwRuntime::ConfigurationElement::constCast(srvCfg) );
336  writer->configure();
337  }
338 
339  auto jobCreatedSignal = writer->signal("jobCreated");
340  if(jobCreatedSignal)
341  {
342  jobCreatedSignal->connect(m_slotForwardJob);
343  }
344 
345  try
346  {
347  writer->start();
348  writer->configureWithIHM();
349 
350  ::fwGui::Cursor cursor;
351  cursor.setCursor(::fwGui::ICursor::BUSY);
352  writer->update();
353  cursor.setDefaultCursor();
354 
355  writer->stop();
356  ::fwServices::OSR::unregisterService(writer);
357  }
358  catch (std::exception& e)
359  {
360  std::string msg = "Failed to write : \n" + std::string(e.what());
362  }
363  }
364  }
365  }
366  else
367  {
368  SLM_WARN("SIOSelector::load : availableExtensions is empty.");
369  if ( m_mode == READER_MODE )
370  {
372  messageBox.setTitle("Reader not found");
373  messageBox.setMessage( "There are no available readers for this data type." );
374  messageBox.setIcon(::fwGui::dialog::IMessageDialog::WARNING);
375  messageBox.addButton(::fwGui::dialog::IMessageDialog::OK);
376  messageBox.show();
377  }
378  else // m_mode == WRITER_MODE
379  {
381  messageBox.setTitle("Writer not found");
382  messageBox.setMessage( "There are no available writers for this data type." );
383  messageBox.setIcon(::fwGui::dialog::IMessageDialog::WARNING);
384  messageBox.addButton(::fwGui::dialog::IMessageDialog::OK);
385  messageBox.show();
386  }
387  }
388 }
389 
390 //------------------------------------------------------------------------------
391 
392 void SIOSelector::info( std::ostream& _sstream )
393 {
394  // Update message
395  _sstream << "SIOSelector";
396 }
397 
398 //------------------------------------------------------------------------------
399 
401 {
402  m_mode = _mode;
403 }
404 
405 //------------------------------------------------------------------------------
406 
407 void SIOSelector::forwardJob(::fwJobs::IJob::sptr iJob)
408 {
409  m_sigJobCreated->emit(iJob);
410 }
411 
412 //------------------------------------------------------------------------------
413 } // namespace editor
414 
415 } // namespace gui
#define FW_DEPRECATED_KEY(newKey, access, version)
Use this macro when deprecating a service key to warn the developer.
Definition: spyLog.hpp:366
virtual FWGUI_API void setCursor(::fwGui::ICursor::CursorType cursor) override
Set the cursor.
#define OSLM_ASSERT(message, cond)
work like &#39;assert&#39; from &#39;cassert&#39;, with in addition a message logged by spylog (with FATAL loglevel) ...
Definition: spyLog.hpp:310
virtual UIIO_API ~SIOSelector() noexcept
Destructor. Do nothing.
Definition: SIOSelector.cpp:64
virtual FWGUI_API void setMessage(const std::string &msg) override
Set the message.
Defines the generic message box for IHM. Use the Delegate design pattern.
static FWGUI_API IMessageDialog::Buttons showMessageDialog(const std::string &title, const std::string &message,::fwGui::dialog::IMessageDialog::Icons icon=INFO)
UIIO_API void setIOMode(IOMode _mode)
This method allows to configure the service in reader or writer mode (set SIOSelector::m_mode).
IOMode
IOMode enum definition.
Definition: SIOSelector.hpp:79
std::shared_ptr< ::fwJobs::IJob > sptr
Cancel request callback type.
Definition: IJob.hpp:54
#define SLM_WARN(message)
Definition: spyLog.hpp:261
#define SLM_DEBUG(message)
Definition: spyLog.hpp:239
Contains fwAtomsFilter::factory utilities.
FWSERVICES_API void setOutput(const ::fwServices::IService::KeyType &key, const ::fwData::Object::sptr &object, size_t index=0)
Register an output object at a given key in the OSR, replacing it if it already exists.
Definition: IService.cpp:80
virtual FWGUI_API void addButton(IMessageDialog::Buttons button) override
Add a button (OK, YES_NO, YES, NO, CANCEL)
UIIO_API void starting() override
Starts the service. Do nothing.
virtual FWGUI_API IMessageDialog::Buttons show() override
Show the message box and return the clicked button.
#define SLM_ASSERT(message, cond)
work like &#39;assert&#39; from &#39;cassert&#39;, with in addition a message logged by spylog (with FATAL loglevel) ...
Definition: spyLog.hpp:308
UIIO_API void stopping() override
Stops the service. Do nothing.
UIIO_API SIOSelector()
Constructor. Do nothing (Just initialize parameters).
Definition: SIOSelector.cpp:54
Base class for each data object.
static const std::string & classname()
return object&#39;s classname without its namespace, i.e. BaseObject
Definition: SIOSelector.hpp:85
virtual FWGUI_API void setIcon(IMessageDialog::Icons icon) override
Set the icon (CRITICAL, WARNING, INFO or QUESTION)
FWSERVICES_API::fwData::Object::sptr getObject()
Return the object associated to service.
Definition: IService.cpp:101
UIIO_API void updating() override
Create a dialogue box to provide the user different available readers (writer) for the IOSelector ass...
Defines the generic cursor for IHM. Use the Delegate design pattern.
static FWSERVICES_API ServiceFactory::sptr getDefault()
Return the unique Instance, create it if required at first access.
std::shared_ptr< ::fwThread::Worker > m_associatedWorker
Associated worker.
Definition: IService.hpp:699
Defines the service interface managing the editor service which create their own container.
static FWSERVICES_API ServiceConfig::sptr getDefault()
Return the default global instance of ServiceConfig.
UIIO_API void info(std::ostream &_sstream) override
Gives the name of the class. Do nothing.
This service displays a list of available readers or writers and lets you select one to load or save ...
Definition: SIOSelector.hpp:73
UIIO_API void configuring() override
This method initializes class member parameters from configuration elements.
Definition: SIOSelector.cpp:70
virtual FWGUI_API void setTitle(const std::string &title) override
Set the title of the message box.
The namespace uiIO contains a simple service to manipulate IO with IHM..
#define SLM_WARN_IF(message, cond)
Definition: spyLog.hpp:265
virtual FWGUI_API void setDefaultCursor() override
Set the default cursor.
FWSERVICES_API ConfigType getConfigTree() const
Return the configuration, in an boost property tree.
Definition: IService.cpp:247