Newer
Older
Gigg, Martyn Anthony
committed
//-----------------------------------------------------------------
// Includes
//-----------------------------------------------------------------
Gigg, Martyn Anthony
committed
#include "MantidAPI/FileProperty.h"
#include "MantidKernel/FileValidator.h"
Gigg, Martyn Anthony
committed
#include "MantidKernel/ConfigService.h"
#include "Poco/Path.h"
#include "Poco/File.h"
Gigg, Martyn Anthony
committed
Gigg, Martyn Anthony
committed
namespace Mantid
{
namespace API
{
Gigg, Martyn Anthony
committed
using namespace Mantid::Kernel;
//-----------------------------------------------------------------
// Public member functions
//-----------------------------------------------------------------
/**
* Constructor
* @param name The name of the property
Gigg, Martyn Anthony
committed
* @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
* @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, new FileValidator(exts, (action == FileProperty::Load) ), direction),
Gigg, Martyn Anthony
committed
m_action(action)
{
m_defaultExt = exts.size() > 0 ? exts.front() : "";
Gigg, Martyn Anthony
committed
}
/**
* Constructor
* @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
* @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)
Peterson, Peter
committed
: PropertyWithValue<std::string>(name, default_value,
new FileValidator(std::vector<std::string>(1,ext), (action == FileProperty::Load) ), direction),
m_action(action), m_defaultExt(ext)
{
}
/**
* Check if this is a load property
* @returns True if the property is a Load property and false if a Save type
*/
bool FileProperty::isLoadProperty() const
{
return m_action == Load || m_action == OptionalLoad;
Gigg, Martyn Anthony
committed
/**
* Set the filename
* @param filename The value here is treated as a filename.
* @returns A string indicating the outcome of the attempt to set the property. An empty string indicates success.
*/
std::string FileProperty::setValue(const std::string & filename)
{
Gigg, Martyn Anthony
committed
// If the path is absolute then don't do any searching but make sure the directory exists for a Save property
Gigg, Martyn Anthony
committed
if( Poco::Path(filename).isAbsolute() )
Gigg, Martyn Anthony
committed
{
Gigg, Martyn Anthony
committed
std::string error("");
Gigg, Martyn Anthony
committed
if( !isLoadProperty() )
{
Gigg, Martyn Anthony
committed
error = checkDirectory(filename);
if( !error.empty() ) return error;
Gigg, Martyn Anthony
committed
}
Gigg, Martyn Anthony
committed
error = PropertyWithValue<std::string>::setValue(filename);
if( error.empty() ) return error;
// Change the file extension to a lower/upper cased version of the extension to check if this can be found instead
std::string diffcase_ext = convertExtension(filename);
return PropertyWithValue<std::string>::setValue(diffcase_ext);
Gigg, Martyn Anthony
committed
}
std::string valid_string("");
// For relative paths, differentiate between load and save types
Gigg, Martyn Anthony
committed
if( isLoadProperty() )
Gigg, Martyn Anthony
committed
{
Gigg, Martyn Anthony
committed
if( filename.empty() ) return PropertyWithValue<std::string>::setValue(filename);
Gigg, Martyn Anthony
committed
Poco::File relative(filename);
Poco::File check_file(Poco::Path(Poco::Path::current()).resolve(relative.path()));
Gigg, Martyn Anthony
committed
valid_string = PropertyWithValue<std::string>::setValue(check_file.path());
Steve Williams
committed
if( !valid_string.empty() || !check_file.exists() )
Gigg, Martyn Anthony
committed
{
Gigg, Martyn Anthony
committed
std::string diffcase_ext = convertExtension(filename);
valid_string = PropertyWithValue<std::string>::setValue(diffcase_ext);
check_file = Poco::Path(Poco::Path::current()).resolve(diffcase_ext);
if( valid_string.empty() && check_file.exists() ) return "";
Poco::File relative_diffext(diffcase_ext);
Gigg, Martyn Anthony
committed
const std::vector<std::string>& search_dirs = ConfigService::Instance().getDataSearchDirs();
std::vector<std::string>::const_iterator iend = search_dirs.end();
for( std::vector<std::string>::const_iterator it = search_dirs.begin(); it != iend; ++it )
{
Gigg, Martyn Anthony
committed
check_file = Poco::File(Poco::Path(*it).resolve(relative.path()));
if( check_file.exists() )
{
valid_string = PropertyWithValue<std::string>::setValue(check_file.path());
break;
}
Gigg, Martyn Anthony
committed
check_file = Poco::File(Poco::Path(*it).resolve(relative_diffext.path()));
if( check_file.exists() )
{
valid_string = PropertyWithValue<std::string>::setValue(check_file.path());
break;
}
Gigg, Martyn Anthony
committed
}
}
}
else
{
if( filename.empty() )
{
if ( m_action == OptionalSave )
{
return PropertyWithValue<std::string>::setValue("");
}
else return "Empty filename not allowed.";
}
Gigg, Martyn Anthony
committed
Gigg, Martyn Anthony
committed
// We have a relative save path so just prepend the path that is in the 'defaultsave.directory'
Gigg, Martyn Anthony
committed
// Note that this catches the Poco::NotFoundException and returns an empty string in that case
Gigg, Martyn Anthony
committed
std::string save_path = ConfigService::Instance().getString("defaultsave.directory");
Poco::Path save_dir;
if( save_path.empty() )
{
save_dir = Poco::Path(filename).parent();
Gigg, Martyn Anthony
committed
// 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
}
else
{
save_dir = Poco::Path(save_path).makeDirectory();
}
Gigg, Martyn Anthony
committed
valid_string = checkDirectory(save_dir.toString());
if( valid_string.empty() )
Gigg, Martyn Anthony
committed
{
Gigg, Martyn Anthony
committed
std::string fullpath = save_dir.resolve(filename).toString();
valid_string = PropertyWithValue<std::string>::setValue(fullpath);
Gigg, Martyn Anthony
committed
}
Gigg, Martyn Anthony
committed
Gigg, Martyn Anthony
committed
}
return valid_string;
}
Gigg, Martyn Anthony
committed
/**
* Check whether a given directory exists and create it if it does not.
* @param fullpath 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
*/
Gigg, Martyn Anthony
committed
std::string FileProperty::checkDirectory(const std::string & fullpath) const
Gigg, Martyn Anthony
committed
{
Poco::Path stempath(fullpath);
if( stempath.isFile() )
{
stempath.makeParent();
}
Gigg, Martyn Anthony
committed
std::string error("");
Gigg, Martyn Anthony
committed
if( !stempath.toString().empty() )
{
Poco::File stem(stempath);
if( !stem.exists() )
{
Gigg, Martyn Anthony
committed
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
try
{
stem.createDirectories();
}
catch(Poco::Exception &e)
{
error = e.what();
}
}
}
else
{
error = "Invalid directory.";
}
return error;
}
/**
* 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.
* @returns The new filename
*/
std::string FileProperty::convertExtension(const std::string & filepath) const
{
Poco::Path fullpath(filepath);
std::string ext = fullpath.getExtension();
if( ext.empty() ) return "";
int nchars = ext.size();
for( int i = 0; i < nchars; ++i )
{
int c = static_cast<int>(ext[i]);
if( c >= 65 && c <= 90 )
{
ext[i] = static_cast<char>(c + 32);
}
else if( c >= 97 && c <= 122 )
{
ext[i] = static_cast<char>(c - 32);
}
else
{
Gigg, Martyn Anthony
committed
}
}
Gigg, Martyn Anthony
committed
fullpath.setExtension(ext);
return fullpath.toString();
Gigg, Martyn Anthony
committed
}