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 <filesystem>
18#include <iterator>
19#include <memory>
20
21namespace Mantid::API {
22
27
28namespace {
35IValidator_sptr createValidator(unsigned int action, const std::vector<std::string> &exts) {
37 return std::make_shared<DirectoryValidator>(action == FileProperty::Directory);
38 } else {
39 return std::make_shared<FileValidator>(exts, (action == FileProperty::Load));
40 }
41}
42
48void addExtension(const std::string &extension, std::vector<std::string> &extensions) {
49 if (std::find(extensions.begin(), extensions.end(), extension) != extensions.end())
50 return;
51 else
52 extensions.emplace_back(extension);
53}
54
60const std::string &getHomePath() {
61 static std::string homePath;
62 static bool initialised(false);
63
64 if (initialised) {
65 return homePath;
66 }
67 initialised = true;
68
69 char *home = std::getenv("HOME"); // Usually set on Windows and UNIX
70 if (home) {
71 homePath = std::string(home);
72 return homePath;
73 }
74
75 char *userProfile = std::getenv("USERPROFILE"); // Not usually set on UNIX
76 // Return even if it's an empty string, as we can do no better
77 homePath = userProfile ? std::string(userProfile) : "";
78 return homePath;
79}
80
91std::string expandUser(const std::string &filepath) {
92 // return immediately if empty
93 if (filepath.empty())
94 return filepath;
95
96 auto const start = filepath.begin();
97 auto const end = filepath.end();
98
99 // Filepath empty or contains no user variables
100 if (*start != '~')
101 return filepath;
102
103 // Position of the first slash after the variable
104 auto nextSlash = find_if(start, end, [](const char &c) { return c == '/' || c == '\\'; });
105
106 // ~user/blah format - no support for this as yet
107 if (std::distance(start, nextSlash) != 1)
108 return filepath;
109
110 return getHomePath() + std::string(nextSlash, end);
111}
112
116std::string resolveCurrentDirectory(const std::string &filepath) {
117 if (filepath.empty())
118 return filepath;
119 // only care about things that start with ./
120 if (filepath[0] != '.') // already know at least one character
121 return filepath;
122 if (filepath.size() > 1 && !(filepath.starts_with("./"))) {
123 return filepath;
124 }
125
126 std::filesystem::path path(filepath);
127 if (!path.is_absolute()) {
128 std::filesystem::path currentPath = std::filesystem::current_path();
129 path = currentPath / path;
130 }
131 return path.string();
132}
133
141std::string createDirectory(const std::filesystem::path &path) {
142 std::filesystem::path stempath(path);
143 // If the path doesn't end with a separator, assume it includes a filename component
144 // and we should create the parent directory instead
145 if (std::filesystem::is_regular_file(stempath)) {
146 stempath = stempath.parent_path();
147 }
148
149 if (!stempath.empty()) {
150 if (!std::filesystem::exists(stempath)) {
151 try {
152 std::filesystem::create_directories(stempath);
153 } catch (const std::exception &e) {
154 std::stringstream msg;
155 msg << "Failed to create directory \"" << stempath << "\": " << e.what();
156 return msg.str();
157 }
158 }
159 } else {
160 return "Invalid directory.";
161 }
162 return ""; // no error
163}
164} // Anonymous namespace
165
166//-----------------------------------------------------------------
167// Public member functions
168//-----------------------------------------------------------------
179FileProperty::FileProperty(const std::string &name, const std::string &defaultValue, unsigned int action,
180 const std::vector<std::string> &exts, unsigned int direction)
181 : PropertyWithValue<std::string>(name, defaultValue, createValidator(action, exts), direction), m_action(action),
182 m_defaultExt((!exts.empty()) ? exts.front() : ""), m_runFileProp(isLoadProperty() && extsMatchRunFiles()),
183 m_oldLoadPropValue(""), m_oldLoadFoundFile("") {}
184
194FileProperty::FileProperty(const std::string &name, const std::string &default_value, unsigned int action,
195 const std::string &ext, unsigned int direction)
196 : FileProperty(name, default_value, action, std::vector<std::string>(1, ext), direction) {}
197
207FileProperty::FileProperty(const std::string &name, const std::string &default_value, unsigned int action,
208 std::initializer_list<std::string> exts, unsigned int direction)
209 : FileProperty(name, default_value, action, std::vector<std::string>(exts), direction) {}
210
216
222
228
236
243std::string FileProperty::setValue(const std::string &propValue) {
244 std::string strippedValue = Kernel::Strings::strip(propValue);
245
246 // Empty value is allowed if optional
247 if (strippedValue.empty()) {
249 return isEmptyValueValid();
250 }
251
252 // Expand user variables, if there are any
253 strippedValue = expandUser(strippedValue);
254 strippedValue = resolveCurrentDirectory(strippedValue);
255 std::filesystem::path strippedPath(strippedValue);
256
257 // If this looks like an absolute path then don't do any searching but make
258 // sure the
259 // directory exists for a Save property
260 if (strippedPath.is_absolute()) {
261 if (isSaveProperty()) {
262 std::string error = createDirectory(strippedPath.parent_path());
263 if (!error.empty())
264 return error;
265 }
266
267 return PropertyWithValue<std::string>::setValue(strippedValue);
268 }
269
270 std::string errorMsg;
271 // For relative paths, differentiate between load and save types
272 if (isLoadProperty()) {
273 errorMsg = setLoadProperty(strippedValue);
274 } else {
275 errorMsg = setSaveProperty(strippedValue);
276 }
277 return errorMsg;
278}
279
288std::string FileProperty::isValid() const {
289 const std::string &value = (*this)();
290 if (value.empty()) {
291 return isEmptyValueValid();
292 } else {
294 }
295}
296
301 if (isOptional()) {
302 return "";
303 } else {
304 return "No file specified.";
305 }
306}
307
315 bool match(false);
316 try {
317 Kernel::FacilityInfo facilityInfo = Kernel::ConfigService::Instance().getFacility();
318 const std::vector<std::string> facilityExts = facilityInfo.extensions();
319 const std::vector<std::string> allowedExts = this->allowedValues();
320 match = std::any_of(allowedExts.cbegin(), allowedExts.cend(), [&facilityExts](const auto &ext) {
321 return std::find(facilityExts.cbegin(), facilityExts.cend(), ext) != facilityExts.cend();
322 });
323
325 } // facility could not be found, do nothing this will return the default
326 // match of false
327
328 return match;
329}
330
336std::string FileProperty::setLoadProperty(const std::string &propValue) {
337 // determine the initial version of foundFile
338 std::string foundFile;
339 if ((propValue == m_oldLoadPropValue) && (!m_oldLoadFoundFile.empty())) {
340 foundFile = m_oldLoadFoundFile;
341 }
342
343 // cache the new version of propValue
344 m_oldLoadPropValue = propValue;
345
346 // if foundFile is not empty then it is the cached file
347 if (foundFile.empty()) {
348 if (m_runFileProp) // runfiles go through FileFinder::findRun
349 {
350 std::vector<std::string> allowedExts(allowedValues());
351 std::vector<std::string> exts;
352 if (!m_defaultExt.empty()) {
353 addExtension(m_defaultExt, exts);
354
356 addExtension(lower, exts);
357
359 addExtension(upper, exts);
360 }
361 for (auto &ext : allowedExts) {
362 std::string lower(ext);
363 std::string upper(ext);
364 std::transform(ext.begin(), ext.end(), lower.begin(), tolower);
365 std::transform(ext.begin(), ext.end(), upper.begin(), toupper);
366 addExtension(ext, exts);
367 addExtension(lower, exts);
368 addExtension(upper, exts);
369 }
370 foundFile = FileFinder::Instance().findRun(propValue, exts).result();
371 } else // non-runfiles go through FileFinder::getFullPath
372 {
373 foundFile = FileFinder::Instance().getFullPath(propValue);
374 }
375 }
376
377 // cache the new version of foundFile
378 m_oldLoadFoundFile = foundFile;
379
380 if (foundFile.empty()) {
382 } else {
384 }
385}
386
392std::string FileProperty::setSaveProperty(const std::string &propValue) {
393 if (propValue.empty()) {
394 if (m_action == OptionalSave) {
396 } else
397 return "Empty filename not allowed.";
398 }
399 std::string errorMsg;
400 // We have a relative save path so just prepend the path that is in the
401 // 'defaultsave.directory'
402 // Note that this catches exceptions and returns an empty string in that case
403 std::string save_path = ConfigService::Instance().getString("defaultsave.directory");
404 std::filesystem::path save_dir;
405 if (save_path.empty()) {
406 save_dir = std::filesystem::path(propValue).parent_path();
407 // If we only have a stem filename, parent_path() will make save_dir empty
408 if (save_dir.empty()) {
409 save_dir = std::filesystem::current_path();
410 }
411 } else {
412 save_dir = std::filesystem::path(save_path);
413 }
414 errorMsg = createDirectory(save_dir);
415 if (errorMsg.empty()) {
416 std::string fullpath = (save_dir / propValue).string();
417 errorMsg = PropertyWithValue<std::string>::setValue(fullpath);
418 }
419 return errorMsg;
420}
421} // 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.