Newer
Older
//----------------------------------------------------------------------
// Includes
//----------------------------------------------------------------------
#include "MantidKernel/PropertyManager.h"
#include "MantidKernel/Exception.h"
Gigg, Martyn Anthony
committed
#include <boost/algorithm/string/trim.hpp>
Janik Zikovsky
committed
using std::string;
// Get a reference to the logger
Logger& PropertyManager::g_log = Logger::get("PropertyManager");
Janik Zikovsky
committed
//-----------------------------------------------------------------------------------------------
Russell Taylor
committed
m_properties(), m_orderedProperties()
Janik Zikovsky
committed
//-----------------------------------------------------------------------------------------------
Janik Zikovsky
committed
/// @param other :: the PropertyManager to copy
Russell Taylor
committed
PropertyManager::PropertyManager(const PropertyManager& other) :
m_properties(), m_orderedProperties(other.m_orderedProperties.size())
{
// We need to do a deep copy of the property pointers here
for (unsigned int i = 0; i < m_orderedProperties.size(); ++i)
{
Property * p = other.m_orderedProperties[i]->clone();
this->m_orderedProperties[i] = p;
Russell Taylor
committed
std::string key = p->name();
std::transform(key.begin(), key.end(), key.begin(), toupper);
this->m_properties[key] = p;
Russell Taylor
committed
}
}
Janik Zikovsky
committed
//-----------------------------------------------------------------------------------------------
Janik Zikovsky
committed
/// @param other :: the PropertyManager to copy
Russell Taylor
committed
PropertyManager& PropertyManager::operator=(const PropertyManager& other)
{
// We need to do a deep copy here
if ( this != &other )
{
for ( PropertyMap::iterator it = m_properties.begin(); it != m_properties.end(); ++it )
{
delete it->second;
}
this->m_properties.clear();
this->m_orderedProperties.resize(other.m_orderedProperties.size());
Russell Taylor
committed
for (unsigned int i = 0; i < m_orderedProperties.size(); ++i)
{
Property * p = other.m_orderedProperties[i]->clone();
this->m_orderedProperties[i] = p;
std::string key = p->name();
std::transform(key.begin(), key.end(), key.begin(), toupper);
this->m_properties[key] = p;
Russell Taylor
committed
}
}
return *this;
}
Janik Zikovsky
committed
//-----------------------------------------------------------------------------------------------
Russell Taylor
committed
/// Virtual destructor
Gigg, Martyn Anthony
committed
clear();
Janik Zikovsky
committed
//-----------------------------------------------------------------------------------------------
/**
* Addition operator
Janik Zikovsky
committed
* @param rhs :: The object that is being added to this.
Janik Zikovsky
committed
* @returns A reference to the summed object
*/
PropertyManager& PropertyManager::operator+=(const PropertyManager& rhs)
{
//Iterate through all properties on the RHS
PropertyMap::const_iterator it;
for (it = rhs.m_properties.begin(); it != rhs.m_properties.end(); ++it)
Janik Zikovsky
committed
{
//The name on the rhs
string rhs_name = it->first;
try
{
Property * lhs_prop = this->getPointerToProperty(rhs_name);
//Use the property's += operator to add THAT. Isn't abstraction fun?!
(*lhs_prop) += it->second;
}
catch (Exception::NotFoundError &)
Janik Zikovsky
committed
{
//The property isnt on the lhs.
//Let's copy it
Property * copy = it->second->clone();
//And we add a copy of that property to *this
this->declareProperty(copy, "");
}
//(*it->second) +=
}
return *this;
}
//-----------------------------------------------------------------------------------------------
/**
* Filter out a run by time. Takes out any TimeSeriesProperty log entries outside of the given
* absolute time range.
*
Janik Zikovsky
committed
* @param start :: Absolute start time. Any log entries at times >= to this time are kept.
* @param stop :: Absolute stop time. Any log entries at times < than this time are kept.
*/
Janik Zikovsky
committed
void PropertyManager::filterByTime(const Kernel::DateAndTime start, const Kernel::DateAndTime stop)
{
Janik Zikovsky
committed
//Iterate through all properties
PropertyMap::const_iterator it;
for (it = this->m_properties.begin(); it != this->m_properties.end(); ++it)
{
//Filter out the property
Property * prop = it->second;
prop->filterByTime(start, stop);
}
}
Janik Zikovsky
committed
//-----------------------------------------------------------------------------------------------
/**
* Split a run by time (splits the TimeSeriesProperties contained).
*
* Total proton charge will get re-integrated after filtering.
*
Janik Zikovsky
committed
* @param splitter :: TimeSplitterType with the intervals and destinations.
* @param outputs :: Vector of output runs.
Janik Zikovsky
committed
*/
void PropertyManager::splitByTime(TimeSplitterType& splitter, std::vector< PropertyManager * > outputs) const
{
size_t n = outputs.size();
//Iterate through all properties
PropertyMap::const_iterator it;
for (it = this->m_properties.begin(); it != this->m_properties.end(); ++it)
Janik Zikovsky
committed
{
//Filter out the property
Property * prop = it->second;
//Make a vector of the output properties contained in the other property managers.
// NULL if it was not found.
std::vector< Property *> output_properties;
for (size_t i=0; i<n; i++)
{
if (outputs[i])
output_properties.push_back( outputs[i]->getPointerToPropertyOrNull( prop->name() ) );
else
output_properties.push_back( NULL );
}
//Now the property does the splitting.
prop->splitByTime(splitter, output_properties);
}//for each property
}
Janik Zikovsky
committed
//-----------------------------------------------------------------------------------------------
/** Add a property to the list of managed properties
Janik Zikovsky
committed
* @param p :: The property object to add
* @param doc :: A description of the property that may be displayed to users
* @throw Exception::ExistsError if a property with the given name already exists
* @throw std::invalid_argument if the property declared has an empty name.
*/
Steve Williams
committed
void PropertyManager::declareProperty( Property *p, const std::string &doc )
{
// Get the name of the property and don't permit empty names
std::string key = p->name();
throw std::invalid_argument("An empty property name is not permitted");
}
std::transform(key.begin(), key.end(), key.begin(), toupper);
if ( m_properties.insert(PropertyMap::value_type(key, p)).second)
{
m_orderedProperties.push_back(p);
}
else
{
// Don't delete if this is actually the same property object!!!
if ( m_properties.find(key)->second != p ) delete p;
throw Exception::ExistsError( "Property with given name already exists", key );
Steve Williams
committed
p->setDocumentation(doc);
Janik Zikovsky
committed
//-----------------------------------------------------------------------------------------------
/** Set the ordered list of properties by one string of values, separated by semicolons.
*
* The string should be of format "PropertyName=value;Property2=value2; etc..."
*
Janik Zikovsky
committed
* @param propertiesArray :: The list of property values
* @throw invalid_argument if error in parameters
// Care will certainly be required in the calling of this function or it could all go horribly wrong!
Freddie Akeroyd
committed
void PropertyManager::setProperties( const std::string &propertiesArray )
// Split up comma-separated properties
typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
boost::char_separator<char> sep(";");
tokenizer propPairs(propertiesArray, sep);
int index=0;
// Iterate over the properties
for (tokenizer::iterator it = propPairs.begin(); it != propPairs.end(); ++it)
{
// Pair of the type "
std::string pair = *it;
size_t n = pair.find('=');
if (n == std::string::npos)
// No equals sign
// This is for a property with no value. Not clear that we will want such a thing.
// Interpret the string as the index^th property in the list,
setPropertyOrdinal(index,pair);
// Normal "PropertyName=value" string.
std::string propName = "";
std::string value = "";
// Extract the value string
if (n < pair.size()-1)
{
propName = pair.substr(0, n);
value = pair.substr(n+1, pair.size()-n-1);
}
else
{
// String is "PropertyName="
propName = pair.substr(0, n);
value = "";
}
// Set it
setPropertyValue(propName,value);
Janik Zikovsky
committed
//-----------------------------------------------------------------------------------------------
* N.B. bool properties must be set using 1/0 rather than true/false
Janik Zikovsky
committed
* @param name :: The name of the property (case insensitive)
* @param value :: The value to assign to the property
* @throw Exception::NotFoundError if the named property is unknown
* @throw std::invalid_argument If the value is not valid for the property given
*/
void PropertyManager::setPropertyValue( const std::string &name, const std::string &value )
{
Property *p = getPointerToProperty(name); // throws NotFoundError if property not in vector
Steve Williams
committed
std::string errorMsg = p->setValue(value);
Steve Williams
committed
if ( !errorMsg.empty() )
{
Steve Williams
committed
errorMsg = "Invalid value for property " + p->name() + " (" +p->type() + ") \"" + value
Steve Williams
committed
+ "\": " + errorMsg;
throw std::invalid_argument(errorMsg);
}
Russell Taylor
committed
Janik Zikovsky
committed
//-----------------------------------------------------------------------------------------------
* N.B. bool properties must be set using 1/0 rather than true/false
Janik Zikovsky
committed
* @param index :: The index of the property to assign
* @param value :: The value to assign to the property
* @throw std::runtime_error if the property index is too high
* @throw std::invalid_argument If the value is not valid for the property given
*/
void PropertyManager::setPropertyOrdinal( const int& index, const std::string &value )
{
Property *p = getPointerToPropertyOrdinal(index); // throws runtime_error if property not in vector
Steve Williams
committed
std::string errorMsg = p->setValue(value);
this->afterPropertySet(p->name());
Steve Williams
committed
if ( !errorMsg.empty() )
{
Steve Williams
committed
errorMsg = "Invalid value for property " + p->name() + " (" +p->type() + ") \"" + value
Steve Williams
committed
+ "\" : " + errorMsg;
Steve Williams
committed
throw std::invalid_argument(errorMsg);
Steve Williams
committed
}
Russell Taylor
committed
Janik Zikovsky
committed
//-----------------------------------------------------------------------------------------------
/** Checks whether the named property is already in the list of managed property.
Janik Zikovsky
committed
* @param name :: The name of the property (case insensitive)
* @return True if the property is already stored
*/
bool PropertyManager::existsProperty( const std::string& name ) const
{
std::string ucName = name;
std::transform(ucName.begin(), ucName.end(), ucName.begin(), toupper);
auto it = m_properties.find(ucName);
return (it != m_properties.end());
Janik Zikovsky
committed
//-----------------------------------------------------------------------------------------------
* @return True if all properties have a valid value
*/
bool PropertyManager::validateProperties() const
{
bool allValid = true;
for ( PropertyMap::const_iterator it = m_properties.begin(); it != m_properties.end(); ++it )
{
Steve Williams
committed
//check for errors in each property
std::string error = it->second->isValid();
//"" means no error
if ( !error.empty() )
Steve Williams
committed
g_log.error() << "Property \"" << it->first << "\" is not set to a valid value: \"" <<
error << "\"." << std::endl;
Russell Taylor
committed
Gigg, Martyn Anthony
committed
//-----------------------------------------------------------------------------------------------
/**
* Count the number of properties under management
* @returns The number of properties being managed
*/
size_t PropertyManager::propertyCount() const
{
return m_orderedProperties.size();
}
Janik Zikovsky
committed
//-----------------------------------------------------------------------------------------------
Janik Zikovsky
committed
* @param name :: The name of the property (case insensitive)
* @return The value of the named property
* @throw Exception::NotFoundError if the named property is unknown
*/
std::string PropertyManager::getPropertyValue( const std::string &name ) const
{
Property *p = getPointerToProperty(name); // throws NotFoundError if property not in vector
return p->value();
}
Russell Taylor
committed
Gigg, Martyn Anthony
committed
//-----------------------------------------------------------------------------------------------
/** Return the property manager serialized as a string.
*
* The format is propName=value,propName=value,propName=value
* @param withDefaultValues :: If true then the value of default parameters will be included
* @param separator :: character to separate property/value pairs. Default comma.
* @returns A serialized version of the manager
*/
std::string PropertyManager::asString(bool withDefaultValues, char separator) const
Gigg, Martyn Anthony
committed
{
std::ostringstream writer;
const size_t count = propertyCount();
Gigg, Martyn Anthony
committed
for( size_t i = 0; i < count; ++i )
{
Property *p = getPointerToPropertyOrdinal((int)i);
Gigg, Martyn Anthony
committed
if( withDefaultValues || !(p->isDefault()) )
Gigg, Martyn Anthony
committed
{
writer << separator;
writer << p->name() << "=" << p->value();
numAdded++;
Gigg, Martyn Anthony
committed
}
}
return writer.str();
Gigg, Martyn Anthony
committed
}
Janik Zikovsky
committed
//-----------------------------------------------------------------------------------------------
Janik Zikovsky
committed
* @param name :: The name of the property (case insensitive)
* @return A pointer to the named property
* @throw Exception::NotFoundError if the named property is unknown
*/
Property* PropertyManager::getPointerToProperty( const std::string &name ) const
{
std::string ucName = name;
std::transform(ucName.begin(), ucName.end(), ucName.begin(), toupper);
PropertyMap::const_iterator it = m_properties.find(ucName);
if (it != m_properties.end())
{
return it->second;
}
throw Exception::NotFoundError("Unknown property", name);
}
Russell Taylor
committed
Janik Zikovsky
committed
//-----------------------------------------------------------------------------------------------
/** Get a property by name
Janik Zikovsky
committed
* @param name :: The name of the property (case insensitive)
Janik Zikovsky
committed
* @return A pointer to the named property; NULL if not found
*/
Property* PropertyManager::getPointerToPropertyOrNull( const std::string &name ) const
{
std::string ucName = name;
std::transform(ucName.begin(), ucName.end(), ucName.begin(), toupper);
PropertyMap::const_iterator it = m_properties.find(ucName);
if (it != m_properties.end())
{
return it->second;
}
return NULL;
}
Janik Zikovsky
committed
//-----------------------------------------------------------------------------------------------
Janik Zikovsky
committed
* @param index :: The name of the property (case insensitive)
* @return A pointer to the named property
* @throw std::runtime_error if the property index is too high
*/
Property* PropertyManager::getPointerToPropertyOrdinal( const int& index) const
{
Russell Taylor
committed
if ( index < static_cast<int>(m_orderedProperties.size()) )
{
return m_orderedProperties[index];
}
throw std::runtime_error("Property index too high");
}
Russell Taylor
committed
Janik Zikovsky
committed
//-----------------------------------------------------------------------------------------------
* The properties will be stored in the order that they were declared.
* @return A vector holding pointers to the list of properties
*/
const std::vector< Property* >& PropertyManager::getProperties() const
{
return m_orderedProperties;
}
Janik Zikovsky
committed
//-----------------------------------------------------------------------------------------------
/** Get the value of a property. Allows you to assign directly to a variable of the property's type
* (if a supported type).
*
* *** This method does NOT work for assigning to an existing std::string.
* In this case you have to use getPropertyValue() instead.
* Note that you can, though, construct a local string variable by writing,
* e.g. std::string s = getProperty("myProperty"). ***
*
Janik Zikovsky
committed
* @param name :: The name of the property
* @return The value of the property. Will be cast to the desired type (if a supported type).
* @throw std::runtime_error If an attempt is made to assign a property to a different type
* @throw Exception::NotFoundError If the property requested does not exist
*/
PropertyManager::TypedValue PropertyManager::getProperty( const std::string &name ) const
{
return TypedValue(*this, name);
}
Russell Taylor
committed
Janik Zikovsky
committed
//-----------------------------------------------------------------------------------------------
Russell Taylor
committed
/** Removes the property from properties map.
Janik Zikovsky
committed
* @param name :: name of the property to be removed.
* @param delproperty :: if true, delete the named property
Russell Taylor
committed
*/
void PropertyManager::removeProperty(const std::string &name, const bool delproperty)
Russell Taylor
committed
{
Janik Zikovsky
committed
{
//remove it
Property* prop=getPointerToProperty(name);
Janik Zikovsky
committed
std::string key = name;
std::transform(key.begin(), key.end(), key.begin(), toupper);
Gigg, Martyn Anthony
committed
m_properties.erase(key);
std::vector<Property*>::iterator itr;
itr=find(m_orderedProperties.begin(),m_orderedProperties.end(),prop);
m_orderedProperties.erase(itr);
if (delproperty){
delete prop;
}
Gigg, Martyn Anthony
committed
//-----------------------------------------------------------------------------------------------
/**
* Clears the whole property map
*/
void PropertyManager::clear()
{
m_orderedProperties.clear();
for ( PropertyMap::iterator it = m_properties.begin(); it != m_properties.end(); ++it )
{
delete it->second;
}
m_properties.clear();
}