Skip to content
Snippets Groups Projects
PropertyManager.cpp 8.91 KiB
Newer Older
//----------------------------------------------------------------------
// Includes
//----------------------------------------------------------------------
#include "MantidKernel/PropertyManager.h"
#include "MantidKernel/Exception.h"
Nick Draper's avatar
Nick Draper committed
#include <boost/tokenizer.hpp>
Nick Draper's avatar
Nick Draper committed
#include <algorithm>

namespace Mantid
{
Nick Draper's avatar
Nick Draper committed
  namespace Kernel
  {
Nick Draper's avatar
Nick Draper committed
    // Get a reference to the logger
    Logger& PropertyManager::g_log = Logger::get("PropertyManager");
Nick Draper's avatar
Nick Draper committed
    /// Default constructor
    PropertyManager::PropertyManager() :
    m_properties(),
      m_orderedProperties()
    {
    }
Nick Draper's avatar
Nick Draper committed
    PropertyManager::~PropertyManager()
    {
      /*for ( PropertyMap::iterator it = m_properties.begin(); it != m_properties.end(); ++it )
Nick Draper's avatar
Nick Draper committed
      {
        delete it->second;
Nick Draper's avatar
Nick Draper committed
    }
Dickon Champion's avatar
Dickon Champion committed

Nick Draper's avatar
Nick Draper committed
    /** Add a property to the list of managed properties
    *  @param p The property object to add
    *  @param doc A description of the property that may be displayed to users
Nick Draper's avatar
Nick Draper committed
    *  @throw Exception::ExistsError if a property with the given name already exists
    *  @throw std::invalid_argument  if the property declared has an empty name.
    */
    void PropertyManager::declareProperty( Property *p, const std::string &doc )
Nick Draper's avatar
Nick Draper committed
    {
      // Get the name of the property and don't permit empty names
      std::string key = p->name();
Nick Draper's avatar
Nick Draper committed
      {
Nick Draper's avatar
Nick Draper committed
        throw std::invalid_argument("An empty property name is not permitted");
      }
Dickon Champion's avatar
Dickon Champion committed

Nick Draper's avatar
Nick Draper committed
      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 );
Nick Draper's avatar
Nick Draper committed
      }
Nick Draper's avatar
Nick Draper committed
    }

    /** Set the ordered list of properties by one string of values.
    *  @param propertiesArray The list of property values
    *  @throws invalid_argument if error in parameters
Nick Draper's avatar
Nick Draper committed
    */
    // Care will certainly be required in the calling of this function or it could all go horribly wrong!
    void PropertyManager::setProperties( const std::string &propertiesArray )
Nick Draper's avatar
Nick Draper committed
    {
        // 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)
		{
			boost::char_separator<char> sep2("=");
			tokenizer properties(*it,sep2);
			std::vector<std::string> property(properties.begin(), properties.end());
			// Call the appropriate setProperty method on the algorithm
			if ( property.size() == 2)
			{
				setPropertyValue(property[0],property[1]);
			}
			else if ( property.size() == 1)
			{
			// This is for a property with no value. Not clear that we will want such a thing.
				setPropertyOrdinal(index,property[0]);
			}
			// Throw if there's a problem with the string
			else
			{
				throw std::invalid_argument("Misformed properties string");
			}
			index++;
		}  
Nick Draper's avatar
Nick Draper committed
    }
Nick Draper's avatar
Nick Draper committed
    /** Set the value of a property by string
    *  N.B. bool properties must be set using 1/0 rather than true/false
    *  @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
      std::string errorMsg = p->setValue(value);
      if ( !errorMsg.empty() ) 
      {
        errorMsg = "Invalid value for property " + p->name() + " (" +p->type() + ") \"" + value
          + "\": " + errorMsg;
        throw std::invalid_argument(errorMsg);
      }
Nick Draper's avatar
Nick Draper committed
    }
Nick Draper's avatar
Nick Draper committed
    /** Set the value of a property by an index
    *  N.B. bool properties must be set using 1/0 rather than true/false
    *  @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
Nick Draper's avatar
Nick Draper committed
    */
    void PropertyManager::setPropertyOrdinal( const int& index, const std::string &value )
    {
      Property *p = getPointerToPropertyOrdinal(index);   // throws runtime_error if property not in vector
      std::string errorMsg = p->setValue(value);
      if ( !errorMsg.empty() ) 
      {
        errorMsg = "Invalid value for property " + p->name() + " (" +p->type() + ") \"" + value
Nick Draper's avatar
Nick Draper committed
    }
Nick Draper's avatar
Nick Draper committed
    /** Checks whether the named property is already in the list of managed property.
    *  @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
    {
Nick Draper's avatar
Nick Draper committed
      {
        getPointerToProperty(name);
        return true;
      }
      catch (Exception::NotFoundError e)
      {
        return false;
      }
    }
Nick Draper's avatar
Nick Draper committed
    /** Validates all the properties in the collection
    *  @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 )
      {
        //check for errors in each property
        std::string error = it->second->isValid();
        //"" means no error
        if ( !error.empty() )
Nick Draper's avatar
Nick Draper committed
        {
          g_log.error() << "Property \"" << it->first << "\" is not set to a valid value: \"" <<
            error << "\"." << std::endl;
Nick Draper's avatar
Nick Draper committed
          allValid=false;
        }
      }
Nick Draper's avatar
Nick Draper committed
    }
Nick Draper's avatar
Nick Draper committed
    /** Get the value of a property as a string
    *  @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();
    }
Nick Draper's avatar
Nick Draper committed
    /** Get a property by name
    *  @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);
    }
Nick Draper's avatar
Nick Draper committed
    /** Get a property by an index
    *  @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
    {
Nick Draper's avatar
Nick Draper committed
      if ( index < static_cast<int>(m_orderedProperties.size()) )
      {
        return m_orderedProperties[index];
      }
      throw std::runtime_error("Property index too high");
    }
Nick Draper's avatar
Nick Draper committed
    /** Get the list of managed properties.
    *  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;
    }
Nick Draper's avatar
Nick Draper committed
    /** Get the value of a property. Allows you to assign directly to a variable of the property's type
    *  (if a supported type).
Nick Draper's avatar
Nick Draper committed
    *  *** 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"). ***
Nick Draper's avatar
Nick Draper 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);
    }
Nick Draper's avatar
Nick Draper committed
  } // namespace Kernel
} // namespace Mantid