Skip to content
Snippets Groups Projects
EnabledWhenProperty.cpp 7.93 KiB
Newer Older
// Mantid Repository : https://github.com/mantidproject/mantid
//
// Copyright © 2018 ISIS Rutherford Appleton Laboratory UKRI,
//     NScD Oak Ridge National Laboratory, European Spallation Source
//     & Institut Laue - Langevin
// SPDX - License - Identifier: GPL - 3.0 +
#include "MantidKernel/Exception.h"
#include "MantidKernel/IPropertyManager.h"
#include "MantidKernel/Property.h"
#include <boost/lexical_cast.hpp>
#include <stdexcept>
namespace Mantid {
namespace Kernel {
 * @param otherPropName :: Name of the OTHER property that we will check.
 * @param when :: Criterion to evaluate
 * @param value :: For the IS_EQUAL_TO or IS_NOT_EQUAL_TO condition, the value
 * (as string) to check for
 */
EnabledWhenProperty::EnabledWhenProperty(const std::string &otherPropName,
                                         const ePropertyCriterion when,
                                         const std::string &value)
  m_propertyDetails = std::make_shared<PropertyDetails>(
      PropertyDetails{otherPropName, when, value});
/** Multiple conditions constructor - takes two enable when property
 * objects and returns the product of of the with the specified
 * logic operator
 *
 * @param conditionOne :: First EnabledWhenProperty object to use
 * @param conditionTwo :: Second EnabledWhenProperty object to use
 * @param logicOperator :: The logic operator to apply across both
 * conditions
 */
EnabledWhenProperty::EnabledWhenProperty(
    const EnabledWhenProperty &conditionOne,
    const EnabledWhenProperty &conditionTwo, eLogicOperator logicOperator)
    : // This method allows the Python interface to easily construct these
      // objects
      // Copy the object then forward onto our move constructor
David Fairbrother's avatar
David Fairbrother committed
      EnabledWhenProperty(std::make_shared<EnabledWhenProperty>(conditionOne),
                          std::make_shared<EnabledWhenProperty>(conditionTwo),
                          logicOperator) {}
/** Multiple conditions constructor - takes two shared pointers to
 * EnabledWhenProperty objects and returns the product of them
 * with the specified logic operator.
 *
 * @param conditionOne :: First EnabledWhenProperty object to use
 * @param conditionTwo :: Second EnabledWhenProperty object to use
 * @param logicOperator :: The logic operator to apply across both
 *conditions
 *
 */
EnabledWhenProperty::EnabledWhenProperty(
    std::shared_ptr<EnabledWhenProperty> &&conditionOne,
    std::shared_ptr<EnabledWhenProperty> &&conditionTwo,
    eLogicOperator logicOperator)
  // Initialise with POD compatible syntax
  m_comparisonDetails =
      std::make_shared<ComparisonDetails<EnabledWhenProperty>>(
          ComparisonDetails<EnabledWhenProperty>{
              std::move(conditionOne), std::move(conditionTwo), logicOperator});
EnabledWhenProperty::EnabledWhenProperty(const EnabledWhenProperty &other)
    : IPropertySettings(), m_propertyDetails{other.m_propertyDetails},
      m_comparisonDetails{other.m_comparisonDetails} {}
 * Checks if the user specified combination of enabled criterion
 * returns a true or false value
 *
 * @param algo :: The algorithm containing the property to check
 * @return :: true if user specified combination was true, else false.
 * @throw ::  If any problems was found
 */
bool EnabledWhenProperty::checkComparison(const IPropertyManager *algo) const {
  const auto &comparison = m_comparisonDetails;
  const auto &objectOne = comparison->conditionOne;
  const auto &objectTwo = comparison->conditionTwo;

  switch (comparison->logicOperator) {
  case AND:
    return objectOne->isEnabled(algo) && objectTwo->isEnabled(algo);
    break;
  case OR:
    return objectOne->isEnabled(algo) || objectTwo->isEnabled(algo);
    break;
  case XOR:
    return objectOne->isEnabled(algo) ^ objectTwo->isEnabled(algo);
    break;
  default:
    throw std::runtime_error("Unknown logic operator in EnabledWhenProperty");
  }
}

/**
 * Does the validator fulfill the criterion based on the
 * other property values?
 * @param algo :: The pointer to the algorithm to check the property values of
 * @return :: True if the criteria are met else false
 * @throw :: Throws on any problems (e.g. property missing from algorithm)
 */
bool EnabledWhenProperty::checkCriterion(const IPropertyManager *algo) const {

  // Value of the other property
  const std::string propValue = getPropertyValue(algo);
  // This is safe as long as getPropertyValue (which checks) has been called
  // already
  auto prop = algo->getPointerToProperty(m_propertyDetails->otherPropName);

  // OK, we have the property. Check the condition
  switch (m_propertyDetails->criterion) {
  case IS_DEFAULT:
    return prop->isDefault();
  case IS_NOT_DEFAULT:
    return !prop->isDefault();
  case IS_EQUAL_TO:
    return (propValue == m_propertyDetails->value);
  case IS_NOT_EQUAL_TO:
    return (propValue != m_propertyDetails->value);
  case IS_MORE_OR_EQ: {
    int check = boost::lexical_cast<int>(m_propertyDetails->value);
    int iPropV = boost::lexical_cast<int>(propValue);
    return (iPropV >= check);
  }
  default:
    // Unknown criterion
    std::string errString = "The EnabledWhenProperty criterion set"
                            " for the following property ";
    errString += m_propertyDetails->otherPropName;
    errString += " is unknown";
    throw std::invalid_argument(errString);
 * Checks the algorithm given is in a valid state and the property
 * exists then proceeds to try to get the value associated
 *
 * @param algo :: The pointer to the algorithm to process
 * @return :: The value contained by said property
 * @throw :: Throws if anything is wrong with the property or algorithm
 */
std::string
EnabledWhenProperty::getPropertyValue(const IPropertyManager *algo) const {
  // Find the property
  if (algo == nullptr)
    throw std::runtime_error(
        "Algorithm properties passed to EnabledWhenProperty was null");

  Property *prop = nullptr;
  try {
    prop = algo->getPointerToProperty(m_propertyDetails->otherPropName);
  } catch (Exception::NotFoundError &) {
    prop = nullptr; // Ensure we still have null pointer
  }
  if (!prop)
    throw std::runtime_error("Property " + m_propertyDetails->otherPropName +
                             " was not found in EnabledWhenProperty");
  return prop->value();
 * Returns whether the property should be enabled or disabled based
 * on the property conditions
 *
 * @param algo :: The algorithm containing the property
 * @return :: True if enabled when conditions matched, else false
 * @throw :: Throws on any error (e.g. missing property)
 */
bool EnabledWhenProperty::isEnabled(const IPropertyManager *algo) const {
  if (m_propertyDetails) {
    return checkCriterion(algo);
  } else if (m_comparisonDetails) {
    return checkComparison(algo);
  } else {
    throw std::runtime_error("Both PropertyDetails and ComparisonDetails were "
                             "null in EnabledWhenProperty");
  }
}

/**
 * Always returns true as EnabledWhenProperty always sets the visibility
 * on while altering whether the property is Enabled or disabled
 *
 * @param algo :: Pointer to the algorithm containing the property
 * @return :: True always
 */
bool EnabledWhenProperty::isVisible(const IPropertyManager *algo) const {
  // VisisbleWhenProperty uses algo so we have to keep it to match interface
  UNUSED_ARG(algo);

/// Does nothing in this case and put here to satisfy the interface.
void EnabledWhenProperty::modify_allowed_values(Property *const /*unused*/) {}
 * Clones the current EnabledWhenProperty object and returns
 * a pointer to the new object. The caller is responsible
 * for deleting this pointer when finished
 *
 * @return Pointer to cloned EnabledWhenProperty object
 */
IPropertySettings *EnabledWhenProperty::clone() const {
  return new EnabledWhenProperty(*this);
} // namespace Mantid