Medical Imaging Interaction Toolkit  2018.4.99-12ad79a3
Medical Imaging Interaction Toolkit
mitkFileWriterSelector.cpp
Go to the documentation of this file.
1 /*============================================================================
2 
3 The Medical Imaging Interaction Toolkit (MITK)
4 
5 Copyright (c) German Cancer Research Center (DKFZ)
6 All rights reserved.
7 
8 Use of this source code is governed by a 3-clause BSD license that can be
9 found in the LICENSE file.
10 
11 ============================================================================*/
12 
13 #include "mitkFileWriterSelector.h"
14 
15 #include <mitkBaseData.h>
16 #include <mitkCoreServices.h>
17 #include <mitkFileWriterRegistry.h>
18 #include <mitkIMimeTypeProvider.h>
19 
20 #include <usAny.h>
21 #include <usServiceProperties.h>
22 #include <usServiceReference.h>
23 
24 #include <itksys/SystemTools.hxx>
25 
26 #include <iterator>
27 #include <limits>
28 #include <set>
29 
30 namespace mitk
31 {
32  struct FileWriterSelector::Item::Impl : us::SharedData
33  {
34  Impl() : m_FileWriter(nullptr), m_ConfidenceLevel(IFileWriter::Unsupported), m_BaseDataIndex(0), m_Id(-1) {}
35  us::ServiceReference<IFileWriter> m_FileWriterRef;
36  IFileWriter *m_FileWriter;
37  IFileWriter::ConfidenceLevel m_ConfidenceLevel;
38  std::size_t m_BaseDataIndex;
39  MimeType m_MimeType;
40  long m_Id;
41  };
42 
43  struct FileWriterSelector::Impl : us::SharedData
44  {
45  Impl() : m_BestId(-1), m_SelectedId(m_BestId) {}
46  Impl(const Impl &other) : us::SharedData(other), m_BestId(-1), m_SelectedId(m_BestId) {}
47  FileWriterRegistry m_WriterRegistry;
48  std::map<long, FileWriterSelector::Item> m_Items;
49  std::set<MimeType> m_MimeTypes;
50  long m_BestId;
51  long m_SelectedId;
52  };
53 
54  FileWriterSelector::FileWriterSelector(const FileWriterSelector &other) : m_Data(other.m_Data) {}
55  FileWriterSelector::FileWriterSelector(const BaseData *baseData, const std::string &mimeType, const std::string &path)
56  : m_Data(new Impl)
57  {
59 
60  std::vector<FileWriterRegistry::WriterReference> refs;
61 
62  std::string destMimeType = mimeType;
63  if (destMimeType.empty() && !path.empty())
64  {
65  // try to derive a mime-type from the file
66  std::vector<MimeType> mimeTypes = mimeTypeProvider->GetMimeTypesForFile(path);
67  if (!mimeTypes.empty())
68  {
69  for (unsigned int index = 0; index < mimeTypes.size(); index++)
70  {
71  std::vector<FileWriterRegistry::WriterReference> tempRefs =
72  m_Data->m_WriterRegistry.GetReferences(baseData, mimeTypes.at(index).GetName());
73  for (unsigned int innerIndex = 0; innerIndex < tempRefs.size(); innerIndex++)
74  {
75  refs.push_back(tempRefs.at(innerIndex));
76  }
77  }
78  }
79  else if (!itksys::SystemTools::GetFilenameExtension(path).empty())
80  {
81  // If there are no suitable mime-type for the file AND an extension
82  // was supplied, we stop here.
83  return;
84  }
85  else
86  {
87  refs = m_Data->m_WriterRegistry.GetReferences(baseData, destMimeType);
88  }
89  }
90  else
91  {
92  refs = m_Data->m_WriterRegistry.GetReferences(baseData, destMimeType);
93  }
94 
95  std::vector<std::string> classHierarchy = baseData->GetClassHierarchy();
96 
97  // Get all writers and their mime types for the given base data type
98  Item bestItem;
99  for (std::vector<FileWriterRegistry::WriterReference>::const_iterator iter = refs.begin(), iterEnd = refs.end();
100  iter != iterEnd;
101  ++iter)
102  {
103  std::string mimeTypeName = iter->GetProperty(IFileWriter::PROP_MIMETYPE()).ToString();
104  if (!mimeTypeName.empty())
105  {
106  MimeType mimeType = mimeTypeProvider->GetMimeTypeForName(mimeTypeName);
107  if (mimeType.IsValid())
108  {
109  // There is a registered mime-type for this writer. Now get the confidence level
110  // of this writer for writing the given base data object.
111 
112  IFileWriter *writer = m_Data->m_WriterRegistry.GetWriter(*iter);
113  if (writer == nullptr)
114  continue;
115  try
116  {
117  writer->SetInput(baseData);
118  IFileWriter::ConfidenceLevel confidenceLevel = writer->GetConfidenceLevel();
119  if (confidenceLevel == IFileWriter::Unsupported)
120  {
121  continue;
122  }
123 
124  std::string baseDataType = iter->GetProperty(IFileWriter::PROP_BASEDATA_TYPE()).ToString();
125  auto idxIter =
126  std::find(classHierarchy.begin(), classHierarchy.end(), baseDataType);
127  std::size_t baseDataIndex = std::numeric_limits<std::size_t>::max();
128  if (idxIter != classHierarchy.end())
129  {
130  baseDataIndex = std::distance(classHierarchy.begin(), idxIter);
131  }
132 
133  Item item;
134  item.d->m_FileWriterRef = *iter;
135  item.d->m_FileWriter = writer;
136  item.d->m_ConfidenceLevel = confidenceLevel;
137  item.d->m_BaseDataIndex = baseDataIndex;
138  item.d->m_MimeType = mimeType;
139  item.d->m_Id = us::any_cast<long>(iter->GetProperty(us::ServiceConstants::SERVICE_ID()));
140  m_Data->m_Items.insert(std::make_pair(item.d->m_Id, item));
141  m_Data->m_MimeTypes.insert(mimeType);
142  if (!bestItem.GetReference() || bestItem < item)
143  {
144  bestItem = item;
145  }
146  }
147  catch (const us::BadAnyCastException &e)
148  {
149  MITK_WARN << "Unexpected: " << e.what();
150  }
151  catch (const std::exception &e)
152  {
153  // Log the error but continue
154  MITK_WARN << "IFileWriter::GetConfidenceLevel exception: " << e.what();
155  }
156  }
157  }
158  }
159 
160  if (bestItem.GetReference())
161  {
162  m_Data->m_BestId = bestItem.GetServiceId();
163  m_Data->m_SelectedId = m_Data->m_BestId;
164  }
165  }
166 
169  {
170  m_Data = other.m_Data;
171  return *this;
172  }
173 
174  bool FileWriterSelector::IsEmpty() const { return m_Data->m_Items.empty(); }
175  std::vector<FileWriterSelector::Item> FileWriterSelector::Get(const std::string &mimeType) const
176  {
177  std::vector<Item> result;
178  for (std::map<long, Item>::const_iterator iter = m_Data->m_Items.begin(), iterEnd = m_Data->m_Items.end();
179  iter != iterEnd;
180  ++iter)
181  {
182  if (mimeType.empty() || iter->second.GetMimeType().GetName() == mimeType)
183  {
184  result.push_back(iter->second);
185  }
186  }
187  std::sort(result.begin(), result.end());
188  return result;
189  }
190 
191  std::vector<FileWriterSelector::Item> FileWriterSelector::Get() const
192  {
193  return Get(this->GetSelected().d->m_MimeType.GetName());
194  }
195 
197  {
198  std::map<long, Item>::const_iterator iter = m_Data->m_Items.find(id);
199  if (iter != m_Data->m_Items.end())
200  {
201  return iter->second;
202  }
203  return Item();
204  }
205 
206  FileWriterSelector::Item FileWriterSelector::GetDefault() const { return Get(m_Data->m_BestId); }
207  long FileWriterSelector::GetDefaultId() const { return m_Data->m_BestId; }
208  FileWriterSelector::Item FileWriterSelector::GetSelected() const { return Get(m_Data->m_SelectedId); }
209  long FileWriterSelector::GetSelectedId() const { return m_Data->m_SelectedId; }
210  bool FileWriterSelector::Select(const std::string &mimeType)
211  {
212  std::vector<Item> items = Get(mimeType);
213  if (items.empty())
214  return false;
215  return Select(items.back());
216  }
217 
218  bool FileWriterSelector::Select(const FileWriterSelector::Item &item) { return Select(item.d->m_Id); }
220  {
221  if (id > -1)
222  {
223  if (m_Data->m_Items.find(id) == m_Data->m_Items.end())
224  {
225  return false;
226  }
227  m_Data->m_SelectedId = id;
228  return true;
229  }
230  return false;
231  }
232 
233  std::vector<MimeType> FileWriterSelector::GetMimeTypes() const
234  {
235  std::vector<MimeType> result;
236  result.reserve(m_Data->m_MimeTypes.size());
237  result.assign(m_Data->m_MimeTypes.begin(), m_Data->m_MimeTypes.end());
238  return result;
239  }
240 
241  void FileWriterSelector::Swap(FileWriterSelector &fws) { m_Data.Swap(fws.m_Data); }
242  FileWriterSelector::Item::Item(const FileWriterSelector::Item &other) : d(other.d) {}
245  {
246  d = other.d;
247  return *this;
248  }
249 
250  IFileWriter *FileWriterSelector::Item::GetWriter() const { return d->m_FileWriter; }
252  {
253  us::Any descr = d->m_FileWriterRef.GetProperty(IFileWriter::PROP_DESCRIPTION());
254  if (descr.Empty())
255  return std::string();
256  return descr.ToString();
257  }
258 
260  MimeType FileWriterSelector::Item::GetMimeType() const { return d->m_MimeType; }
262  {
263  us::Any any = d->m_FileWriterRef.GetProperty(IFileWriter::PROP_BASEDATA_TYPE());
264  if (any.Empty())
265  return std::string();
266  return any.ToString();
267  }
268 
270  long FileWriterSelector::Item::GetServiceId() const { return d->m_Id; }
272  {
273  // sort by confidence level first (ascending)
274  if (d->m_ConfidenceLevel == other.d->m_ConfidenceLevel)
275  {
276  // sort by class hierarchy index (writers for more derived
277  // based data types are considered a better match)
278  if (d->m_BaseDataIndex == other.d->m_BaseDataIndex)
279  {
280  // sort by file writer service ranking
281  return d->m_FileWriterRef < other.d->m_FileWriterRef;
282  }
283  return other.d->m_BaseDataIndex < d->m_BaseDataIndex;
284  }
285  return d->m_ConfidenceLevel < other.d->m_ConfidenceLevel;
286  }
287 
288  FileWriterSelector::Item::Item() : d(new Impl()) {}
289  void swap(FileWriterSelector &fws1, FileWriterSelector &fws2) { fws1.Swap(fws2); }
290 }
virtual ConfidenceLevel GetConfidenceLevel() const =0
The confidence level of the reader or writer implementation.
std::vector< Item > Get() const
Get a sorted list of file writer info objects.
static IMimeTypeProvider * GetMimeTypeProvider(us::ModuleContext *context=us::GetModuleContext())
Get an IMimeTypeProvider instance.
Base of all data objects.
Definition: mitkBaseData.h:37
virtual MimeType GetMimeTypeForName(const std::string &name) const =0
static std::string PROP_DESCRIPTION()
Service property name for a description.
Definition: mitkIFileIO.cpp:18
bool Select(const std::string &mimeType)
DataCollection - Class to facilitate loading/accessing structured data.
ValueType * any_cast(Any *operand)
Definition: usAny.h:377
static std::string PROP_MIMETYPE()
Service property name for the mime-type associated with this file writer.
Definition: mitkIFileIO.cpp:24
bool Empty() const
Definition: usAny.h:246
virtual std::vector< std::string > GetClassHierarchy() const
Definition: mitkBaseData.h:41
std::string ToString() const
Definition: usAny.h:257
IFileWriter::ConfidenceLevel GetConfidenceLevel() const
std::vector< MimeType > GetMimeTypes() const
bool IsValid() const
const char * what() const override
Definition: usAny.h:352
void Swap(ExplicitlySharedDataPointer &other)
Definition: usSharedData.h:210
bool operator<(const Item &other) const
#define MITK_WARN
Definition: mitkLogMacros.h:19
ConfidenceLevel
A confidence level describing the confidence of the reader or writer in handling the given data...
Definition: mitkIFileIO.h:45
Definition: usAny.h:163
void swap(CustomMimeType &l, CustomMimeType &r)
static T max(T x, T y)
Definition: svm.cpp:56
virtual void SetInput(const BaseData *data)=0
Set the input data for writing.
The MimeType class represens a registered mime-type. It is an immutable wrapper for mitk::CustomMimeT...
Definition: mitkMimeType.h:36
FileWriterSelector & operator=(const FileWriterSelector &other)
static std::string PROP_BASEDATA_TYPE()
Service property name for the supported mitk::BaseData sub-class.
FileWriterSelector(const FileWriterSelector &other)
A RAII helper class for core service objects.
US_Core_EXPORT const std::string & SERVICE_ID()
The common interface of all MITK file writers.
us::ServiceReference< IFileWriter > GetReference() const
void Swap(FileWriterSelector &fws)
virtual std::vector< MimeType > GetMimeTypesForFile(const std::string &filePath) const =0