Newer
Older
Gigg, Martyn Anthony
committed
//-----------------------------------------------------------------
// Includes
//-----------------------------------------------------------------
Gigg, Martyn Anthony
committed
#include "MantidAPI/FileProperty.h"
Gigg, Martyn Anthony
committed
#include "MantidAPI/FileFinder.h"
Gigg, Martyn Anthony
committed
#include "MantidKernel/ConfigService.h"
#include "MantidKernel/DirectoryValidator.h"
Gigg, Martyn Anthony
committed
#include "MantidKernel/FacilityInfo.h"
#include "MantidKernel/FileValidator.h"
#include "MantidKernel/Strings.h"
#include <Poco/Path.h>
#include <algorithm>
#include <cctype>
Gigg, Martyn Anthony
committed
Gigg, Martyn Anthony
committed
Gigg, Martyn Anthony
committed
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
using Mantid::Kernel::ConfigService;
using Mantid::Kernel::DirectoryValidator;
using Mantid::Kernel::FileValidator;
using Mantid::Kernel::IValidator_sptr;
namespace {
/**
* Create the appropriate validator based on the parameters
* @param action The type of property that is being defined, @see FileAction
* @param exts A list of extensions, only use for File-type actions and are
* passed to the validator
*/
IValidator_sptr createValidator(unsigned int action,
const std::vector<std::string> &exts) {
if (action == FileProperty::Directory ||
action == FileProperty::OptionalDirectory) {
return boost::make_shared<DirectoryValidator>(action ==
FileProperty::Directory);
} else {
return boost::make_shared<FileValidator>(
exts, (action == FileProperty::Load), (action == FileProperty::Save));
}
}
/**
* If the given extension doesn't exist in the list then add it
* @param extension A string listing the extension
* @param extensions The existing collection
*/
void addExtension(const std::string &extension,
std::vector<std::string> &extensions) {
if (std::find(extensions.begin(), extensions.end(), extension) !=
extensions.end())
return;
else
extensions.push_back(extension);
}
}
Gigg, Martyn Anthony
committed
//-----------------------------------------------------------------
// Public member functions
//-----------------------------------------------------------------
/**
* Constructor
* @param name The name of the property
* @param defaultValue A default value for the property
* @param action Inndicate whether this should be a load/save
* @param exts The allowed extensions. The front entry in the vector
* will be the default extension
* @param direction An optional direction (default=Input)
Gigg, Martyn Anthony
committed
*/
FileProperty::FileProperty(const std::string &name,
const std::string &defaultValue, unsigned int action,
const std::vector<std::string> &exts,
unsigned int direction)
: PropertyWithValue<std::string>(name, defaultValue,
createValidator(action, exts), direction),
m_action(action), m_defaultExt((exts.size() > 0) ? exts.front() : ""),
m_runFileProp(isLoadProperty() && extsMatchRunFiles()),
m_oldLoadPropValue(""), m_oldLoadFoundFile("") {}
Gigg, Martyn Anthony
committed
/**
* Constructor
Janik Zikovsky
committed
* @param name :: The name of the property
* @param default_value :: A default value for the property
* @param ext :: The allowed extension
* @param action :: An enum indicating whether this should be a load/save
* property
Janik Zikovsky
committed
* @param direction :: An optional direction (default=Input)
*/
FileProperty::FileProperty(const std::string &name,
const std::string &default_value,
unsigned int action, const std::string &ext,
unsigned int direction)
: FileProperty(name, default_value, action,
std::vector<std::string>(1, ext), direction) {}
/**
* Constructor
* @param name :: The name of the property
* @param default_value :: A default value for the property
* @param exts :: The braced-list of allowed extensions
* @param action :: An enum indicating whether this should be a load/save
* property
* @param direction :: An optional direction (default=Input)
*/
FileProperty::FileProperty(const std::string &name,
const std::string &default_value,
unsigned int action,
std::initializer_list<std::string> exts,
unsigned int direction)
: FileProperty(name, default_value, action,
std::vector<std::string>(std::move(exts)), direction) {}
/**
* Check if this is a load property
Janik Zikovsky
committed
* @returns True if the property is a Load property and false otherwise
bool FileProperty::isLoadProperty() const {
return m_action == Load || m_action == OptionalLoad;
Janik Zikovsky
committed
/**
* Check if this is a Save property
* @returns True if the property is a Save property and false otherwise
*/
bool FileProperty::isSaveProperty() const {
Janik Zikovsky
committed
return m_action == Save || m_action == OptionalSave;
}
/**
* Check if this is a directory selection property
* @returns True if the property is a Directory property
*/
bool FileProperty::isDirectoryProperty() const {
Janik Zikovsky
committed
return m_action == Directory || m_action == OptionalDirectory;
}
Gigg, Martyn Anthony
committed
/**
* Check if this property is optional
* @returns True if the property is optinal, false otherwise
*/
bool FileProperty::isOptional() const {
return (m_action == OptionalLoad || m_action == OptionalSave ||
m_action == OptionalDirectory);
Gigg, Martyn Anthony
committed
}
Gigg, Martyn Anthony
committed
/**
Gigg, Martyn Anthony
committed
* Set the value of the property
Janik Zikovsky
committed
* @param propValue :: The value here is treated as relating to a filename
* @return A string indicating the outcome of the attempt to set the property.
* An empty string indicates success.
Gigg, Martyn Anthony
committed
*/
std::string FileProperty::setValue(const std::string &propValue) {
std::string strippedValue = Kernel::Strings::strip(propValue);
Gigg, Martyn Anthony
committed
// Empty value is allowed if optional
Gigg, Martyn Anthony
committed
PropertyWithValue<std::string>::setValue("");
return isEmptyValueValid();
Gigg, Martyn Anthony
committed
}
// If this looks like an absolute path then don't do any searching but make
// sure the
Gigg, Martyn Anthony
committed
// directory exists for a Save property
if (Poco::Path(strippedValue).isAbsolute()) {
Gigg, Martyn Anthony
committed
std::string error("");
if (isSaveProperty()) {
error = createDirectory(strippedValue);
if (!error.empty())
return error;
Gigg, Martyn Anthony
committed
}
Gigg, Martyn Anthony
committed
return PropertyWithValue<std::string>::setValue(strippedValue);
Gigg, Martyn Anthony
committed
}
Gigg, Martyn Anthony
committed
std::string errorMsg("");
Gigg, Martyn Anthony
committed
// For relative paths, differentiate between load and save types
errorMsg = setLoadProperty(strippedValue);
errorMsg = setSaveProperty(strippedValue);
Gigg, Martyn Anthony
committed
}
return errorMsg;
}
Gigg, Martyn Anthony
committed
* Checks whether the current value is considered valid. Use the validator
* unless the
* value is an empty string. In this case it is only valid if the property is
* not optional
* @returns an empty string if the property is valid, otherwise contains an
* error message
std::string FileProperty::isValid() const {
const std::string &value = (*this)();
if (value.empty()) {
return isEmptyValueValid();
return PropertyWithValue<std::string>::isValid();
}
}
/**
* @returns a string depending on whether an empty value is valid
*/
std::string FileProperty::isEmptyValueValid() const {
if (isOptional()) {
return "No file specified.";
}
}
Gigg, Martyn Anthony
committed
/**
* Do the allowed values match the facility preference extensions for run files
* @returns True if the extensions match those in the facility's preference list
* for
Gigg, Martyn Anthony
committed
* run file extensions, false otherwise
*/
bool FileProperty::extsMatchRunFiles() {
Gigg, Martyn Anthony
committed
bool match(false);
try {
Kernel::FacilityInfo facilityInfo =
Kernel::ConfigService::Instance().getFacility();
const std::vector<std::string> facilityExts = facilityInfo.extensions();
auto facilityExtsBegin =
const std::vector<std::string> allowedExts = this->allowedValues();
for (auto it = allowedExts.begin(); it != allowedExts.end(); ++it) {
if (std::find(facilityExtsBegin, facilityExtsEnd, *it) !=
facilityExtsEnd) {
match = true;
break;
}
Gigg, Martyn Anthony
committed
}
} catch (Mantid::Kernel::Exception::NotFoundError &) {
} // facility could not be found, do nothing this will return the default
Gigg, Martyn Anthony
committed
return match;
}
/**
* Handles the filename if this is a load property
Janik Zikovsky
committed
* @param propValue :: The filename to treat as a filepath to be loaded
Gigg, Martyn Anthony
committed
* @returns A string contain the result of the operation, empty if successful.
*/
std::string FileProperty::setLoadProperty(const std::string &propValue) {
// determine the initial version of foundFile
Gigg, Martyn Anthony
committed
std::string foundFile("");
if ((propValue == m_oldLoadPropValue) && (!m_oldLoadFoundFile.empty())) {
foundFile = m_oldLoadFoundFile;
}
// cache the new version of propValue
m_oldLoadPropValue = propValue;
// if foundFile is not empty then it is the cached file
if (foundFile.empty()) {
if (m_runFileProp) // runfiles go through FileFinder::findRun
{
std::vector<std::string> allowedExts(allowedValues());
std::vector<std::string> exts;
addExtension(m_defaultExt, exts);
std::string lower(m_defaultExt);
std::transform(m_defaultExt.begin(), m_defaultExt.end(), lower.begin(),
tolower);
addExtension(lower, exts);
std::string upper(m_defaultExt);
std::transform(m_defaultExt.begin(), m_defaultExt.end(), upper.begin(),
toupper);
addExtension(upper, exts);
}
for (auto it = allowedExts.begin(); it != allowedExts.end(); ++it) {
std::string lower(*it);
std::string upper(*it);
std::transform(it->begin(), it->end(), lower.begin(), tolower);
std::transform(it->begin(), it->end(), upper.begin(), toupper);
addExtension(*it, exts);
addExtension(lower, exts);
addExtension(upper, exts);
}
foundFile = FileFinder::Instance().findRun(propValue, exts);
} else // non-runfiles go through FileFinder::getFullPath
foundFile = FileFinder::Instance().getFullPath(propValue);
Gigg, Martyn Anthony
committed
}
// cache the new version of foundFile
m_oldLoadFoundFile = foundFile;
Gigg, Martyn Anthony
committed
return PropertyWithValue<std::string>::setValue(propValue);
Gigg, Martyn Anthony
committed
return PropertyWithValue<std::string>::setValue(foundFile);
}
}
/**
* Handles the filename if this is a save property
Janik Zikovsky
committed
* @param propValue :: The filename to treat as a filepath to be saved
Gigg, Martyn Anthony
committed
* @returns A string contain the result of the operation, empty if successful.
*/
std::string FileProperty::setSaveProperty(const std::string &propValue) {
if (propValue.empty()) {
if (m_action == OptionalSave) {
Gigg, Martyn Anthony
committed
return PropertyWithValue<std::string>::setValue("");
} else
return "Empty filename not allowed.";
Gigg, Martyn Anthony
committed
}
std::string errorMsg("");
// We have a relative save path so just prepend the path that is in the
// 'defaultsave.directory'
// Note that this catches the Poco::NotFoundException and returns an empty
// string in that case
std::string save_path =
ConfigService::Instance().getString("defaultsave.directory");
Gigg, Martyn Anthony
committed
Poco::Path save_dir;
Gigg, Martyn Anthony
committed
save_dir = Poco::Path(propValue).parent();
// If we only have a stem filename, parent() will make save_dir empty and
// then Poco::File throws
if (save_dir.toString().empty()) {
Gigg, Martyn Anthony
committed
save_dir = Poco::Path::current();
Gigg, Martyn Anthony
committed
}
Gigg, Martyn Anthony
committed
save_dir = Poco::Path(save_path).makeDirectory();
}
errorMsg = createDirectory(save_dir.toString());
Gigg, Martyn Anthony
committed
std::string fullpath = save_dir.resolve(propValue).toString();
errorMsg = PropertyWithValue<std::string>::setValue(fullpath);
}
return errorMsg;
Gigg, Martyn Anthony
committed
}
Gigg, Martyn Anthony
committed
/**
Gigg, Martyn Anthony
committed
* Create a given directory if it does not already exist.
Janik Zikovsky
committed
* @param path :: The path to the directory, which can include file stem
Gigg, Martyn Anthony
committed
* @returns A string indicating a problem if one occurred
Gigg, Martyn Anthony
committed
*/
std::string FileProperty::createDirectory(const std::string &path) const {
Gigg, Martyn Anthony
committed
Poco::Path stempath(path);
Gigg, Martyn Anthony
committed
stempath.makeParent();
}
if (!stempath.toString().empty()) {
Gigg, Martyn Anthony
committed
Poco::File stem(stempath);
stem.createDirectories();
std::stringstream msg;
msg << "Failed to create directory \"" << stempath.toString()
return msg.str();
Gigg, Martyn Anthony
committed
}
}
return "Invalid directory.";
Gigg, Martyn Anthony
committed
}
return ""; // everything went fine
Gigg, Martyn Anthony
committed
}
/**
* Check file extension to see if a lower- or upper-cased version will also
* match if the given one does not exist
* @param filepath :: A filename whose extension is checked and converted to
* lower/upper case if necessary.
Gigg, Martyn Anthony
committed
* @returns The new filename
*/
std::string FileProperty::convertExtension(const std::string &filepath) const {
Gigg, Martyn Anthony
committed
Poco::Path fullpath(filepath);
std::string ext = fullpath.getExtension();
if (ext.empty())
return filepath;
Steve Williams
committed
const size_t nchars = ext.size();
for (size_t i = 0; i < nchars; ++i) {
Gigg, Martyn Anthony
committed
int c = static_cast<int>(ext[i]);
Gigg, Martyn Anthony
committed
}
}
Gigg, Martyn Anthony
committed
fullpath.setExtension(ext);
Gigg, Martyn Anthony
committed
}