Mantid
Loading...
Searching...
No Matches
FileProperty.cpp
Go to the documentation of this file.
1// Mantid Repository : https://github.com/mantidproject/mantid
2//
3// Copyright © 2018 ISIS Rutherford Appleton Laboratory UKRI,
4// NScD Oak Ridge National Laboratory, European Spallation Source,
5// Institut Laue - Langevin & CSNS, Institute of High Energy Physics, CAS
6// SPDX - License - Identifier: GPL - 3.0 +
8
15
16#include <Poco/File.h>
17#include <Poco/Path.h>
18
19#include <iterator>
20#include <memory>
21
22namespace Mantid::API {
23
28
29namespace {
36IValidator_sptr createValidator(unsigned int action, const std::vector<std::string> &exts) {
38 return std::make_shared<DirectoryValidator>(action == FileProperty::Directory);
39 } else {
40 return std::make_shared<FileValidator>(exts, (action == FileProperty::Load));
41 }
42}
43
49void addExtension(const std::string &extension, std::vector<std::string> &extensions) {
50 if (std::find(extensions.begin(), extensions.end(), extension) != extensions.end())
51 return;
52 else
53 extensions.emplace_back(extension);
54}
55
61const std::string &getHomePath() {
62 static std::string homePath;
63 static bool initialised(false);
64
65 if (initialised) {
66 return homePath;
67 }
68 initialised = true;
69
70 char *home = std::getenv("HOME"); // Usually set on Windows and UNIX
71 if (home) {
72 homePath = std::string(home);
73 return homePath;
74 }
75
76 char *userProfile = std::getenv("USERPROFILE"); // Not usually set on UNIX
77 // Return even if it's an empty string, as we can do no better
78 homePath = userProfile ? std::string(userProfile) : "";
79 return homePath;
80}
81
92std::string expandUser(const std::string &filepath) {
93 auto start = filepath.begin();
94 auto end = filepath.end();
95
96 // Filepath empty or contains no user variables
97 if (start == end || *start != '~')
98 return filepath;
99
100 // Position of the first slash after the variable
101 auto nextSlash = find_if(start, end, [](const char &c) { return c == '/' || c == '\\'; });
102
103 // ~user/blah format - no support for this as yet
104 if (std::distance(start, nextSlash) != 1)
105 return filepath;
106
107 return getHomePath() + std::string(nextSlash, end);
108}
109
115std::string createDirectory(const std::string &path) {
116 Poco::Path stempath(path);
117 if (stempath.isFile()) {
118 stempath.makeParent();
119 }
120
121 if (!stempath.toString().empty()) {
122 Poco::File stem(stempath);
123 if (!stem.exists()) {
124 try {
125 stem.createDirectories();
126 } catch (Poco::Exception &e) {
127 std::stringstream msg;
128 msg << "Failed to create directory \"" << stempath.toString() << "\": " << e.what();
129 return msg.str();
130 }
131 }
132 } else {
133 return "Invalid directory.";
134 }
135 return ""; // everything went fine
136}
137} // Anonymous namespace
138
139//-----------------------------------------------------------------
140// Public member functions
141//-----------------------------------------------------------------
152FileProperty::FileProperty(const std::string &name, const std::string &defaultValue, unsigned int action,
153 const std::vector<std::string> &exts, unsigned int direction)
154 : PropertyWithValue<std::string>(name, defaultValue, createValidator(action, exts), direction), m_action(action),
155 m_defaultExt((!exts.empty()) ? exts.front() : ""), m_runFileProp(isLoadProperty() && extsMatchRunFiles()),
156 m_oldLoadPropValue(""), m_oldLoadFoundFile("") {}
157
167FileProperty::FileProperty(const std::string &name, const std::string &default_value, unsigned int action,
168 const std::string &ext, unsigned int direction)
169 : FileProperty(name, default_value, action, std::vector<std::string>(1, ext), direction) {}
170
180FileProperty::FileProperty(const std::string &name, const std::string &default_value, unsigned int action,
181 std::initializer_list<std::string> exts, unsigned int direction)
182 : FileProperty(name, default_value, action, std::vector<std::string>(exts), direction) {}
183
189
195
201
208}
209
216std::string FileProperty::setValue(const std::string &propValue) {
217 std::string strippedValue = Kernel::Strings::strip(propValue);
218
219 // Empty value is allowed if optional
220 if (strippedValue.empty()) {
222 return isEmptyValueValid();
223 }
224
225 // Expand user variables, if there are any
226 strippedValue = expandUser(strippedValue);
227
228 // If this looks like an absolute path then don't do any searching but make
229 // sure the
230 // directory exists for a Save property
231 if (Poco::Path(strippedValue).isAbsolute()) {
232 std::string error;
233 if (isSaveProperty()) {
234 error = createDirectory(strippedValue);
235 if (!error.empty())
236 return error;
237 }
238
239 return PropertyWithValue<std::string>::setValue(strippedValue);
240 }
241
242 std::string errorMsg;
243 // For relative paths, differentiate between load and save types
244 if (isLoadProperty()) {
245 errorMsg = setLoadProperty(strippedValue);
246 } else {
247 errorMsg = setSaveProperty(strippedValue);
248 }
249 return errorMsg;
250}
251
260std::string FileProperty::isValid() const {
261 const std::string &value = (*this)();
262 if (value.empty()) {
263 return isEmptyValueValid();
264 } else {
266 }
267}
268
273 if (isOptional()) {
274 return "";
275 } else {
276 return "No file specified.";
277 }
278}
279
287 bool match(false);
288 try {
289 Kernel::FacilityInfo facilityInfo = Kernel::ConfigService::Instance().getFacility();
290 const std::vector<std::string> facilityExts = facilityInfo.extensions();
291 auto facilityExtsBegin = facilityExts.cbegin();
292 auto facilityExtsEnd = facilityExts.cend();
293 const std::vector<std::string> allowedExts = this->allowedValues();
294
295 for (const auto &ext : allowedExts) {
296 if (std::find(facilityExtsBegin, facilityExtsEnd, ext) != facilityExtsEnd) {
297 match = true;
298 break;
299 }
300 }
302 } // facility could not be found, do nothing this will return the default
303 // match of false
304
305 return match;
306}
307
313std::string FileProperty::setLoadProperty(const std::string &propValue) {
314 // determine the initial version of foundFile
315 std::string foundFile;
316 if ((propValue == m_oldLoadPropValue) && (!m_oldLoadFoundFile.empty())) {
317 foundFile = m_oldLoadFoundFile;
318 }
319
320 // cache the new version of propValue
321 m_oldLoadPropValue = propValue;
322
323 // if foundFile is not empty then it is the cached file
324 if (foundFile.empty()) {
325 if (m_runFileProp) // runfiles go through FileFinder::findRun
326 {
327 std::vector<std::string> allowedExts(allowedValues());
328 std::vector<std::string> exts;
329 if (!m_defaultExt.empty()) {
330 addExtension(m_defaultExt, exts);
331
333 addExtension(lower, exts);
334
336 addExtension(upper, exts);
337 }
338 for (auto &ext : allowedExts) {
339 std::string lower(ext);
340 std::string upper(ext);
341 std::transform(ext.begin(), ext.end(), lower.begin(), tolower);
342 std::transform(ext.begin(), ext.end(), upper.begin(), toupper);
343 addExtension(ext, exts);
344 addExtension(lower, exts);
345 addExtension(upper, exts);
346 }
347 foundFile = FileFinder::Instance().findRun(propValue, exts);
348 } else // non-runfiles go through FileFinder::getFullPath
349 {
350 foundFile = FileFinder::Instance().getFullPath(propValue);
351 }
352 }
353
354 // cache the new version of foundFile
355 m_oldLoadFoundFile = foundFile;
356
357 if (foundFile.empty()) {
359 } else {
361 }
362}
363
369std::string FileProperty::setSaveProperty(const std::string &propValue) {
370 if (propValue.empty()) {
371 if (m_action == OptionalSave) {
373 } else
374 return "Empty filename not allowed.";
375 }
376 std::string errorMsg;
377 // We have a relative save path so just prepend the path that is in the
378 // 'defaultsave.directory'
379 // Note that this catches the Poco::NotFoundException and returns an empty
380 // string in that case
381 std::string save_path = ConfigService::Instance().getString("defaultsave.directory");
382 Poco::Path save_dir;
383 if (save_path.empty()) {
384 save_dir = Poco::Path(propValue).parent();
385 // If we only have a stem filename, parent() will make save_dir empty and
386 // then Poco::File throws
387 if (save_dir.toString().empty()) {
388 save_dir = Poco::Path::current();
389 }
390 } else {
391 save_dir = Poco::Path(save_path).makeDirectory();
392 }
393 errorMsg = createDirectory(save_dir.toString());
394 if (errorMsg.empty()) {
395 std::string fullpath = save_dir.resolve(propValue).toString();
396 errorMsg = PropertyWithValue<std::string>::setValue(fullpath);
397 }
398 return errorMsg;
399}
400} // namespace Mantid::API
double error
Definition: IndexPeaks.cpp:133
double lower
lower and upper bounds on the multiplier, if known
double upper
A specialized class for dealing with file properties.
Definition: FileProperty.h:42
unsigned int m_action
The action type of this property, i.e. load/save.
Definition: FileProperty.h:106
bool isLoadProperty() const
Check if this is a load type property.
std::string setValue(const std::string &propValue) override
Overridden setValue method.
bool isOptional() const
Check if this property is optional.
bool isDirectoryProperty() const
Check if this is a directory type property.
std::string isEmptyValueValid() const
Returns a string depending on whether an empty value is valid.
std::string setLoadProperty(const std::string &propValue)
Handles the filename if this is a save property.
std::string m_oldLoadPropValue
Last value of propValue used in FileProperty::setLoadProperty.
Definition: FileProperty.h:113
std::string setSaveProperty(const std::string &propValue)
Handles the filename if this is a save property.
bool m_runFileProp
Is this property for run files?
Definition: FileProperty.h:111
bool isSaveProperty() const
Check if this is a save type property.
std::string m_oldLoadFoundFile
Last value of foundFile used in FileProperty::setLoadProperty.
Definition: FileProperty.h:115
FileProperty(const std::string &name, const std::string &defaultValue, unsigned int action, const std::vector< std::string > &exts=std::vector< std::string >(), unsigned int direction=Kernel::Direction::Input)
Constructor taking a list of extensions as a vector.
bool extsMatchRunFiles()
Do the allowed values match the facility preference extensions for run files.
std::string m_defaultExt
The default file extension associated with the type of file this property will handle.
Definition: FileProperty.h:109
std::string isValid() const override
Returns an empty string if the property is valid, otherwise contains an error message.
@ Directory
to specify a directory that must exist
Definition: FileProperty.h:54
@ OptionalSave
to specify a file to write to but an empty string is
Definition: FileProperty.h:50
@ OptionalLoad
to specify a file to read but the file doesn't have to exist
Definition: FileProperty.h:53
@ OptionalDirectory
to specify a directory that does not have to exist
Definition: FileProperty.h:55
@ Save
to specify a file to write to, the file may or may not exist
Definition: FileProperty.h:49
@ Load
allowed here which will be passed to the algorithm
Definition: FileProperty.h:52
Loads a workspace from a data file.
Definition: Load.h:23
DirectoryValidator is a validator that checks that a directory path is valid.
Exception for when an item is not found in a collection.
Definition: Exception.h:145
A class that holds information about a facility.
Definition: FacilityInfo.h:36
const std::vector< std::string > extensions() const
Returns a list of file extensions.
Definition: FacilityInfo.h:48
FileValidator is a validator that checks that a filepath is valid.
Definition: FileValidator.h:25
The concrete, templated class for properties.
std::string setValue(const std::string &value) override
Set the value of the property via a string.
std::vector< std::string > allowedValues() const override
std::string isValid() const override
Overridden function that checks whether the property, if not overriden returns "".
Manage the lifetime of a class intended to be a singleton.
static T & Instance()
Return a reference to the Singleton instance, creating it if it does not already exist Creation is do...
DLLExport QString addExtension(const QString &filename, const QString &selectedFilter)
For file dialogs.
MANTID_KERNEL_DLL std::string toLower(const std::string &input)
Converts string to all lowercase.
Definition: Strings.cpp:116
MANTID_KERNEL_DLL std::string strip(const std::string &A)
strip pre/post spaces
Definition: Strings.cpp:397
MANTID_KERNEL_DLL std::string toUpper(const std::string &input)
Converts string to all uppercase.
Definition: Strings.cpp:124
std::shared_ptr< IValidator > IValidator_sptr
A shared_ptr to an IValidator.
Definition: IValidator.h:26
STL namespace.