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
16
17#include <Poco/File.h>
18#include <Poco/Path.h>
19
20#include <iterator>
21#include <memory>
22
23namespace Mantid::API {
24
29
30namespace {
37IValidator_sptr createValidator(unsigned int action, const std::vector<std::string> &exts) {
39 return std::make_shared<DirectoryValidator>(action == FileProperty::Directory);
40 } else {
41 return std::make_shared<FileValidator>(exts, (action == FileProperty::Load));
42 }
43}
44
50void addExtension(const std::string &extension, std::vector<std::string> &extensions) {
51 if (std::find(extensions.begin(), extensions.end(), extension) != extensions.end())
52 return;
53 else
54 extensions.emplace_back(extension);
55}
56
62const std::string &getHomePath() {
63 static std::string homePath;
64 static bool initialised(false);
65
66 if (initialised) {
67 return homePath;
68 }
69 initialised = true;
70
71 char *home = std::getenv("HOME"); // Usually set on Windows and UNIX
72 if (home) {
73 homePath = std::string(home);
74 return homePath;
75 }
76
77 char *userProfile = std::getenv("USERPROFILE"); // Not usually set on UNIX
78 // Return even if it's an empty string, as we can do no better
79 homePath = userProfile ? std::string(userProfile) : "";
80 return homePath;
81}
82
93std::string expandUser(const std::string &filepath) {
94 auto start = filepath.begin();
95 auto end = filepath.end();
96
97 // Filepath empty or contains no user variables
98 if (start == end || *start != '~')
99 return filepath;
100
101 // Position of the first slash after the variable
102 auto nextSlash = find_if(start, end, [](const char &c) { return c == '/' || c == '\\'; });
103
104 // ~user/blah format - no support for this as yet
105 if (std::distance(start, nextSlash) != 1)
106 return filepath;
107
108 return getHomePath() + std::string(nextSlash, end);
109}
110
116std::string createDirectory(const std::string &path) {
117 Poco::Path stempath(path);
118 if (stempath.isFile()) {
119 stempath.makeParent();
120 }
121
122 if (!stempath.toString().empty()) {
123 Poco::File stem(stempath);
124 if (!stem.exists()) {
125 try {
126 stem.createDirectories();
127 } catch (Poco::Exception &e) {
128 std::stringstream msg;
129 msg << "Failed to create directory \"" << stempath.toString() << "\": " << e.what();
130 return msg.str();
131 }
132 }
133 } else {
134 return "Invalid directory.";
135 }
136 return ""; // everything went fine
137}
138} // Anonymous namespace
139
140//-----------------------------------------------------------------
141// Public member functions
142//-----------------------------------------------------------------
153FileProperty::FileProperty(const std::string &name, const std::string &defaultValue, unsigned int action,
154 const std::vector<std::string> &exts, unsigned int direction)
155 : PropertyWithValue<std::string>(name, defaultValue, createValidator(action, exts), direction), m_action(action),
156 m_defaultExt((!exts.empty()) ? exts.front() : ""), m_runFileProp(isLoadProperty() && extsMatchRunFiles()),
157 m_oldLoadPropValue(""), m_oldLoadFoundFile("") {}
158
168FileProperty::FileProperty(const std::string &name, const std::string &default_value, unsigned int action,
169 const std::string &ext, unsigned int direction)
170 : FileProperty(name, default_value, action, std::vector<std::string>(1, ext), direction) {}
171
181FileProperty::FileProperty(const std::string &name, const std::string &default_value, unsigned int action,
182 std::initializer_list<std::string> exts, unsigned int direction)
183 : FileProperty(name, default_value, action, std::vector<std::string>(exts), direction) {}
184
190
196
202
210
217std::string FileProperty::setValue(const std::string &propValue) {
218 std::string strippedValue = Kernel::Strings::strip(propValue);
219
220 // Empty value is allowed if optional
221 if (strippedValue.empty()) {
223 return isEmptyValueValid();
224 }
225
226 // Expand user variables, if there are any
227 strippedValue = expandUser(strippedValue);
228
229 // If this looks like an absolute path then don't do any searching but make
230 // sure the
231 // directory exists for a Save property
232 if (Poco::Path(strippedValue).isAbsolute()) {
233 if (isSaveProperty()) {
234 std::string 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 const std::vector<std::string> allowedExts = this->allowedValues();
292 match = std::any_of(allowedExts.cbegin(), allowedExts.cend(), [&facilityExts](const auto &ext) {
293 return std::find(facilityExts.cbegin(), facilityExts.cend(), ext) != facilityExts.cend();
294 });
295
297 } // facility could not be found, do nothing this will return the default
298 // match of false
299
300 return match;
301}
302
308std::string FileProperty::setLoadProperty(const std::string &propValue) {
309 // determine the initial version of foundFile
310 std::string foundFile;
311 if ((propValue == m_oldLoadPropValue) && (!m_oldLoadFoundFile.empty())) {
312 foundFile = m_oldLoadFoundFile;
313 }
314
315 // cache the new version of propValue
316 m_oldLoadPropValue = propValue;
317
318 // if foundFile is not empty then it is the cached file
319 if (foundFile.empty()) {
320 if (m_runFileProp) // runfiles go through FileFinder::findRun
321 {
322 std::vector<std::string> allowedExts(allowedValues());
323 std::vector<std::string> exts;
324 if (!m_defaultExt.empty()) {
325 addExtension(m_defaultExt, exts);
326
328 addExtension(lower, exts);
329
331 addExtension(upper, exts);
332 }
333 for (auto &ext : allowedExts) {
334 std::string lower(ext);
335 std::string upper(ext);
336 std::transform(ext.begin(), ext.end(), lower.begin(), tolower);
337 std::transform(ext.begin(), ext.end(), upper.begin(), toupper);
338 addExtension(ext, exts);
339 addExtension(lower, exts);
340 addExtension(upper, exts);
341 }
342 foundFile = FileFinder::Instance().findRun(propValue, exts).result();
343 } else // non-runfiles go through FileFinder::getFullPath
344 {
345 foundFile = FileFinder::Instance().getFullPath(propValue);
346 }
347 }
348
349 // cache the new version of foundFile
350 m_oldLoadFoundFile = foundFile;
351
352 if (foundFile.empty()) {
354 } else {
356 }
357}
358
364std::string FileProperty::setSaveProperty(const std::string &propValue) {
365 if (propValue.empty()) {
366 if (m_action == OptionalSave) {
368 } else
369 return "Empty filename not allowed.";
370 }
371 std::string errorMsg;
372 // We have a relative save path so just prepend the path that is in the
373 // 'defaultsave.directory'
374 // Note that this catches the Poco::NotFoundException and returns an empty
375 // string in that case
376 std::string save_path = ConfigService::Instance().getString("defaultsave.directory");
377 Poco::Path save_dir;
378 if (save_path.empty()) {
379 save_dir = Poco::Path(propValue).parent();
380 // If we only have a stem filename, parent() will make save_dir empty and
381 // then Poco::File throws
382 if (save_dir.toString().empty()) {
383 save_dir = Poco::Path::current();
384 }
385 } else {
386 save_dir = Poco::Path(save_path).makeDirectory();
387 }
388 errorMsg = createDirectory(save_dir.toString());
389 if (errorMsg.empty()) {
390 std::string fullpath = save_dir.resolve(propValue).toString();
391 errorMsg = PropertyWithValue<std::string>::setValue(fullpath);
392 }
393 return errorMsg;
394}
395} // namespace Mantid::API
std::string name
Definition Run.cpp:60
double error
double lower
lower and upper bounds on the multiplier, if known
double upper
A specialized class for dealing with file properties.
unsigned int m_action
The action type of this property, i.e. load/save.
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.
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?
bool isSaveProperty() const
Check if this is a save type property.
std::string m_oldLoadFoundFile
Last value of foundFile used in FileProperty::setLoadProperty.
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.
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
@ OptionalSave
to specify a file to write to but an empty string is
@ OptionalLoad
to specify a file to read but the file doesn't have to exist
@ OptionalDirectory
to specify a directory that does not have to exist
@ Save
to specify a file to write to, the file may or may not exist
@ Load
allowed here which will be passed to the algorithm
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.
const std::vector< std::string > & extensions() const
Returns a list of file extensions.
FileValidator is a validator that checks that a filepath is valid.
The concrete, templated class for properties.
std::string setValue(const std::string &value) override
Set the value of the property from a string representation.
std::vector< std::string > allowedValues() const override
Returns the set of valid values for this property, if such a set exists.
std::string value() const override
Get the value of the property as a string.
std::string isValid() const override
Check the value chosen for the property is OK, unless overidden it just calls the validator's isValid...
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:129
MANTID_KERNEL_DLL std::string strip(const std::string &A)
strip pre/post spaces
Definition Strings.cpp:419
MANTID_KERNEL_DLL std::string toUpper(const std::string &input)
Converts string to all uppercase.
Definition Strings.cpp:137
Mantid::Kernel::SingletonHolder< ConfigServiceImpl > ConfigService
std::shared_ptr< IValidator > IValidator_sptr
A shared_ptr to an IValidator.
Definition IValidator.h:26
STL namespace.