fw4spl
SWriter.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 "ioAtoms/SWriter.hpp"
8 
9 #include "ioAtoms/SReader.hpp"
10 
11 #include <fwAtomConversion/convert.hpp>
12 
13 #include <fwAtomsBoostIO/types.hpp>
14 #include <fwAtomsBoostIO/Writer.hpp>
15 
16 #include <fwAtomsPatch/PatchingManager.hpp>
17 #include <fwAtomsPatch/VersionsGraph.hpp>
18 #include <fwAtomsPatch/VersionsManager.hpp>
19 
20 #include <fwCom/Signal.hxx>
21 
22 #include <fwData/Composite.hpp>
23 #include <fwData/location/Folder.hpp>
24 #include <fwData/location/SingleFile.hpp>
25 
26 #include <fwDataCamp/visitor/RecursiveLock.hpp>
27 
28 #include <fwGui/Cursor.hpp>
29 #include <fwGui/dialog/MessageDialog.hpp>
30 #include <fwGui/dialog/ProgressDialog.hpp>
31 #include <fwGui/dialog/SelectorDialog.hpp>
32 
33 #include <fwJobs/Aggregator.hpp>
34 #include <fwJobs/Job.hpp>
35 
36 #include <fwMDSemanticPatch/PatchLoader.hpp>
37 
38 #include <fwServices/macros.hpp>
39 
40 #include <fwZip/WriteDirArchive.hpp>
41 #include <fwZip/WriteZipArchive.hpp>
42 
43 #include <boost/algorithm/string/join.hpp>
44 #include <boost/assign.hpp>
45 #include <boost/filesystem/path.hpp>
46 
47 #include <regex>
48 
49 namespace ioAtoms
50 {
51 
52 //-----------------------------------------------------------------------------
53 
54 fwServicesRegisterMacro( ::fwIO::IWriter, ::ioAtoms::SWriter, ::fwData::Object );
55 
56 static const ::fwCom::Signals::SignalKeyType JOB_CREATED_SIGNAL = "jobCreated";
57 
58 //-----------------------------------------------------------------------------
59 
61  m_useAtomsPatcher(false),
62  m_exportedVersion("Undefined"),
63  m_context("Undefined"),
64  m_version("Undefined")
65 {
66  m_sigJobCreated = newSignal< JobCreatedSignalType >( JOB_CREATED_SIGNAL );
67 
68  for(SReader::FileExtension2NameType::value_type ext : SReader::s_EXTENSIONS)
69  {
70  m_allowedExts.insert(m_allowedExts.end(), ext.first);
71  }
72 }
73 
74 //-----------------------------------------------------------------------------
75 
77 {
78 }
79 
80 //-----------------------------------------------------------------------------
81 
83 {
84 }
85 
86 //-----------------------------------------------------------------------------
87 
89 {
91 
92  m_customExts.clear();
93  m_allowedExtLabels.clear();
94 
95  const ConfigType config = this->getConfigTree();
96 
97  const auto archiveCfgs = config.equal_range("archive");
98 
99  for (auto it = archiveCfgs.first; it != archiveCfgs.second; ++it)
100  {
101  const std::string backend = it->second.get<std::string>("<xmlattr>.backend");
102  SLM_ASSERT("No backend attribute given in archive tag", backend != "");
103  SLM_ASSERT("Unsupported backend '" + backend + "'",
104  SReader::s_EXTENSIONS.find("." + backend) != SReader::s_EXTENSIONS.end());
105 
106  const auto extCfgs = it->second.equal_range("extension");
107 
108  for (auto itExt = extCfgs.first; itExt != extCfgs.second; ++itExt)
109  {
110  const std::string extension = itExt->second.get<std::string>("");
111  SLM_ASSERT("No extension given for backend '" + backend + "'", !extension.empty());
112  SLM_ASSERT("Extension must begin with '.'", extension[0] == '.');
113 
114  m_customExts[extension] = backend;
115  m_allowedExtLabels[extension] = itExt->second.get("<xmlattr>.label", "");
116  }
117  }
118 
119  const auto extensionsCfg = config.get_child_optional("extensions");
120 
121  if (extensionsCfg)
122  {
123  m_allowedExts.clear();
124 
125  const auto extCfgs = extensionsCfg->equal_range("extension");
126  for (auto it = extCfgs.first; it != extCfgs.second; ++it)
127  {
128  const std::string ext = it->second.get<std::string>("");
129 
130  // The extension must be found either in custom extensions list or in known extensions
131  FileExtension2NameType::const_iterator itKnown = SReader::s_EXTENSIONS.find(ext);
132  FileExtension2NameType::const_iterator itCustom = m_customExts.find(ext);
133 
134  const bool extIsKnown = (itKnown != SReader::s_EXTENSIONS.end() || itCustom != m_customExts.end());
135  SLM_ASSERT("Extension '" + ext + "' is not allowed in configuration", extIsKnown);
136 
137  if(extIsKnown)
138  {
139  m_allowedExts.insert(m_allowedExts.end(), ext);
140  m_allowedExtLabels[ext] = it->second.get("<xmlattr>.label", "");
141  }
142  }
143  }
144  else
145  {
146  m_allowedExts.clear();
147 
148  for(FileExtension2NameType::value_type ext : m_customExts)
149  {
150  m_allowedExts.insert(m_allowedExts.end(), ext.first);
151  }
152 
153  for(SReader::FileExtension2NameType::value_type ext : SReader::s_EXTENSIONS)
154  {
155  m_allowedExts.insert(m_allowedExts.end(), ext.first);
156  m_allowedExtLabels[ext.first] = ext.second;
157  }
158  }
159 
160  const auto patcherCfg = config.get_child_optional("patcher");
161 
162  if (patcherCfg)
163  {
164  m_context = patcherCfg->get<std::string>("<xmlattr>.context", "MedicalData");
165  m_version = patcherCfg->get<std::string>("<xmlattr>.version",
167  m_useAtomsPatcher = true;
168  }
169 }
170 
171 //----------------------------------------------------------------------------
172 
174 {
175  using namespace boost::assign;
176 
177  ::fwAtomsPatch::VersionsGraph::sptr vg = ::fwAtomsPatch::VersionsManager::getDefault()->getGraph(m_context);
178 
179  // have some information about this format
180  if ( vg )
181  {
182  std::vector< std::string > versions = vg->getConnectedVersions(m_version);
183  if ( versions.size() == 0 )
184  {
186  return true;
187  }
188  else
189  {
190  versions.push_back(m_version);
191 
192  std::transform(versions.begin(), versions.end(), versions.begin(), [](const std::string& _version)
193  {
194  static const std::regex ala("ALA");
195  return std::regex_replace(_version, ala, "");
196  } );
197 
198  // Sort versions according to repository/number. This is not really honnest since we should not make any
199  // assumption about the versioning convention, especially for child repositories... But since this is
200  // how things are organized currently I don't think this is such a big issue
201  std::sort(versions.begin(), versions.end(), [](const std::string& _a, const std::string& _b)
202  {
203  try
204  {
205  // Assume a pattern like V[0-9][0-9][A-Z][A-Z][A-Z]
206  // Sort with the version number
207  const std::string repoA = _a.substr(3, _a.size());
208  const std::string repoB = _b.substr(3, _b.size());
209  if(repoA == repoB)
210  {
211  const std::string numA = _a.substr(1, 2);
212  const std::string numB = _b.substr(1, 2);
213  return numA > numB;
214  }
215  return repoA < repoB;
216  }
217  catch ( std::out_of_range e)
218  {
219  OSLM_ERROR("Bad version format: either " + _a + " or " + _b);
220  return false;
221  }
222  });
223 
224  std::vector< std::string > prettyVersionsAll;
225  std::map< std::string, std::string > prettyVersionsToVersions;
226 
227  for(const auto& v : versions)
228  {
229  try
230  {
231  const std::string num = v.substr(0, 3);
232  const std::string repo = v.substr(3, v.size());
233 
234  const std::string prettyVersion = num + ((repo.empty()) ? "" : " (" + repo + ")");
235  prettyVersionsAll.push_back(prettyVersion);
236  prettyVersionsToVersions[ prettyVersion ] = v;
237 
238  }
239  catch ( std::out_of_range e)
240  {
241  OSLM_ERROR("Bad version format: " + v);
242 
243  prettyVersionsAll.push_back(v);
244  prettyVersionsToVersions[ v ] = v;
245  }
246  }
247 
248  // Create a shortened list of versions, with only the latest ones of each repo
249  std::vector< std::string > prettyVersions;
250  prettyVersions.push_back(prettyVersionsAll[0]);
251  for(auto itVersion = prettyVersionsAll.begin() + 1; itVersion != prettyVersionsAll.end(); ++itVersion)
252  {
253  const auto& versionA = *(itVersion - 1);
254  const auto& versionB = *(itVersion);
255  const std::string repoA = versionA.substr(3, versionA.size());
256  const std::string repoB = versionB.substr(3, versionB.size());
257 
258  if(repoA != repoB)
259  {
260  prettyVersions.push_back(versionB);
261  }
262  }
263 
264  ::fwGui::dialog::SelectorDialog dialogVersion;
265 
266  dialogVersion.setTitle("Archive version");
267  dialogVersion.setMessage("Select an archive version");
268 
269  bool selectAmongstAllVersions = false;
270  dialogVersion.addCustomButton("Advanced", [&selectAmongstAllVersions]()
271  {
272  selectAmongstAllVersions = true;
273  });
274 
275  dialogVersion.setSelections(prettyVersions);
276  std::string result = dialogVersion.show();
277  if(selectAmongstAllVersions)
278  {
279  ::fwGui::dialog::SelectorDialog dialogVersionAll;
280 
281  dialogVersionAll.setTitle("Archive version");
282  dialogVersionAll.setMessage("Select an archive version");
283  dialogVersionAll.setSelections(prettyVersionsAll);
284  result = dialogVersionAll.show();
285  }
286  if( !result.empty() )
287  {
288  m_exportedVersion = prettyVersionsToVersions[result];
289  }
290  return !result.empty();
291  }
292  }
293  else
294  {
296  return true;
297  }
298 }
299 
300 //-----------------------------------------------------------------------------
301 
303 {
304  if(!this->hasLocationDefined())
305  {
306  return;
307  }
308 
309  ::fwData::Object::csptr obj = this->getInput< ::fwData::Object >(::fwIO::s_DATA_KEY);
310  if (!obj)
311  {
312  FW_DEPRECATED_KEY(::fwIO::s_DATA_KEY, "inout", "18.0");
313  obj = this->getObject< ::fwData::Object >();
314  }
315 
316  ::fwGui::Cursor cursor;
317  cursor.setCursor(::fwGui::ICursor::BUSY);
318 
319  // Get the selected extension
320  const ::boost::filesystem::path& requestedFilePath = this->getFile();
321  std::string requestedExtension = requestedFilePath.extension().string();
322 
323  if ( !m_selectedExtension.empty()
324  && !requestedExtension.empty()
325  && m_selectedExtension.compare(requestedExtension))
326  {
327  std::string errorMessage("File extension '" + requestedExtension +
328  "' is different from the selected extension '" + m_selectedExtension + "'");
329  ::fwGui::dialog::MessageDialog::showMessageDialog("Medical data writer failed",
330  errorMessage,
331  ::fwGui::dialog::IMessageDialog::CRITICAL);
332  return;
333  }
334 
335  ::boost::filesystem::path filePath = requestedFilePath;
336  if( ::boost::filesystem::exists( requestedFilePath ) )
337  {
338  FW_RAISE_IF( "can't write to : " << requestedFilePath << ", it is a directory.",
339  ::boost::filesystem::is_directory(requestedFilePath)
340  );
341  filePath = ::boost::filesystem::unique_path(filePath);
342  }
343 
344  const ::boost::filesystem::path folderPath = filePath.parent_path();
345  ::boost::filesystem::path filename = filePath.filename();
346  std::string extension = filePath.extension().string();
347 
348  // Check if the extension of the filename is set. If not, assign it to the selected extension.
349  if (extension.empty())
350  {
351  extension = m_selectedExtension;
352  }
353 
354  // Check if the extension set is allowed. If not, assigns to the first allowed extension.
355  if (m_allowedExts.find(extension) == m_allowedExts.end())
356  {
357  std::set< std::string >::const_iterator begin = m_allowedExts.begin();
358  std::string firstAllowedExt = *begin;
359 
360  extension = firstAllowedExt;
361  }
362  FW_RAISE_IF( "Extension is empty", extension.empty() );
363  FW_RAISE_IF("The file extension '" << extension << "' is not managed",
364  m_allowedExts.find(extension) == m_allowedExts.end());
365 
366  // Find in custom extensions if our extension exists.
367  if (m_customExts.find(extension) != m_customExts.end())
368  {
369  extension = "." + m_customExts[extension];
370  }
371 
372  // Mutex data lock
373  ::fwDataCamp::visitor::RecursiveLock recursiveLock(obj);
374 
375  ::fwAtoms::Object::sptr atom;
376  const unsigned int progressBarOffset = 10;
377 
378  // Convert data to atom : job 1
379  ::fwJobs::Job::sptr convertJob = ::fwJobs::Job::New("Writing " + extension + " file",
380  [ =, &atom](::fwJobs::Job& runningJob)
381  {
382  runningJob.doneWork(progressBarOffset);
383 
384  atom = ::fwAtomConversion::convert(::fwData::Object::constCast(obj));
385  runningJob.done();
386  }, m_associatedWorker );
387 
388  // Path atom : job 2
389  ::fwJobs::Job::sptr patchingJob = ::fwJobs::Job::New("Writing " + extension + " file",
390  [ =, &atom](::fwJobs::Job& runningJob)
391  {
392 
393  atom->setMetaInfo("context", m_context);
394  atom->setMetaInfo("version_name", m_version);
395 
396  if(runningJob.cancelRequested())
397  {
398  return;
399  }
400 
401  runningJob.doneWork(progressBarOffset);
402 
403  if( m_useAtomsPatcher )
404  {
405  ::fwAtomsPatch::PatchingManager globalPatcher( atom );
406  atom = globalPatcher.transformTo( m_exportedVersion );
407  }
408 
409  runningJob.done();
410  },
412  );
413 
414  // Writing file : job 3
415  ::fwJobs::Job::sptr writeJob = ::fwJobs::Job::New("Writing " + extension + " file",
416  [ =, &atom](::fwJobs::Job& runningJob)
417  {
418  runningJob.doneWork(progressBarOffset);
419  // Write atom
420  ::fwZip::IWriteArchive::sptr writeArchive;
421  ::fwAtomsBoostIO::FormatType format;
422  ::boost::filesystem::path archiveRootName;
423  if ( extension == ".json" )
424  {
425  writeArchive = ::fwZip::WriteDirArchive::New(folderPath.string());
426  archiveRootName = filename;
427  format = ::fwAtomsBoostIO::JSON;
428  }
429  else if ( extension == ".jsonz" )
430  {
431  if ( ::boost::filesystem::exists( filePath ) )
432  {
433  ::boost::filesystem::remove( filePath );
434  }
435  writeArchive = ::fwZip::WriteZipArchive::New(filePath.string());
436  archiveRootName = "root.json";
437  format = ::fwAtomsBoostIO::JSON;
438  }
439  else if ( extension == ".xml" )
440  {
441  writeArchive = ::fwZip::WriteDirArchive::New(folderPath.string());
442  archiveRootName = filename;
443  format = ::fwAtomsBoostIO::XML;
444  }
445  else if ( extension == ".xmlz" )
446  {
447  if ( ::boost::filesystem::exists( filePath ) )
448  {
449  ::boost::filesystem::remove( filePath );
450  }
451  writeArchive = ::fwZip::WriteZipArchive::New(filePath.string());
452  archiveRootName = "root.xml";
453  format = ::fwAtomsBoostIO::XML;
454  }
455  else
456  {
457  FW_RAISE( "This file extension '" << extension << "' is not managed" );
458  }
459 
460  ::fwAtomsBoostIO::Writer(atom).write( writeArchive, archiveRootName, format );
461  writeArchive.reset();
462 
463  runningJob.done();
464  }, m_associatedWorker );
465 
466  ::fwJobs::Aggregator::sptr jobs = ::fwJobs::Aggregator::New(extension + " writer");
467  jobs->add(convertJob);
468  jobs->add(patchingJob);
469  jobs->add(writeJob);
470  jobs->setCancelable(false);
471 
472  m_sigJobCreated->emit(jobs);
473 
474  try
475  {
476  jobs->run().get();
477  }
478  catch( std::exception& e )
479  {
480  OSLM_ERROR( e.what() );
481  ::fwGui::dialog::MessageDialog::showMessageDialog("Medical data writer failed",
482  e.what(),
483  ::fwGui::dialog::IMessageDialog::CRITICAL);
484  }
485  catch( ... )
486  {
487  ::fwGui::dialog::MessageDialog::showMessageDialog("Medical data writer failed",
488  "Writing process aborted",
489  ::fwGui::dialog::IMessageDialog::CRITICAL);
490  }
491 
492  cursor.setDefaultCursor();
493 }
494 
495 //-----------------------------------------------------------------------------
496 
498 {
499  return ::fwIO::FILE;
500 }
501 
502 //-----------------------------------------------------------------------------
503 
505 {
506  static ::boost::filesystem::path _sDefaultPath;
507 
509  {
511  dialogFile.setTitle(m_windowTitle.empty() ? "Enter file name" : m_windowTitle);
512  dialogFile.setDefaultLocation( ::fwData::location::Folder::New(_sDefaultPath) );
513  dialogFile.setOption(::fwGui::dialog::ILocationDialog::WRITE);
514  dialogFile.setType(::fwGui::dialog::LocationDialog::SINGLE_FILE);
515 
516  dialogFile.addFilter("Medical data", "*" + ::boost::algorithm::join(m_allowedExts, " *"));
517 
518  for(const std::string& ext : m_allowedExts)
519  {
520  dialogFile.addFilter(m_allowedExtLabels[ext], "*" + ext);
521  }
522 
523  ::fwData::location::SingleFile::sptr result
524  = ::fwData::location::SingleFile::dynamicCast( dialogFile.show() );
525 
526  if (result)
527  {
528  _sDefaultPath = result->getPath();
529  this->setFile( _sDefaultPath );
530  dialogFile.saveDefaultLocation( ::fwData::location::Folder::New(_sDefaultPath.parent_path()) );
532  }
533  else
534  {
535  this->clearLocations();
536  }
537 
538  }
539 
540 }
541 
542 //-----------------------------------------------------------------------------
543 
544 } // namespace ioAtoms
IOATOMS_API void configuring() override
Parse the configuration.
Definition: SWriter.cpp:88
#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.
FWATOMSPATCH_API::fwAtoms::Object::sptr transformTo(const std::string &newVersion)
Transforms the object to the given version.
JobCreatedSignalType::sptr m_sigJobCreated
Signal emitted when job created.
Definition: SWriter.hpp:150
IOATOMS_API void starting() override
Does nothing.
Definition: SWriter.cpp:76
virtual FWGUI_API void setSelections(std::vector< std::string > _selections) override
Set the string list that can be chosen by the selector.
virtual FWGUI_API void setMessage(const std::string &msg) override
Set the message.
IOATOMS_API::fwIO::IOPathType getIOPathType() const override
Returns managed path type, here service manages only single file.
Definition: SWriter.cpp:497
FWJOBS_API void doneWork(std::uint64_t units)
Setter on done work units.
Definition: IJob.cpp:379
static FWGUI_API IMessageDialog::Buttons showMessageDialog(const std::string &title, const std::string &message,::fwGui::dialog::IMessageDialog::Icons icon=INFO)
FWGUI_API void setTitle(std::string title) override
Sets the selector title.
FileExtension2NameType m_customExts
Maps custom extensions to known format.
Definition: SWriter.hpp:144
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.
IOATOMS_API void stopping() override
Does nothing.
Definition: SWriter.cpp:82
std::string m_context
Defines context of data.
Definition: SWriter.hpp:131
FWGUI_API void addFilter(const std::string &filterName, const std::string &wildcardList) override
specify some filtering when browsing files:
SelectorDialog allows the choice of an element among several (_selections) Use the Delegate design pa...
std::shared_ptr< ::fwJobs::Aggregator > sptr
Aggregator container type.
Definition: Aggregator.hpp:39
FWJOBS_API const bool & cancelRequested() const
Returns the job canceling status.
Definition: IJob.cpp:52
This class encapsulate a task that will report it&#39;s progression The embeded task will be run at most ...
Definition: Job.hpp:30
FileExtension2NameType m_allowedExtLabels
Labels shown in file dialog for each allowed extension.
Definition: SWriter.hpp:147
static FWMDSEMANTICPATCH_API std::string getCurrentVersion()
Returns current MedicalData version.
FWIO_API void setFile(const ::boost::filesystem::path &file)
Sets file path.
Definition: IWriter.cpp:49
FWGUI_API std::string show() override
Show the selector and return the selection.
#define OSLM_ERROR(message)
Definition: spyLog.hpp:274
bool m_useAtomsPatcher
To activate atom patcher.
Definition: SWriter.hpp:125
virtual FWGUI_API void addCustomButton(const std::string &label, std::function< void()> clickedFn) override
Add a custom button to this dialog.
virtual FWIO_API void configuring() override
This method proposes to parse xml configuration to retrieve file/files/folder paths.
Definition: IWriter.cpp:122
FWIO_APIconst::boost::filesystem::path & getFile() const
Returns the file path set by the user or set during service configuration.
Definition: IWriter.cpp:40
IOATOMS_API SWriter()
Does nothing.
Definition: SWriter.cpp:60
std::string m_version
Current version of format.
Definition: SWriter.hpp:134
FWIO_API void clearLocations()
Clear any location set by the setFile/setFiles/setFolder setter.
Definition: IWriter.cpp:115
#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
Manages object patching.
static const FileExtension2NameType s_EXTENSIONS
Managed file extensions.
Definition: SReader.hpp:114
This class is an helper to lock an object and all its children recursively.
Base class for each data object.
IOATOMS_API void updating() override
Convert fwData to fwAtoms, and apply the writer chosen from file extension.
Definition: SWriter.cpp:302
IOPathType
IOPathType defines different type of paths used by service readers/writers.
Definition: ioTypes.hpp:19
std::set< std::string > m_allowedExts
Allowed file extensions.
Definition: SWriter.hpp:141
bool versionSelection()
Definition: SWriter.cpp:173
static std::shared_ptr< VersionsManager > getDefault()
Returns the default instance of VersionsManager.
static FWJOBS_API sptr New(const std::string &name, Task task, const std::shared_ptr< ::fwThread::Worker > &worker=nullptr)
Construct a new job and return a smart pointer of it.
Definition: Job.cpp:25
Writer service API. It manages extension points definition and extension configuration.
Definition: IWriter.hpp:33
FWGUI_API void setTitle(const std::string &title) override
Set the title for the dialog.
Defines the generic file/folder selector dialog for IHM.
FWGUI_API std::string getCurrentSelection() const override
Gets the current extension file selection.
Defines the generic cursor for IHM. Use the Delegate design pattern.
std::shared_ptr< ::fwThread::Worker > m_associatedWorker
Associated worker.
Definition: IService.hpp:699
std::string m_selectedExtension
Extension selected in file dialog.
Definition: SWriter.hpp:153
FWJOBS_API void done()
Set done work units to total work units.
Definition: IJob.cpp:476
Contains services to read and write data via atom conversion.
IOATOMS_API void configureWithIHM() override
Propose to create a medical data file.
Definition: SWriter.cpp:504
FWGUI_API void setType(::fwGui::dialog::ILocationDialog::Types type) override
Set the type of location for the dialog (SINGLE_FILE, FORLDER, MULTI_FILES)
FWGUI_API void saveDefaultLocation(::fwData::location::ILocation::sptr loc) override
Save the specified default location for the dialog in preferences (if available)
static FWJOBS_API sptr New(const std::string &name="")
Create a new Aggregator smart pointer.
Definition: Aggregator.cpp:24
std::shared_ptr< ::fwJobs::Job > sptr
Task type.
Definition: Job.hpp:36
FWIO_API bool hasLocationDefined() const
Returns if a location has been defined ( by the configuration process or directly by user ) ...
Definition: IWriter.cpp:184
Atoms writer. Service to write an fwData medical data converted in fwAtoms.
Definition: SWriter.hpp:80
std::string m_exportedVersion
Selected exported version of atom.
Definition: SWriter.hpp:128
std::string m_windowTitle
Title of the window that will open when the configureWithIHM slot is called.
Definition: IWriter.hpp:171
FWSERVICES_API ConfigType getConfigTree() const
Return the configuration, in an boost property tree.
Definition: IService.cpp:247