SWriter.cpp 15.2 KB
Newer Older
1
/* ***** BEGIN LICENSE BLOCK *****
2
 * FW4SPL - Copyright (C) IRCAD, 2009-2017.
3
4
5
6
 * Distributed under the terms of the GNU Lesser General Public License (LGPL) as
 * published by the Free Software Foundation.
 * ****** END LICENSE BLOCK ****** */

7
#include "ioAtoms/SWriter.hpp"
8

9
#include "ioAtoms/SReader.hpp"
10
11
12

#include <fwAtomConversion/convert.hpp>

13
#include <fwAtomsBoostIO/types.hpp>
14
#include <fwAtomsBoostIO/Writer.hpp>
15
16
17
18
19

#include <fwAtomsPatch/PatchingManager.hpp>
#include <fwAtomsPatch/VersionsGraph.hpp>
#include <fwAtomsPatch/VersionsManager.hpp>

20
21
#include <fwCom/Signal.hxx>

22
23
#include <fwData/Composite.hpp>
#include <fwData/location/Folder.hpp>
24
25
26
#include <fwData/location/SingleFile.hpp>

#include <fwDataCamp/visitor/RecursiveLock.hpp>
27
28
29

#include <fwGui/Cursor.hpp>
#include <fwGui/dialog/MessageDialog.hpp>
30
#include <fwGui/dialog/ProgressDialog.hpp>
31
#include <fwGui/dialog/SelectorDialog.hpp>
32
33
34

#include <fwJobs/Aggregator.hpp>
#include <fwJobs/Job.hpp>
35
36
37
38
39
40

#include <fwServices/macros.hpp>

#include <fwZip/WriteDirArchive.hpp>
#include <fwZip/WriteZipArchive.hpp>

41
#include <boost/algorithm/string/join.hpp>
42
43
#include <boost/assign.hpp>
#include <boost/filesystem/path.hpp>
44
45
46
47
48
49

namespace ioAtoms
{

//-----------------------------------------------------------------------------

julien.waechter's avatar
julien.waechter committed
50
fwServicesRegisterMacro( ::io::IWriter, ::ioAtoms::SWriter, ::fwData::Object );
51

52
53
static const ::fwCom::Signals::SignalKeyType JOB_CREATED_SIGNAL = "jobCreated";

54
55
//-----------------------------------------------------------------------------

56
SWriter::SWriter() :
julien.waechter's avatar
julien.waechter committed
57
    m_useAtomsPatcher(false),
58
59
60
    m_exportedVersion("Undefined"),
    m_context("Undefined"),
    m_version("Undefined")
61
{
62
63
    m_sigJobCreated = newSignal< JobCreatedSignalType >( JOB_CREATED_SIGNAL );

64
    for(SReader::FileExtension2NameType::value_type ext :  SReader::s_EXTENSIONS)
65
66
67
68
    {
        m_allowedExts.insert(m_allowedExts.end(), ext.first);
    }
}
69
70
71

//-----------------------------------------------------------------------------

72
void SWriter::starting() throw(::fwTools::Failed)
julien.waechter's avatar
julien.waechter committed
73
74
{
}
75
76
77
78

//-----------------------------------------------------------------------------

void SWriter::stopping() throw(::fwTools::Failed)
julien.waechter's avatar
julien.waechter committed
79
80
{
}
81
82
83

//-----------------------------------------------------------------------------

84
85
86
87
void SWriter::configuring() throw(::fwTools::Failed)
{
    ::io::IWriter::configuring();

julien.waechter's avatar
julien.waechter committed
88
    typedef SPTR (::fwRuntime::ConfigurationElement) ConfigurationElement;
89
90
    typedef std::vector < ConfigurationElement >    ConfigurationElementContainer;

91
92
93
94
    m_customExts.clear();
    m_allowedExtLabels.clear();

    ConfigurationElementContainer customExtsList = m_configuration->find("archive");
95
    for(ConfigurationElement archive :  customExtsList)
96
97
98
99
    {
        const std::string& backend = archive->getAttributeValue("backend");
        SLM_ASSERT("No backend attribute given in archive tag", backend != "");
        SLM_ASSERT("Unsupported backend '" + backend + "'",
julien.waechter's avatar
julien.waechter committed
100
                   SReader::s_EXTENSIONS.find("." + backend) != SReader::s_EXTENSIONS.end());
101
102

        ConfigurationElementContainer exts = archive->find("extension");
103
        for(ConfigurationElement ext :  exts)
104
105
106
107
108
        {
            const std::string& extension = ext->getValue();
            SLM_ASSERT("No extension given for backend '" + backend + "'", !extension.empty());
            SLM_ASSERT("Extension must begin with '.'", extension[0] == '.');

julien.waechter's avatar
julien.waechter committed
109
            m_customExts[extension]       = backend;
110
111
112
113
            m_allowedExtLabels[extension] = ext->getAttributeValue("label");
        }
    }

114
115
116
117
118
    ConfigurationElementContainer extensionsList = m_configuration->find("extensions");
    SLM_ASSERT("The <extensions> element can be set at most once.", extensionsList.size() <= 1);

    if(extensionsList.size() == 1)
    {
119
120
        m_allowedExts.clear();

121
        ConfigurationElementContainer extensions = extensionsList.at(0)->find("extension");
122
        for(ConfigurationElement extension :  extensions)
123
124
125
        {
            const std::string& ext = extension->getValue();

126
            // The extension must be found either in custom extensions list or in known extensions
julien.waechter's avatar
julien.waechter committed
127
            FileExtension2NameType::const_iterator itKnown  = SReader::s_EXTENSIONS.find(ext);
128
129
130
131
            FileExtension2NameType::const_iterator itCustom = m_customExts.find(ext);

            const bool extIsKnown = (itKnown != SReader::s_EXTENSIONS.end() || itCustom != m_customExts.end());
            OSLM_ASSERT("Extension '" << ext << "' is not allowed in configuration", extIsKnown);
132

133
            if(extIsKnown)
134
135
            {
                m_allowedExts.insert(m_allowedExts.end(), ext);
136
                m_allowedExtLabels[ext] = extension->getAttributeValue("label");
137
138
139
            }
        }
    }
140
141
142
143
    else
    {
        m_allowedExts.clear();

144
        for(FileExtension2NameType::value_type ext :  m_customExts)
145
146
147
148
        {
            m_allowedExts.insert(m_allowedExts.end(), ext.first);
        }

149
        for(SReader::FileExtension2NameType::value_type ext :  SReader::s_EXTENSIONS)
150
151
152
153
154
        {
            m_allowedExts.insert(m_allowedExts.end(), ext.first);
            m_allowedExtLabels[ext.first] = ext.second;
        }
    }
155
156
157
158
159

    ConfigurationElementContainer patcher = m_configuration->find("patcher");
    SLM_ASSERT("The <patcher> element can be set at most once.", patcher.size() <= 1 );
    if (patcher.size() == 1)
    {
julien.waechter's avatar
julien.waechter committed
160
161
        m_context         = patcher.at(0)->getExistingAttributeValue("context");
        m_version         = patcher.at(0)->getExistingAttributeValue("version");
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
        m_exportedVersion = m_version;
        m_useAtomsPatcher = true;
    }
}

//----------------------------------------------------------------------------

bool SWriter::versionSelection()
{
    using namespace boost::assign;

    ::fwAtomsPatch::VersionsGraph::sptr vg = ::fwAtomsPatch::VersionsManager::getDefault()->getGraph(m_context);

    // have some information about this format
    if ( vg )
    {
        std::vector< std::string > versions = vg->getConnectedVersions(m_version);
        if ( versions.size() == 0 )
        {
            m_exportedVersion = m_version;
            return true;
        }
        else
        {
            versions.push_back(m_version);
            ::fwGui::dialog::SelectorDialog dialogVersion;

            dialogVersion.setTitle("Archive version");
            dialogVersion.setMessage("Select an archive version");

            dialogVersion.setSelections(versions);
            std::string result = dialogVersion.show();
julien.waechter's avatar
julien.waechter committed
194
            if ( !result.empty() )
195
196
197
            {
                m_exportedVersion = result;
            }
julien.waechter's avatar
julien.waechter committed
198
            return !result.empty();
199
200
201
202
203
204
205
206
207
208
209
        }
    }
    else
    {
        m_exportedVersion = m_version;
        return true;
    }
}

//-----------------------------------------------------------------------------

210
211
void SWriter::updating() throw(::fwTools::Failed)
{
212
    if(!this->hasLocationDefined())
213
    {
214
215
        return;
    }
216

217
    ::fwData::Object::sptr obj = this->getObject< ::fwData::Object >();
218

219
220
    ::fwGui::Cursor cursor;
    cursor.setCursor(::fwGui::ICursor::BUSY);
221

222
    // Get the selected extension
223
    const ::boost::filesystem::path& requestedFilePath = this->getFile();
224
225
226
227
228
229
230
231
232
233
234
235
236
    std::string requestedExtension                     = requestedFilePath.extension().string();

    if ( !m_selectedExtension.empty()
         && !requestedExtension.empty()
         && m_selectedExtension.compare(requestedExtension))
    {
        std::string errorMessage("File extension '" + requestedExtension +
                                 "' is different from the selected extension '" + m_selectedExtension + "'");
        ::fwGui::dialog::MessageDialog::showMessageDialog("Medical data writer failed",
                                                          errorMessage,
                                                          ::fwGui::dialog::IMessageDialog::CRITICAL);
        return;
    }
237

238
    ::boost::filesystem::path filePath = requestedFilePath;
239
240
241
242
243
244
245
    if( ::boost::filesystem::exists( requestedFilePath ) )
    {
        FW_RAISE_IF( "can't write to : " << requestedFilePath << ", it is a directory.",
                     ::boost::filesystem::is_directory(requestedFilePath)
                     );
        filePath = ::boost::filesystem::unique_path(filePath);
    }
246

247
    const ::boost::filesystem::path folderPath = filePath.parent_path();
248
249
250
251
252
253
254
255
256
257
258
259
260
261
    ::boost::filesystem::path filename = filePath.filename();
    std::string extension = filePath.extension().string();

    // Check if the extension of the filename is set. If not, assign it to the selected extension.
    if (extension.empty())
    {
        extension = m_selectedExtension;
    }

    // Check if the extension set is allowed. If not, assigns to the first allowed extension.
    if (m_allowedExts.find(extension) == m_allowedExts.end())
    {
        std::set< std::string >::const_iterator begin = m_allowedExts.begin();
        std::string firstAllowedExt                   = *begin;
262

263
264
265
        extension = firstAllowedExt;
    }
    FW_RAISE_IF( "Extension is empty", extension.empty() );
266
267
    FW_RAISE_IF("The file extension '" << extension << "' is not managed",
                m_allowedExts.find(extension) == m_allowedExts.end());
268
269
270
271
272
273

    // Find in custom extensions if our extension exists.
    if (m_customExts.find(extension) != m_customExts.end())
    {
        extension = "." + m_customExts[extension];
    }
274
275

    // Mutex data lock
276
    ::fwDataCamp::visitor::RecursiveLock recursiveLock(obj);
277
278
279
280
281
282
283
284
285

    ::fwAtoms::Object::sptr atom;
    const unsigned int progressBarOffset = 10;

    // Convert data to atom : job 1
    ::fwJobs::Job::sptr convertJob = ::fwJobs::Job::New("Writing " + extension + " file",
                                                        [ =, &atom](::fwJobs::Job& runningJob)
        {
            runningJob.doneWork(progressBarOffset);
286

287
288
289
290
291
292
293
294
            atom = ::fwAtomConversion::convert(obj);
            runningJob.done();
        }, m_associatedWorker );

    // Path atom : job 2
    ::fwJobs::Job::sptr patchingJob = ::fwJobs::Job::New("Writing " + extension + " file",
                                                         [ =, &atom](::fwJobs::Job& runningJob)
        {
295
296
297

            atom->setMetaInfo("context", m_context);
            atom->setMetaInfo("version_name", m_version);
298
299
300
301
302
303
304
305

            if(runningJob.cancelRequested())
            {
                return;
            }

            runningJob.doneWork(progressBarOffset);

306
307
308
309
310
            if( m_useAtomsPatcher )
            {
                ::fwAtomsPatch::PatchingManager globalPatcher( atom );
                atom = globalPatcher.transformTo( m_exportedVersion );
            }
311

312
313
314
315
            runningJob.done();
        },
                                                         m_associatedWorker
                                                         );
316

317
318
319
320
321
    // Writing file : job 3
    ::fwJobs::Job::sptr writeJob = ::fwJobs::Job::New("Writing " + extension + " file",
                                                      [ =, &atom](::fwJobs::Job& runningJob)
        {
            runningJob.doneWork(progressBarOffset);
322
323
324
325
326
            // Write atom
            ::fwZip::IWriteArchive::sptr writeArchive;
            ::fwAtomsBoostIO::FormatType format;
            ::boost::filesystem::path archiveRootName;
            if ( extension == ".json" )
327
            {
328
                writeArchive = ::fwZip::WriteDirArchive::New(folderPath.string());
329
                archiveRootName = filename;
330
                format = ::fwAtomsBoostIO::JSON;
331
            }
332
            else if ( extension == ".jsonz" )
333
            {
334
                if ( ::boost::filesystem::exists( filePath ) )
335
                {
336
                    ::boost::filesystem::remove( filePath );
337
                }
338
                writeArchive = ::fwZip::WriteZipArchive::New(filePath.string());
339
                archiveRootName = "root.json";
340
                format = ::fwAtomsBoostIO::JSON;
341
342
343
            }
            else if ( extension == ".xml" )
            {
344
                writeArchive = ::fwZip::WriteDirArchive::New(folderPath.string());
345
                archiveRootName = filename;
346
                format = ::fwAtomsBoostIO::XML;
347
348
349
350
            }
            else if ( extension == ".xmlz" )
            {
                if ( ::boost::filesystem::exists( filePath ) )
351
                {
352
                    ::boost::filesystem::remove( filePath );
353
                }
354
                writeArchive = ::fwZip::WriteZipArchive::New(filePath.string());
355
                archiveRootName = "root.xml";
356
                format = ::fwAtomsBoostIO::XML;
357
            }
358
359
360
361
362
363
364
            else
            {
                FW_RAISE( "This file extension '" << extension << "' is not managed" );
            }

            ::fwAtomsBoostIO::Writer(atom).write( writeArchive, archiveRootName, format );
            writeArchive.reset();
365

366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
            runningJob.done();
        }, m_associatedWorker );

    ::fwJobs::Aggregator::sptr jobs = ::fwJobs::Aggregator::New(extension + " writer");
    jobs->add(convertJob);
    jobs->add(patchingJob);
    jobs->add(writeJob);
    jobs->setCancelable(false);

    m_sigJobCreated->emit(jobs);

    try
    {
        jobs->run().get();
    }
381
    catch( std::exception& e )
382
383
384
385
386
    {
        OSLM_ERROR( e.what() );
        ::fwGui::dialog::MessageDialog::showMessageDialog("Medical data writer failed",
                                                          e.what(),
                                                          ::fwGui::dialog::IMessageDialog::CRITICAL);
387
    }
388
389
390
391
392
393
394
395
    catch( ... )
    {
        ::fwGui::dialog::MessageDialog::showMessageDialog("Medical data writer failed",
                                                          "Writing process aborted",
                                                          ::fwGui::dialog::IMessageDialog::CRITICAL);
    }

    cursor.setDefaultCursor();
396
397
398
399
400
401
402
403
404
405
406
407
408
}

//-----------------------------------------------------------------------------

::io::IOPathType SWriter::getIOPathType() const
{
    return ::io::FILE;
}

//-----------------------------------------------------------------------------

void SWriter::configureWithIHM()
{
409
410
    static ::boost::filesystem::path _sDefaultPath;

julien.waechter's avatar
julien.waechter committed
411
    if( !m_useAtomsPatcher || versionSelection() )
412
413
    {
        ::fwGui::dialog::LocationDialog dialogFile;
414
        dialogFile.setTitle(m_windowTitle.empty() ? "Enter file name" : m_windowTitle);
415
416
417
418
        dialogFile.setDefaultLocation( ::fwData::location::Folder::New(_sDefaultPath) );
        dialogFile.setOption(::fwGui::dialog::ILocationDialog::WRITE);
        dialogFile.setType(::fwGui::dialog::LocationDialog::SINGLE_FILE);

419
        dialogFile.addFilter("Medical data", "*" + ::boost::algorithm::join(m_allowedExts, " *"));
420

421
        for(const std::string& ext :  m_allowedExts)
422
423
        {
            dialogFile.addFilter(m_allowedExtLabels[ext], "*" + ext);
424
425
426
427
428
429
430
431
432
433
        }

        ::fwData::location::SingleFile::sptr result
            = ::fwData::location::SingleFile::dynamicCast( dialogFile.show() );

        if (result)
        {
            _sDefaultPath = result->getPath();
            this->setFile( _sDefaultPath );
            dialogFile.saveDefaultLocation( ::fwData::location::Folder::New(_sDefaultPath.parent_path()) );
434
            m_selectedExtension = dialogFile.getCurrentSelection();
435
436
437
438
439
440
441
        }
        else
        {
            this->clearLocations();
        }

    }
442

443
444
445
446
447
448
}

//-----------------------------------------------------------------------------

} // namespace ioAtoms