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"
Gigg, Martyn Anthony
committed
#include <cctype>
#include <algorithm>
#include <iostream>
Gigg, Martyn Anthony
committed
Gigg, Martyn Anthony
committed
Gigg, Martyn Anthony
committed
Gigg, Martyn Anthony
committed
using namespace Mantid::Kernel;
//-----------------------------------------------------------------
// Public member functions
//-----------------------------------------------------------------
/**
* Constructor
Janik Zikovsky
committed
* @param name :: The name of the property
* @param default_value :: A default value for the property
* @param exts :: The allowed extensions, the front entry in the vector
* will be the default extension
* @param action :: An enum indicating whether this should be a load/save
* property
Janik Zikovsky
committed
* @param direction :: An optional direction (default=Input)
Gigg, Martyn Anthony
committed
*/
FileProperty::FileProperty(const std::string &name,
const std::string &default_value,
unsigned int action,
const std::vector<std::string> &exts,
unsigned int direction)
: PropertyWithValue<std::string>(
name, default_value,
/* Create either a FileValidator or a
DirectoryValidator, depending on Action
*/
(action == FileProperty::Directory ||
action == FileProperty::OptionalDirectory)
? boost::make_shared<DirectoryValidator>(action ==
FileProperty::Directory)
: boost::make_shared<FileValidator>(
exts, (action == FileProperty::Load),
(action == FileProperty::Save)),
direction),
m_action(action), m_defaultExt(""), m_runFileProp(false),
m_oldLoadPropValue(""), m_oldLoadFoundFile("") {
Gigg, Martyn Anthony
committed
setUp((exts.size() > 0) ? exts.front() : "");
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)
: PropertyWithValue<std::string>(
name, default_value,
/* Create either a FileValidator or a
DirectoryValidator, depending on Action
*/
(action == FileProperty::Directory ||
action == FileProperty::OptionalDirectory)
? boost::make_shared<DirectoryValidator>(action ==
FileProperty::Directory)
: boost::make_shared<FileValidator>(
std::vector<std::string>(1, ext),
(action == FileProperty::Load),
(action == FileProperty::Save)),
direction),
m_action(action), m_defaultExt(ext), m_runFileProp(false),
m_oldLoadPropValue(""), m_oldLoadFoundFile("") {
Gigg, Martyn Anthony
committed
setUp(ext);
}
/**
* 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
/**
* Set up the property
Janik Zikovsky
committed
* @param defExt :: The default extension
Gigg, Martyn Anthony
committed
*/
void FileProperty::setUp(const std::string &defExt) {
Gigg, Martyn Anthony
committed
m_defaultExt = defExt;
if (isLoadProperty() && extsMatchRunFiles()) {
Gigg, Martyn Anthony
committed
m_runFileProp = true;
Gigg, Martyn Anthony
committed
m_runFileProp = false;
}
}
Gigg, Martyn Anthony
committed
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();
std::vector<std::string>::const_iterator facilityExtsBegin =
facilityExts.begin();
std::vector<std::string>::const_iterator facilityExtsEnd =
facilityExts.end();
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
// match of false
Gigg, Martyn Anthony
committed
return match;
}
namespace { // anonymous namespace keeps it here
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
/**
* 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
}