21#include "MantidQtWidgets/Common/QtPropertyBrowser/DoubleDialogEditor.h"
22#include "MantidQtWidgets/Common/QtPropertyBrowser/FilenameDialogEditor.h"
23#include "MantidQtWidgets/Common/QtPropertyBrowser/FormulaDialogEditor.h"
24#include "MantidQtWidgets/Common/QtPropertyBrowser/WorkspaceEditorFactory.h"
28#include "MantidQtWidgets/Common/QtPropertyBrowser/CompositeEditorFactory.h"
29#include "MantidQtWidgets/Common/QtPropertyBrowser/DoubleEditorFactory.h"
30#include "MantidQtWidgets/Common/QtPropertyBrowser/qteditorfactory.h"
31#include "MantidQtWidgets/Common/QtPropertyBrowser/qtpropertymanager.h"
32#include "MantidQtWidgets/Common/QtPropertyBrowser/qttreepropertybrowser.h"
34#include <QApplication>
39#include <QInputDialog>
45#include <QSignalMapper>
50#include <boost/lexical_cast.hpp>
57const char *globalOptionName =
"Global";
59const std::regex PREFIX_REGEX(
"(^[f][0-9](.*))");
60inline bool variableIsPrefixed(std::string
const &
name) {
return std::regex_match(
name, PREFIX_REGEX); }
62std::string insertPrefix(std::string
const ¶m) {
63 auto const parameterName = QString::fromStdString(param);
64 return parameterName.left(parameterName.indexOf(
".") + 1).toStdString() +
"f0." +
65 parameterName.right(parameterName.size() - parameterName.indexOf(
".") - 1).toStdString();
68std::string addPrefix(std::string
const ¶m) {
return "f0." + param; }
70std::string removeEmbeddedPrefix(std::string
const ¶m) {
71 if (variableIsPrefixed(param)) {
72 const auto paramSplit = QString::fromStdString(param).split(
".");
73 return paramSplit[0].toStdString() +
"." + paramSplit[paramSplit.size() - 1].toStdString();
79std::string removePrefix(std::string
const ¶m) {
80 if (variableIsPrefixed(param)) {
81 const auto paramSplit = QString::fromStdString(param).split(
".");
82 return paramSplit[paramSplit.size() - 1].toStdString();
88bool containsOneOf(std::string
const &str, std::string
const &delimiters) {
89 return !str.empty() && str.find_first_of(delimiters) != std::string::npos;
94const std::vector<std::string> REQUIRESRECONSTRUCTIONATTRIBUTES = {
"n",
"Formula",
"Workspace"};
107 :
IFunctionView(parent), m_multiDataset(multi), m_multiDomainFunctionPrefix(),
108 m_allowedCategories(
std::move(categories)), m_selectFunctionDialog(nullptr)
115 QVBoxLayout *layout =
new QVBoxLayout(
this);
116 layout->setContentsMargins(0, 0, 0, 0);
145 options << globalOptionName;
147 m_browser =
new QtTreePropertyBrowser(
this, options);
168 QtSpinBoxFactory *spinBoxFactory =
new QtSpinBoxFactory(
this);
169 DoubleEditorFactory *dblEditorFactory =
new DoubleEditorFactory(
this);
170 ParameterEditorFactory *paramEditorFactory =
new ParameterEditorFactory(
this);
172 QtAbstractEditorFactory<ParameterPropertyManager> *parameterEditorFactory(
nullptr);
175 auto compositeFactory =
new CompositeEditorFactory<ParameterPropertyManager>(
this,
m_doubleEditorFactory);
176 compositeFactory->setSecondaryFactory(globalOptionName, paramEditorFactory);
177 parameterEditorFactory = compositeFactory;
182 parameterEditorFactory = paramEditorFactory;
185 QtLineEditFactory *lineEditFactory =
new QtLineEditFactory(
this);
186 QtCheckBoxFactory *checkBoxFactory =
new QtCheckBoxFactory(
this);
188 FormulaDialogEditorFactory *formulaDialogEditFactory =
new FormulaDialogEditorFactory(
this);
189 WorkspaceEditorFactory *workspaceEditorFactory =
new WorkspaceEditorFactory(
this);
206 m_browser->setContextMenuPolicy(Qt::CustomContextMenu);
207 connect(
m_browser, SIGNAL(customContextMenuRequested(
const QPoint &)),
this, SLOT(
popupMenu(
const QPoint &)));
208 connect(
m_browser, SIGNAL(optionChanged(QtProperty *,
const QString &,
bool)),
this,
228 m_browser->setFocusPolicy(Qt::StrongFocus);
307 ap.
prop = subproperty;
308 if (parent ==
nullptr) {
311 parent->addSubProperty(subproperty);
312 auto items =
m_browser->items(subproperty);
313 if (items.isEmpty()) {
314 throw std::runtime_error(
"Unexpected error in FunctionTreeView [1]");
334 auto children = prop->subProperties();
335 foreach (QtProperty *child, children) {
345 for (
auto it =
m_ties.begin(); it !=
m_ties.end(); ++it) {
346 if (it.value().tieProp == prop) {
355 auto &cp = it.value();
356 if (cp.lower == prop) {
363 }
else if (cp.upper == prop) {
376 ap.
parent->removeSubProperty(prop);
391 if (parent &&
dynamic_cast<QtAbstractPropertyManager *
>(
m_functionManager) != parent->propertyManager()) {
392 throw std::runtime_error(
"Unexpected error in FunctionTreeView [2]");
394 QtProperty *prop =
m_functionManager->addProperty(QString::fromStdString(funName));
406 std::string
const ¶mDesc,
double paramValue) {
408 if (!parent ||
dynamic_cast<QtAbstractPropertyManager *
>(
m_functionManager) != parent->propertyManager()) {
409 throw std::runtime_error(
"Unexpected error in FunctionTreeView [3]");
411 QtProperty *prop =
m_parameterManager->addProperty(QString::fromStdString(parameterName));
419 prop->setOption(globalOptionName,
false);
430 auto children = prop->subProperties();
431 foreach (QtProperty *child, children) {
455 auto cf = std::dynamic_pointer_cast<Mantid::API::CompositeFunction>(parentFun);
457 throw std::logic_error(
"FunctionTreeView: CompositeFunction is expected for addFunction");
460 cf->addFunction(fun);
461 }
catch (
const std::exception &e) {
462 QMessageBox::warning(
this,
"Mantid - Warning", QString(
"Cannot Add function:\n\n%1").arg(e.what()));
483 throw std::runtime_error(
"Unexpected error in FunctionTreeView [4]");
490 QtProperty *prop =
nullptr;
491 if (
m_attName.indexOf(
"FileName") != -1) {
496 }
else if (
m_attName.indexOf(
"Formula") != -1) {
501 }
else if (
m_attName.indexOf(
"Workspace") != -1) {
526 prop->setEnabled(i < std::numeric_limits<int>::max());
551 QString parName =
"value[%1]";
552 for (
size_t i = 0; i < v.size(); ++i) {
559 sizeProp->setEnabled(
false);
581 void apply(std::string &str)
const override {
582 QString attName =
m_prop->propertyName();
583 if (attName ==
"FileName") {
585 }
else if (attName ==
"Formula") {
587 }
else if (attName ==
"Workspace") {
600 void apply(std::vector<double> &v)
const override {
603 throw std::runtime_error(
"FunctionTreeView: empty vector attribute group.");
604 int n = members.size() - 1;
610 for (
int i = 0; i <
n; ++i) {
629 return att.
apply(cap);
644 const std::size_t &parentIndex) {
649 auto attributeNames = fun->getAttributeNames();
650 for (
const auto &att : attributeNames) {
651 if (!variableIsPrefixed(att)) {
656 auto cf = std::dynamic_pointer_cast<Mantid::API::CompositeFunction>(fun);
659 for (
size_t i = 0; i < cf->nFunctions(); ++i) {
664 for (
size_t i = 0; i < fun->nParams(); ++i) {
665 auto name = fun->parameterName(i);
666 auto desc = fun->parameterDescription(i);
667 double value = fun->getParameter(i);
670 if (!fun->isActive(i))
675 if (
const auto constraint = fun->getConstraint(i)) {
694 const std::string ¶meterName,
const std::size_t ¶meterIndex,
696 if (
const auto tie = function->getTie(parameterIndex)) {
699 auto tieAdded =
false;
704 addTieProperty(property, QString::number(function->getParameter(parameterIndex)).toStdString());
719 for (
auto i = 0u; i < composite->nParams(); ++i) {
721 if (fullName == composite->parameterName(i)) {
722 if (
const auto tie = composite->getTie(i)) {
723 const auto tieStr = QString::fromStdString(tie->asString());
724 addTieProperty(property, tieStr.mid(tieStr.indexOf(
'=') + 1).toStdString());
744 const std::size_t &parentIndex) {
748 auto const fullName =
getFullParameterName(parameterName, parentComposite ?
static_cast<int>(parentIndex) : -1);
751 [&fullName](
const auto &globalTie) { return fullName == globalTie.m_parameter; });
764 indexProperty->setEnabled(
false);
788 QString
index =
"fff";
790 ip->setEnabled(
false);
803 if (prop ==
nullptr) {
809 auto children = prop->subProperties();
811 foreach (QtProperty *child, children) {
826 if (props.isEmpty()) {
833 QtProperty *prop = props[0];
842 return prop &&
dynamic_cast<QtAbstractPropertyManager *
>(
m_functionManager) == prop->propertyManager();
851 dynamic_cast<QtAbstractPropertyManager *
>(
m_formulaManager) == prop->propertyManager() ||
852 dynamic_cast<QtAbstractPropertyManager *
>(
m_filenameManager) == prop->propertyManager() ||
853 dynamic_cast<QtAbstractPropertyManager *
>(
m_workspaceManager) == prop->propertyManager());
869 return prop &&
dynamic_cast<QtAbstractPropertyManager *
>(
m_attributeIntManager) == prop->propertyManager();
877 return prop &&
dynamic_cast<QtAbstractPropertyManager *
>(
m_attributeBoolManager) == prop->propertyManager();
902 return prop &&
dynamic_cast<QtAbstractPropertyManager *
>(
m_parameterManager) == prop->propertyManager();
915 return prop &&
dynamic_cast<QtAbstractPropertyManager *
>(
m_indexManager) == prop->propertyManager();
926 auto props = prop->subProperties();
929 const auto it = std::find_if(props.cbegin(), props.cend(), [&](
const auto &prop) { return isIndex(prop); });
930 if (it != props.cend()) {
946 return getIndex(prop) + prop->propertyName().toStdString();
949 return getIndex(prop) + parent->propertyName().toStdString();
958 return getIndex(prop) + prop->propertyName().toStdString();
960 throw std::logic_error(
"QtProperty " + prop->propertyName().toStdString() +
" is not an attribute property.");
991 throw std::runtime_error(
"FunctionTreeView: null property pointer");
1001 QtProperty *tieProp =
m_tieManager->addProperty(
"Tie");
1012 m_ties.insert(funProp, atie);
1022 if (!
isNumber(tie) && !containsOneOf(tie,
"="))
1038 if (compositeIndex != -1)
1040 fullParameterName += parameter;
1041 return fullParameterName;
1051 const auto children = prop->subProperties();
1052 return std::any_of(children.cbegin(), children.cend(),
1053 [](
const auto child) { return child->propertyName() ==
"Tie"; });
1061 return prop &&
dynamic_cast<QtAbstractPropertyManager *
>(
m_tieManager) == prop->propertyManager();
1071 if (prop->propertyName() ==
"Tie") {
1074 const auto children = prop->subProperties();
1076 std::find_if(children.cbegin(), children.cend(), [](
const auto child) { return child->propertyName() ==
"Tie"; });
1077 if (it != children.cend()) {
1089 std::string
const &constraint) {
1093 if (parts.first.empty())
1095 auto lowerBound = parts.second.first;
1096 auto upperBound = parts.second.second;
1104 if (!lowerBound.empty()) {
1107 ac.
lower = apLower.prop;
1111 if (!upperBound.empty()) {
1114 ac.
upper = apUpper.prop;
1129 return prop &&
dynamic_cast<QtAbstractPropertyManager *
>(
m_constraintManager) == prop->propertyManager();
1145 const auto props = prop->subProperties();
1146 return std::any_of(props.cbegin(), props.cend(), [&](
const auto &p) {
1147 return dynamic_cast<QtAbstractPropertyManager *>(m_constraintManager) == p->propertyManager() &&
1148 p->propertyName() ==
"LowerBound";
1159 const auto props = prop->subProperties();
1160 return std::any_of(props.cbegin(), props.cend(), [&](
const auto &p) {
1161 return dynamic_cast<QtAbstractPropertyManager *>(m_constraintManager) == p->propertyManager() &&
1162 p->propertyName() ==
"UpperBound";
1168 const double &upperBound)
const {
1170 std::string constraint;
1172 constraint += QString::number(lowerBound).toStdString() +
"<";
1174 constraint += parameterName;
1176 constraint +=
"<" + QString::number(upperBound).toStdString();
1187 QMenu context(
this);
1189 if (!QApplication::clipboard()->text().isEmpty()) {
1192 if (!
m_browser->properties().isEmpty()) {
1195 context.exec(QCursor::pos());
1198 QtProperty *prop = item->property();
1200 QMenu context(
this);
1202 Mantid::API::FunctionFactory::Instance().createFunction(prop->propertyName().toStdString());
1203 auto cf = std::dynamic_pointer_cast<Mantid::API::CompositeFunction>(fun);
1208 if (!QApplication::clipboard()->text().isEmpty()) {
1211 if (!
m_browser->properties().isEmpty()) {
1215 context.exec(QCursor::pos());
1217 QMenu context(
this);
1226 if (!hasLower && !hasUpper) {
1227 QMenu *constraintMenu =
new QMenu(
"Constraints",
this);
1231 context.addMenu(constraintMenu);
1235 context.exec(QCursor::pos());
1237 QMenu context(
this);
1239 context.exec(QCursor::pos());
1249 QtProperty *prop =
nullptr;
1251 prop = item->property();
1259 if (!
top.isEmpty()) {
1277 if (result != QDialog::Accepted) {
1282 if (newFunction.isEmpty())
1286 auto f = Mantid::API::FunctionFactory::Instance().createFunction(newFunction.toStdString());
1294 Mantid::API::FunctionFactory::Instance().createFunction(prop->propertyName().toStdString());
1295 auto cf = std::dynamic_pointer_cast<Mantid::API::CompositeFunction>(fun);
1305 std::transform(globalParameters.begin(), globalParameters.end(), globalParameters.begin(),
1307 cf->addFunction(f0);
1328 std::string attName = prop->propertyName().toStdString();
1334 }
catch (std::exception &expt) {
1335 QMessageBox::critical(
this,
"Mantid - Error",
1336 "Cannot set attribute " + QString::fromStdString(attName) +
" of function " +
1337 prop->propertyName() +
":\n\n" + QString::fromStdString(expt.what()));
1347 if (prop ==
nullptr) {
1349 if (props.isEmpty())
1357 auto fun = Mantid::API::FunctionFactory::Instance().createFunction(prop->propertyName().toStdString());
1358 auto cf = std::dynamic_pointer_cast<Mantid::API::CompositeFunction>(fun);
1360 auto children = prop->subProperties();
1361 foreach (QtProperty *child, children) {
1374 auto children = prop->subProperties();
1375 foreach (QtProperty *child, children) {
1378 }
else if (!attributesOnly &&
isParameter(child)) {
1379 fun->setParameter(child->propertyName().toStdString(),
getParameter(child));
1391 auto from =
m_ties.lowerBound(prop);
1392 auto to =
m_ties.upperBound(prop);
1395 for (
auto it = from; it != to; ++it) {
1396 auto const tie = (it->paramName +
"=" +
m_tieManager->value(it.value().tieProp).toStdString());
1400 failedTies << it.value().tieProp;
1401 g_log.
warning() <<
"Invalid tie has been removed: " << tie << std::endl;
1405 foreach (QtProperty *p, failedTies) {
1414 for (
auto it = from; it != to; ++it) {
1416 const auto &localParam = it.value();
1420 fun->addConstraints(constraint);
1449 auto children = prop->subProperties();
1450 const auto it = std::find_if(children.cbegin(), children.cend(), [&](
auto &child) {
1451 return isParameter(child) && child->propertyName().toStdString() == name;
1453 if (it != children.cend()) {
1484 QString
value = QString::fromStdString(valueAsStdStr);
1488 auto attName = prop->propertyName();
1489 if (attName ==
"FileName") {
1491 }
else if (attName ==
"Formula") {
1493 }
else if (attName ==
"Workspace") {
1547 throw std::runtime_error(
"Unknown function attribute " + attrName);
1555 const auto children = prop->subProperties();
1556 const auto it = std::find_if(children.cbegin(), children.cend(), [&](
const auto &child) {
1557 return isParameter(child) && child->propertyName().toStdString() == name;
1559 if (it != children.cend()) {
1563 std::string message =
"Unknown function parameter " + parameterName +
1564 "\n\n This may happen if there is a CompositeFunction "
1565 "containing only one function.";
1566 throw std::runtime_error(message);
1571 const QtProperty *prop;
1573 if (!variableIsPrefixed(attributeName)) {
1580 const auto children = prop->subProperties();
1581 const auto it = std::find_if(children.cbegin(), children.cend(), [&](
const auto &child) {
1582 return isAttribute(child) && child->propertyName().toStdString() == name;
1584 if (it != children.cend()) {
1587 std::string message =
"Unknown function attribute " + attributeName;
1588 throw std::runtime_error(message);
1595 std::find_if(
m_ties.cbegin(),
m_ties.cend(), [&prop](
const auto &tie) { return tie.tieProp == prop; });
1596 if (itProp !=
m_ties.cend())
1597 return (*itProp).paramProp;
1600 return (constraint.lower == prop || constraint.upper == prop);
1603 return (*itConstr).paramProp;
1604 throw std::logic_error(
"QtProperty " + prop->propertyName().toStdString() +
1605 " is not a child of a property for any function parameter.");
1615 QtProperty *prop = item->property();
1618 auto const functionString =
getFunction(prop)->asString();
1619 auto const functionIndex =
getIndex(prop);
1629 if (!props.isEmpty()) {
1634 auto topProp = props[0];
1635 auto cf = std::dynamic_pointer_cast<Mantid::API::CompositeFunction>(
getFunction(topProp));
1641 if (cf->nFunctions() == 1 && cf->name() ==
"CompositeFunction") {
1644 auto func =
getFunction(props[0]->subProperties()[1]);
1645 std::transform(globalParameters.begin(), globalParameters.end(), globalParameters.begin(),
1667 QtProperty *prop = item->property();
1670 auto tie = QString::number(
getParameter(prop)).toStdString();
1677 const auto children = prop->subProperties();
1678 const auto it = std::find_if(children.cbegin(), children.cend(),
1679 [](
const auto &child) { return child->propertyName() ==
"Tie"; });
1680 if (it != children.cend()) {
1693 QtProperty *prop = item->property();
1710 QtProperty *prop = item->property();
1715 auto tie = QInputDialog::getText(
this,
"Add a tie",
"Tie:", QLineEdit::Normal,
"", &ok).toStdString();
1716 if (ok && !tie.empty()) {
1721 QMessageBox::critical(
this,
"Mantid - Error",
"Syntax errors found in tie: " + QString::fromStdString(tie));
1722 }
catch (std::exception &e) {
1723 QMessageBox::critical(
this,
"Mantid - Error", QString::fromLatin1(
"Errors found in tie: ") + e.what());
1732 auto funStr = QApplication::clipboard()->text().toStdString();
1736 auto fun = Mantid::API::FunctionFactory::Instance().createInitialized(funStr);
1743 QMessageBox::warning(
this,
"Mantid - Warning",
1744 "Text in the clipboard isn't a function definition"
1745 " or contains errors.");
1761 QtProperty *prop = item->property();
1764 std::string functionIndex,
name;
1779 QtProperty *prop = item->property();
1783 std::string functionIndex,
name;
1785 auto const constraint =
1786 QString::number(val * 0.9).toStdString() +
"<" +
name +
"<" + QString::number(val * 1.1).toStdString();
1798 QtProperty *prop = item->property();
1802 std::string functionIndex,
name;
1804 auto const constraint =
1805 QString::number(val * 0.5).toStdString() +
"<" +
name +
"<" + QString::number(val * 1.5).toStdString();
1811 auto props = prop->subProperties();
1812 foreach (QtProperty *p, props) {
1826 QtProperty *prop = item->property();
1840 QtProperty *prop = item->property();
1847 std::string functionIndex, constraint;
1849 if (!constraint.empty()) {
1860 QtProperty *prop = item->property();
1876 for (
auto const *p : prop->subProperties()) {
1877 if (p->propertyName() ==
"LowerBound")
1879 if (p->propertyName() ==
"UpperBound")
1883 std::string functionIndex,
name;
1887 return std::make_pair(
"",
"");
1901 if (std::find(REQUIRESRECONSTRUCTIONATTRIBUTES.begin(), REQUIRESRECONSTRUCTIONATTRIBUTES.end(),
1902 removePrefix(attributeName)) != REQUIRESRECONSTRUCTIONATTRIBUTES.end()) {
1920 }
catch (std::exception &expt) {
1921 QMessageBox::critical(
this,
"Mantid - Error", QString::fromStdString(expt.what()));
1931 throw std::logic_error(
"FunctionTreeView: inconsistency in vector "
1932 "properties.\nAttribute property not found.");
1935 throw std::logic_error(
"FunctionTreeView: inconsistency in vector "
1936 "properties.\nFunction property not found.");
1939 throw std::logic_error(
"FunctionTreeView: inconsistency in vector "
1940 "properties.\nFunction undefined.");
1941 auto attName = vectorProp->propertyName().toStdString();
1942 auto attribute = fun->getAttribute(attName).asVector();
1946 if (attribute.size() !=
static_cast<size_t>(newSize)) {
1950 attribute.resize(newSize);
1952 fun->setAttributeValue(attName, attribute);
1966 throw std::runtime_error(
"FunctionTreeView: inconsistency in vector properties.");
1972 if (tieProp && !tieProp->isEnabled()) {
1974 QString newTie = QString(
"%1=%2").arg(prop->propertyName()).arg(
m_parameterManager->value(prop));
1975 if (!newTie.isEmpty()) {
1987 for (
const auto &atie :
m_ties) {
1988 if (atie.tieProp == prop) {
1997 const bool isLower = constr.lower == prop;
1998 const bool isUpper = constr.upper == prop;
1999 if (isLower || isUpper) {
2001 std::string functionIndex, constraint;
2003 if (!constraint.empty()) {
2072 std::optional<std::string> newIndex;
2074 if (
auto item =
m_browser->currentItem()) {
2075 auto prop = item->property();
2090 m_tieManager->setValue(tieProp, QString::fromStdString(tie));
2094 }
else if (tieProp) {
2108 std::vector<std::string> globals;
2110 if (prop.prop->checkOption(globalOptionName)) {
2112 globals.emplace_back(
name);
2120 auto prop = ap.prop;
2121 if (!prop->hasOption(globalOptionName))
2125 auto const isGlobal = std::any_of(globals.cbegin(), globals.cend(), [&](std::string
const &global) {
2126 return m_multiDomainFunctionPrefix + global == parameterName;
2128 prop->setOption(globalOptionName, isGlobal);
2140 return item->treeWidget()->visualItemRect(item);
2147 }
catch (std::exception &) {
2156 }
catch (std::exception &) {
2164 return item->treeWidget()->itemWidget(item, 1);
2165 }
catch (std::exception &) {
double value
The value of the point.
std::map< DeltaEMode::Type, std::string > index
#define UNUSED_ARG(x)
Function arguments are sometimes unused in certain implmentations but are required for documentation ...
double lower
lower and upper bounds on the multiplier, if known
This class is responsible for creating the correct dialog for an algorithm.
void showFitFunctionHelp(const QString &name=QString())
A composite function is a function containing other functions.
Specialised exception for parsing errors.
Attribute is a non-fitting parameter.
T apply(AttributeVisitor< T > &v)
Apply an attribute visitor.
Const version of AttributeVisitor.
This is an interface to a fitting function - a semi-abstarct class.
virtual Attribute getAttribute(const std::string &name) const
Return a value of attribute attName.
virtual void setAttribute(const std::string &name, const Attribute &)
Set a value to attribute attName.
The Logger class is in charge of the publishing messages from the framework through various channels.
void warning(const std::string &msg)
Logs at warning level.
Kernel::Logger g_log("ExperimentInfo")
static logger object
std::shared_ptr< IFunction > IFunction_sptr
shared pointer to the function base class
std::shared_ptr< CompositeFunction > CompositeFunction_sptr
shared pointer to the composite function base class
constexpr double EMPTY_DBL() noexcept
Returns what we consider an "empty" double within a property.
std::string to_string(const wide_integer< Bits, Signed > &n)