fw4spl
ioGdcm/src/ioGdcm/SSeriesDBReader.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 "ioGdcm/SSeriesDBReader.hpp"
8 
9 #include <fwCom/Signal.hxx>
10 
11 #include <fwData/location/Folder.hpp>
12 #include <fwData/mt/ObjectWriteLock.hpp>
13 #include <fwData/String.hpp>
14 
15 #include <fwGdcmIO/reader/SeriesDB.hpp>
16 
17 #include <fwGui/Cursor.hpp>
18 #include <fwGui/dialog/LocationDialog.hpp>
19 #include <fwGui/dialog/LoggerDialog.hpp>
20 #include <fwGui/dialog/MessageDialog.hpp>
21 #include <fwGui/dialog/ProgressDialog.hpp>
22 #include <fwGui/dialog/PulseProgressDialog.hpp>
23 
24 #include <fwIO/IReader.hpp>
25 
26 #include <fwJobs/IJob.hpp>
27 #include <fwJobs/Observer.hpp>
28 
29 #include <fwLog/Logger.hpp>
30 
31 #include <fwMedData/SeriesDB.hpp>
32 
33 #include <fwMedDataTools/helper/SeriesDB.hpp>
34 
35 #include <fwServices/macros.hpp>
36 #include <fwServices/op/Add.hpp>
37 #include <fwServices/registry/ServiceConfig.hpp>
38 
39 #include <fwTools/ProgressToLogger.hpp>
40 
41 namespace ioGdcm
42 {
43 
44 fwServicesRegisterMacro( ::fwIO::IReader, ::ioGdcm::SSeriesDBReader, ::fwMedData::SeriesDB );
45 
46 static const ::fwCom::Signals::SignalKeyType JOB_CREATED_SIGNAL = "jobCreated";
47 
48 //------------------------------------------------------------------------------
49 
51  m_showLogDialog(true),
52  m_enableBufferRotation(true),
53  m_dicomDirSupport(USER_SELECTION)
54 {
55  m_sigJobCreated = newSignal<JobCreatedSignal>(JOB_CREATED_SIGNAL);
56 }
57 
58 //------------------------------------------------------------------------------
59 
61 {
62 }
63 
64 //------------------------------------------------------------------------------
65 
67 {
68  return ::fwIO::FOLDER;
69 }
70 
71 //------------------------------------------------------------------------------
72 
74 {
75  static ::boost::filesystem::path _sDefaultPath;
76 
78  dialogFile.setTitle(m_windowTitle.empty() ? this->getSelectorDialogTitle() : m_windowTitle);
79  dialogFile.setDefaultLocation( ::fwData::location::Folder::New(_sDefaultPath) );
80  dialogFile.setOption(::fwGui::dialog::ILocationDialog::READ);
81  dialogFile.setType(::fwGui::dialog::LocationDialog::FOLDER);
82 
83  ::fwData::location::Folder::sptr result;
84  result = ::fwData::location::Folder::dynamicCast( dialogFile.show() );
85  if (result)
86  {
87  _sDefaultPath = result->getFolder();
88  this->setFolder( _sDefaultPath );
89  dialogFile.saveDefaultLocation( ::fwData::location::Folder::New(_sDefaultPath) );
90  }
91  else
92  {
93  this->clearLocations();
94  }
95 
96  // Select filter
97  if(!m_filterConfig.empty())
98  {
99  // Get the config
100  ::fwRuntime::ConfigurationElement::csptr filterSelectorConfig;
101  filterSelectorConfig = ::fwServices::registry::ServiceConfig::getDefault()->getServiceConfig(
102  m_filterConfig, "::ioDicom::SFilterSelectorDialog");
103 
104  SLM_ASSERT("Sorry, there is no service configuration "
105  << m_filterConfig
106  << " for ::ioDicom::SFilterSelectorDialog", filterSelectorConfig);
107 
108  // Init and execute the service
109  ::fwServices::IService::sptr filterSelectorSrv;
110  ::fwData::String::sptr key = ::fwData::String::New();
111  filterSelectorSrv = ::fwServices::add(key,
112  "::fwGui::editor::IDialogEditor",
113  "::ioDicom::SFilterSelectorDialog");
114  filterSelectorSrv->setConfiguration( ::fwRuntime::ConfigurationElement::constCast(filterSelectorConfig) );
115  filterSelectorSrv->configure();
116  filterSelectorSrv->start();
117  filterSelectorSrv->update();
118  filterSelectorSrv->stop();
119  ::fwServices::OSR::unregisterService( filterSelectorSrv );
120 
121  m_filterType = key->getValue();
122  }
123 }
124 
125 //------------------------------------------------------------------------------
126 
128 {
130 
131  const ::fwServices::IService::ConfigType config = this->getConfigTree();
132 
133  // Use filter selector
134  m_filterConfig = config.get<std::string>("filterConfig", "");
135 
136  // Set filter
137  m_filterType = config.get<std::string>("filterConfig", "");
138 
139  // Show log dialog
140  m_showLogDialog = config.get<bool>("showLogDialog", true);
141 
142  // Enable buffer rotation
143  m_enableBufferRotation = config.get<bool>("enableBufferRotation", true);
144 
145  // Enable dicomdir
146  const std::string dicomDirStr = config.get<std::string>("dicomdirSupport", "user_selection");
147  SLM_ASSERT("<dicomdirSupport> value must be 'always' or 'never' or 'user_selection'",
148  dicomDirStr == "always" || dicomDirStr == "never" || dicomDirStr == "user_selection");
149  if(dicomDirStr == "always")
150  {
151  m_dicomDirSupport = ALWAYS;
152  }
153  else if(dicomDirStr == "never")
154  {
155  m_dicomDirSupport = NEVER;
156  }
157  else if(dicomDirStr == "user_selection")
158  {
159  m_dicomDirSupport = USER_SELECTION;
160  }
161 
162  // Get SOP Class selection
163  if(config.count("SOPClassSelection") == 1 )
164  {
165  const auto sopClassSelectionConfig = config.get_child("SOPClassSelection");
166  const auto sopClassRange = sopClassSelectionConfig.equal_range("SOPClass");
167  for(auto sopClassIter = sopClassRange.first; sopClassIter != sopClassRange.second; ++sopClassIter)
168  {
169  const ::fwServices::IService::ConfigType& sopClassConfig = sopClassIter->second;
170  const ::fwServices::IService::ConfigType& sopClassAttr = sopClassConfig.get_child("<xmlattr>");
171 
172  SLM_ASSERT("Missing attribute 'uid' in element '<SOPClass>'", sopClassAttr.count("uid") == 1);
173  m_supportedSOPClassSelection.push_back(sopClassAttr.get<std::string>("uid"));
174  }
175  }
176 }
177 
178 //------------------------------------------------------------------------------
179 
181 {
182  SLM_TRACE_FUNC();
183 }
184 
185 //------------------------------------------------------------------------------
186 
188 {
189  SLM_TRACE_FUNC();
190 }
191 
192 //------------------------------------------------------------------------------
193 
194 void SSeriesDBReader::info(std::ostream& _sstream )
195 {
196  _sstream << "SSeriesDBReader::info";
197 }
198 
199 //------------------------------------------------------------------------------
200 
202 {
203  return "Choose a directory with DICOM images";
204 }
205 
206 //------------------------------------------------------------------------------
207 
208 ::fwMedData::SeriesDB::sptr SSeriesDBReader::createSeriesDB( const ::boost::filesystem::path& dicomDir)
209 {
210  SLM_TRACE_FUNC();
211  ::fwGdcmIO::reader::SeriesDB::sptr reader = ::fwGdcmIO::reader::SeriesDB::New();
212  ::fwMedData::SeriesDB::sptr dummy = ::fwMedData::SeriesDB::New();
213  reader->setObject(dummy);
214  reader->setFolder(dicomDir);
215  reader->setDicomFilterType(m_filterType);
216  reader->setBufferRotationEnabled(m_enableBufferRotation);
217  reader->setSupportedSOPClassContainer(m_supportedSOPClassSelection);
218  auto job = reader->getJob();
219  m_sigJobCreated->emit(job);
220 
221  if(m_dicomDirSupport == USER_SELECTION && reader->isDicomDirAvailable())
222  {
224  messageBox.setTitle("Dicomdir file");
225  messageBox.setMessage( "There is a dicomdir file in the root folder. "
226  "Would you like to use it for the reading process ?" );
227  messageBox.setIcon(::fwGui::dialog::IMessageDialog::QUESTION);
228  messageBox.addButton(::fwGui::dialog::IMessageDialog::YES_NO);
229  ::fwGui::dialog::IMessageDialog::Buttons button = messageBox.show();
230 
231  reader->setDicomdirActivated(button == ::fwGui::dialog::IMessageDialog::YES);
232  }
233  else if(m_dicomDirSupport == ALWAYS)
234  {
235  reader->setDicomdirActivated(true);
236  }
237  else //m_dicomDirSupport == NEVER
238  {
239  reader->setDicomdirActivated(false);
240  }
241 
242  try
243  {
244  reader->read();
245 
246  // Retrieve logger
247  ::fwLog::Logger::sptr logger = reader->getLogger();
248  logger->sort();
249 
250  // Set default cursor
251  ::fwGui::Cursor cursor;
252  cursor.setDefaultCursor();
253 
254  // Display logger dialog if enabled
255  if(m_showLogDialog && !logger->empty())
256  {
257 
258  std::stringstream ss;
259  if(dummy->size() > 1)
260  {
261  ss << "The reading process is over : <b>" << dummy->size() << " series</b> have been found. "
262  "<br>Please verify the log report to be informed of the potential errors.";
263  }
264  else
265  {
266  ss << "The reading process is over : <b>" << dummy->size() << " series</b> has been found. "
267  "<br>Please verify the log report to be informed of the potential errors.";
268  }
269 
270  bool result = false;
271  if(!job->cancelRequested())
272  {
273  result = ::fwGui::dialog::LoggerDialog::showLoggerDialog("Reading process over", ss.str(), logger);
274  }
275 
276  // If the user cancel the reading process we delete the loaded series
277  if(!result || job->cancelRequested())
278  {
279  ::fwMedDataTools::helper::SeriesDB sDBhelper(dummy);
280  sDBhelper.clear();
281  }
282  }
283  }
284  catch (const std::exception& e)
285  {
286  std::stringstream ss;
287  ss << "Warning during loading : " << e.what();
289  "Warning", ss.str(), ::fwGui::dialog::IMessageDialog::WARNING);
290  }
291  catch( ... )
292  {
294  "Warning", "Warning during loading", ::fwGui::dialog::IMessageDialog::WARNING);
295  }
296 
297  return dummy;
298 }
299 
300 //------------------------------------------------------------------------------
301 
303 {
304  SLM_TRACE_FUNC();
305  if( this->hasLocationDefined() )
306  {
307  ::fwMedData::SeriesDB::sptr localSeriesDB = this->createSeriesDB(this->getFolder());
308 
309  if( !localSeriesDB->empty() )
310  {
311  // Retrieve dataStruct associated with this service
312  ::fwMedData::SeriesDB::sptr seriesDB = this->getInOut< ::fwMedData::SeriesDB >(::fwIO::s_DATA_KEY);
313 
314  // Clear SeriesDB and add new series
315  ::fwMedDataTools::helper::SeriesDB sDBhelper(seriesDB);
316  ::fwData::mt::ObjectWriteLock lock(seriesDB);
317  sDBhelper.clear();
318  // Notify removal.
319  sDBhelper.notify();
320  {
321  ::fwData::mt::ObjectWriteLock lock(localSeriesDB);
322  seriesDB->shallowCopy(localSeriesDB);
323  }
324 
325  ::fwMedData::SeriesDB::ContainerType addedSeries = seriesDB->getContainer();
326 
327  auto sig = seriesDB->signal< ::fwMedData::SeriesDB::AddedSeriesSignalType >(
329  sig->asyncEmit(addedSeries);
330  }
331  }
332 }
333 
334 //------------------------------------------------------------------------------
335 
336 } // namespace ioGdcm
virtual IOGDCM_API void starting() override
Override.
virtual IOGDCM_API void configuring() override
Configuring method. This method is used to configure the service.
std::string m_windowTitle
Title of the window that will open when the configureWithIHM slot is called.
Definition: IReader.hpp:207
#define SLM_TRACE_FUNC()
Trace contextual function signature.
Definition: spyLog.hpp:329
IOGDCM_API::fwIO::IOPathType getIOPathType() const override
Return managed file type, here FOLDER.
FWIO_API bool hasLocationDefined() const
Returns if a location has been defined ( by the configuration process or directly by user ) ...
Definition: IReader.cpp:233
virtual FWGUI_API void setMessage(const std::string &msg) override
Set the message.
virtual FWIO_API void configuring() override
This method proposes to parse xml configuration to retrieve file/files/folder paths.
Definition: IReader.cpp:144
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)
virtual IOGDCM_API void stopping() override
Override.
virtual IOGDCM_API void configureWithIHM() override
Override.
virtual FWGUI_API void setDefaultLocation(::fwData::location::ILocation::sptr loc) override
Set the initial location for the dialog.
FWGUI_API::fwGui::dialog::ILocationDialog & setOption(::fwGui::dialog::ILocationDialog::Options option) override
allow to set option to the file dialog mode=READ/WRITE, check=FILE_MUST_EXIST
FWGUI_API::fwData::location::ILocation::sptr show() override
Display the dialog.
A helper to lock object on exclusive mode.
FWIO_APIconst::boost::filesystem::path & getFolder() const
Returns folder path set by the user or set during service configuration.
Definition: IReader.cpp:97
Defines an helper to modify an fwMedData::SeriesDB and create in parallel the message to announce thi...
virtual FWGUI_API void addButton(IMessageDialog::Buttons button) override
Add a button (OK, YES_NO, YES, NO, CANCEL)
FWMEDDATATOOLS_API void clear()
Clear all series in the SeriesDB.
static FWMEDDATA_APIconst::fwCom::Signals::SignalKeyType s_ADDED_SERIES_SIG
Type of signal when series are added.
virtual FWGUI_API IMessageDialog::Buttons show() override
Show the message box and return the clicked button.
Reader service API. It manages extension points definition and extension configuration.
Definition: IReader.hpp:34
#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
Read DICOM (ImageSeries/ModelSeries) with gdcm reader.
virtual IOGDCM_API ~SSeriesDBReader() noexcept override
destructor
virtual FWGUI_API void setIcon(IMessageDialog::Icons icon) override
Set the icon (CRITICAL, WARNING, INFO or QUESTION)
virtual IOGDCM_API std::string getSelectorDialogTitle() override
Override.
IOPathType
IOPathType defines different type of paths used by service readers/writers.
Definition: ioTypes.hpp:19
ioGdcm contains services use to deal with DICOM using the GDCM library.
FWGUI_API void setTitle(const std::string &title) override
Set the title for the dialog.
Defines the generic file/folder selector dialog for IHM.
Defines the generic cursor for IHM. Use the Delegate design pattern.
static FWSERVICES_API ServiceConfig::sptr getDefault()
Return the default global instance of ServiceConfig.
FWIO_API void setFolder(const ::boost::filesystem::path &folder)
Sets folder path.
Definition: IReader.cpp:106
FWGUI_API void setType(::fwGui::dialog::ILocationDialog::Types type) override
Set the type of location for the dialog (SINGLE_FILE, FORLDER, MULTI_FILES)
static FWGUI_API bool showLoggerDialog(const std::string &title, const std::string &message, const ::fwLog::Logger::sptr &logger)
FWIO_API void clearLocations()
Clear any location set by the setFile/setFiles/setFolder setter.
Definition: IReader.cpp:137
FWGUI_API void saveDefaultLocation(::fwData::location::ILocation::sptr loc) override
Save the specified default location for the dialog in preferences (if available)
IOGDCM_API void info(std::ostream &_sstream) override
Override.
virtual FWGUI_API void setTitle(const std::string &title) override
Set the title of the message box.
virtual FWGUI_API void setDefaultCursor() override
Set the default cursor.
IOGDCM_API void updating() override
Override.
FWSERVICES_API ConfigType getConfigTree() const
Return the configuration, in an boost property tree.
Definition: IService.cpp:247
IOGDCM_API SSeriesDBReader() noexcept
constructor