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(
const std::string &name) {
return std::regex_match(name, PREFIX_REGEX); }
62QString insertPrefix(
const QString ¶m) {
63 return param.left(param.indexOf(
".") + 1) +
"f0." + param.right(param.size() - param.indexOf(
".") - 1);
66QString addPrefix(
const QString ¶m) {
return "f0." + param; }
68QString removeEmbeddedPrefix(
const QString ¶m) {
69 if (variableIsPrefixed(param.toStdString())) {
70 const auto paramSplit = param.split(
".");
71 return paramSplit[0] +
"." + paramSplit[paramSplit.size() - 1];
77QString removePrefix(
const QString ¶m) {
78 if (variableIsPrefixed(param.toStdString())) {
79 const auto paramSplit = param.split(
".");
80 return paramSplit[paramSplit.size() - 1];
86bool containsOneOf(std::string
const &str, std::string
const &delimiters) {
87 return !str.empty() && str.find_first_of(delimiters) != std::string::npos;
92const std::vector<QString> REQUIRESRECONSTRUCTIONATTRIBUTES = {QString(
"n"), QString(
"Formula")};
105 :
IFunctionView(parent), m_multiDataset(multi), m_multiDomainFunctionPrefix(),
106 m_allowedCategories(
std::move(categories)), m_selectFunctionDialog(nullptr)
113 QVBoxLayout *layout =
new QVBoxLayout(
this);
114 layout->setContentsMargins(0, 0, 0, 0);
143 options << globalOptionName;
145 m_browser =
new QtTreePropertyBrowser(
this, options);
166 QtSpinBoxFactory *spinBoxFactory =
new QtSpinBoxFactory(
this);
168 ParameterEditorFactory *paramEditorFactory =
new ParameterEditorFactory(
this);
170 QtAbstractEditorFactory<ParameterPropertyManager> *parameterEditorFactory(
nullptr);
173 auto compositeFactory =
new CompositeEditorFactory<ParameterPropertyManager>(
this,
m_doubleEditorFactory);
174 compositeFactory->setSecondaryFactory(globalOptionName, paramEditorFactory);
175 parameterEditorFactory = compositeFactory;
180 parameterEditorFactory = paramEditorFactory;
183 QtLineEditFactory *lineEditFactory =
new QtLineEditFactory(
this);
184 QtCheckBoxFactory *checkBoxFactory =
new QtCheckBoxFactory(
this);
186 FormulaDialogEditorFactory *formulaDialogEditFactory =
new FormulaDialogEditorFactory(
this);
187 WorkspaceEditorFactory *workspaceEditorFactory =
new WorkspaceEditorFactory(
this);
204 m_browser->setContextMenuPolicy(Qt::CustomContextMenu);
205 connect(
m_browser, SIGNAL(customContextMenuRequested(
const QPoint &)),
this, SLOT(
popupMenu(
const QPoint &)));
206 connect(
m_browser, SIGNAL(optionChanged(QtProperty *,
const QString &,
bool)),
this,
226 m_browser->setFocusPolicy(Qt::StrongFocus);
305 ap.
prop = subproperty;
306 if (parent ==
nullptr) {
309 parent->addSubProperty(subproperty);
310 auto items =
m_browser->items(subproperty);
311 if (items.isEmpty()) {
312 throw std::runtime_error(
"Unexpected error in FunctionTreeView [1]");
332 auto children = prop->subProperties();
341 for (
auto it =
m_ties.begin(); it !=
m_ties.end(); ++it) {
342 if (it.value().tieProp == prop) {
351 auto &cp = it.value();
352 if (cp.lower == prop) {
359 }
else if (cp.upper == prop) {
372 ap.
parent->removeSubProperty(prop);
387 if (parent &&
dynamic_cast<QtAbstractPropertyManager *
>(
m_functionManager) != parent->propertyManager()) {
388 throw std::runtime_error(
"Unexpected error in FunctionTreeView [2]");
402 const QString ¶mDesc,
double paramValue) {
404 if (!parent ||
dynamic_cast<QtAbstractPropertyManager *
>(
m_functionManager) != parent->propertyManager()) {
405 throw std::runtime_error(
"Unexpected error in FunctionTreeView [3]");
415 prop->setOption(globalOptionName,
false);
426 auto children = prop->subProperties();
449 auto cf = std::dynamic_pointer_cast<Mantid::API::CompositeFunction>(parentFun);
451 throw std::logic_error(
"FunctionTreeView: CompositeFunction is expected for addFunction");
454 cf->addFunction(fun);
455 }
catch (
const std::exception &e) {
456 QMessageBox::warning(
this,
"Mantid - Warning", QString(
"Cannot Add function:\n\n%1").arg(e.what()));
477 throw std::runtime_error(
"Unexpected error in FunctionTreeView [4]");
484 QtProperty *prop =
nullptr;
485 if (
m_attName.indexOf(
"FileName") != -1) {
490 }
else if (
m_attName.indexOf(
"Formula") != -1) {
495 }
else if (
m_attName.indexOf(
"Workspace") != -1) {
544 QString parName =
"value[%1]";
545 for (
size_t i = 0; i < v.size(); ++i) {
552 sizeProp->setEnabled(
false);
574 void apply(std::string &str)
const override {
575 QString attName =
m_prop->propertyName();
576 if (attName ==
"FileName") {
578 }
else if (attName ==
"Formula") {
580 }
else if (attName ==
"Workspace") {
593 void apply(std::vector<double> &v)
const override {
596 throw std::runtime_error(
"FunctionTreeView: empty vector attribute group.");
597 int n = members.size() - 1;
603 for (
int i = 0; i <
n; ++i) {
622 return att.
apply(cap);
637 const std::size_t &parentIndex) {
642 auto attributeNames = fun->getAttributeNames();
643 for (
const auto &att : attributeNames) {
644 if (!variableIsPrefixed(att)) {
645 QString attName = QString::fromStdString(att);
650 auto cf = std::dynamic_pointer_cast<Mantid::API::CompositeFunction>(fun);
653 for (
size_t i = 0; i < cf->nFunctions(); ++i) {
658 for (
size_t i = 0; i < fun->nParams(); ++i) {
659 QString name = QString::fromStdString(fun->parameterName(i));
660 QString desc = QString::fromStdString(fun->parameterDescription(i));
661 double value = fun->getParameter(i);
664 if (!fun->isActive(i))
669 if (
const auto constraint = fun->getConstraint(i)) {
688 const std::string ¶meterName,
const std::size_t ¶meterIndex,
690 if (
const auto tie = function->getTie(parameterIndex)) {
691 addTieProperty(property, QString::fromStdString(tie->asString()));
693 auto tieAdded =
false;
698 addTieProperty(property, QString::number(function->getParameter(parameterIndex)));
713 for (
auto i = 0u; i < composite->nParams(); ++i) {
715 if (fullName == composite->parameterName(i)) {
716 if (
const auto tie = composite->getTie(i)) {
717 const auto tieStr = QString::fromStdString(tie->asString());
738 const std::size_t &parentIndex) {
742 auto const fullName =
getFullParameterName(parameterName, parentComposite ?
static_cast<int>(parentIndex) : -1);
745 [&fullName](
const auto &globalTie) { return fullName == globalTie.m_parameter; });
747 addTieProperty(property, QString::fromStdString((*it).m_tie),
true);
758 indexProperty->setEnabled(
false);
782 QString
index =
"fff";
784 ip->setEnabled(
false);
797 if (prop ==
nullptr) {
803 auto children = prop->subProperties();
805 foreach (QtProperty *child, children) {
820 if (props.isEmpty()) {
827 QtProperty *prop = props[0];
836 return prop &&
dynamic_cast<QtAbstractPropertyManager *
>(
m_functionManager) == prop->propertyManager();
845 dynamic_cast<QtAbstractPropertyManager *
>(
m_formulaManager) == prop->propertyManager() ||
846 dynamic_cast<QtAbstractPropertyManager *
>(
m_filenameManager) == prop->propertyManager() ||
847 dynamic_cast<QtAbstractPropertyManager *
>(
m_workspaceManager) == prop->propertyManager());
863 return prop &&
dynamic_cast<QtAbstractPropertyManager *
>(
m_attributeIntManager) == prop->propertyManager();
871 return prop &&
dynamic_cast<QtAbstractPropertyManager *
>(
m_attributeBoolManager) == prop->propertyManager();
896 return prop &&
dynamic_cast<QtAbstractPropertyManager *
>(
m_parameterManager) == prop->propertyManager();
909 return prop &&
dynamic_cast<QtAbstractPropertyManager *
>(
m_indexManager) == prop->propertyManager();
920 auto props = prop->subProperties();
923 for (
auto it = props.begin(); it != props.end(); ++it) {
941 return getIndex(prop) + prop->propertyName();
944 return getIndex(prop) + parent->propertyName();
953 return getIndex(prop) + prop->propertyName();
955 throw std::logic_error(
"QtProperty " + prop->propertyName().toStdString() +
" is not an attribute property.");
986 throw std::runtime_error(
"FunctionTreeView: null property pointer");
1007 m_ties.insert(funProp, atie);
1017 if (!
isNumber(tie.toStdString()) && !containsOneOf(tie.toStdString(),
"="))
1033 if (compositeIndex != -1)
1035 fullParameterName += parameter;
1036 return fullParameterName;
1046 auto children = prop->subProperties();
1047 foreach (QtProperty *child, children) {
1048 if (child->propertyName() ==
"Tie") {
1060 return prop &&
dynamic_cast<QtAbstractPropertyManager *
>(
m_tieManager) == prop->propertyManager();
1070 if (prop->propertyName() ==
"Tie") {
1073 auto children = prop->subProperties();
1074 foreach (QtProperty *child, children) {
1075 if (child->propertyName() ==
"Tie") {
1088 const QString &constraint) {
1092 if (parts.first.isEmpty())
1094 auto lowerBound = parts.second.first;
1095 auto upperBound = parts.second.second;
1103 if (!lowerBound.isEmpty()) {
1106 ac.
lower = apLower.prop;
1110 if (!upperBound.isEmpty()) {
1113 ac.
upper = apUpper.prop;
1128 return prop &&
dynamic_cast<QtAbstractPropertyManager *
>(
m_constraintManager) == prop->propertyManager();
1144 auto props = prop->subProperties();
1145 if (props.isEmpty())
1147 foreach (QtProperty *p, props) {
1148 if (
dynamic_cast<QtAbstractPropertyManager *
>(
m_constraintManager) == p->propertyManager() &&
1149 p->propertyName() ==
"LowerBound")
1162 auto props = prop->subProperties();
1163 if (props.isEmpty())
1165 foreach (QtProperty *p, props) {
1166 if (
dynamic_cast<QtAbstractPropertyManager *
>(
m_constraintManager) == p->propertyManager() &&
1167 p->propertyName() ==
"UpperBound")
1175 const double &upperBound)
const {
1179 constraint += QString::number(lowerBound) +
"<";
1181 constraint += paramName;
1183 constraint +=
"<" + QString::number(upperBound);
1194 QMenu context(
this);
1196 if (!QApplication::clipboard()->text().isEmpty()) {
1199 if (!
m_browser->properties().isEmpty()) {
1202 context.exec(QCursor::pos());
1205 QtProperty *prop = item->property();
1207 QMenu context(
this);
1210 auto cf = std::dynamic_pointer_cast<Mantid::API::CompositeFunction>(fun);
1215 if (!QApplication::clipboard()->text().isEmpty()) {
1218 if (!
m_browser->properties().isEmpty()) {
1222 context.exec(QCursor::pos());
1224 QMenu context(
this);
1233 if (!hasLower && !hasUpper) {
1234 QMenu *constraintMenu =
new QMenu(
"Constraints",
this);
1238 context.addMenu(constraintMenu);
1242 context.exec(QCursor::pos());
1244 QMenu context(
this);
1246 context.exec(QCursor::pos());
1256 QtProperty *prop =
nullptr;
1258 prop = item->property();
1266 if (!
top.isEmpty()) {
1284 if (result != QDialog::Accepted) {
1289 if (newFunction.isEmpty())
1302 auto cf = std::dynamic_pointer_cast<Mantid::API::CompositeFunction>(fun);
1312 std::transform(globalParameters.begin(), globalParameters.end(), globalParameters.begin(),
1314 cf->addFunction(f0);
1335 std::string attName = prop->propertyName().toStdString();
1341 }
catch (std::exception &expt) {
1342 QMessageBox::critical(
this,
"Mantid - Error",
1343 "Cannot set attribute " + QString::fromStdString(attName) +
" of function " +
1344 prop->propertyName() +
":\n\n" + QString::fromStdString(expt.what()));
1354 if (prop ==
nullptr) {
1356 if (props.isEmpty())
1365 auto cf = std::dynamic_pointer_cast<Mantid::API::CompositeFunction>(fun);
1367 auto children = prop->subProperties();
1368 foreach (QtProperty *child, children) {
1381 auto children = prop->subProperties();
1382 foreach (QtProperty *child, children) {
1385 }
else if (!attributesOnly &&
isParameter(child)) {
1386 fun->setParameter(child->propertyName().toStdString(),
getParameter(child));
1398 auto from =
m_ties.lowerBound(prop);
1399 auto to =
m_ties.upperBound(prop);
1402 for (
auto it = from; it != to; ++it) {
1403 auto const tie = (it->paramName +
"=" +
m_tieManager->value(it.value().tieProp)).toStdString();
1407 failedTies << it.value().tieProp;
1408 g_log.
warning() <<
"Invalid tie has been removed: " << tie << std::endl;
1419 for (
auto it = from; it != to; ++it) {
1421 const auto &localParam = it.value();
1425 fun->addConstraints(constraint.toStdString());
1451 QString
index, name;
1454 auto children = prop->subProperties();
1455 foreach (QtProperty *child, children) {
1456 if (
isParameter(child) && child->propertyName() == name) {
1489 QString
value = QString::fromStdString(valueAsStdStr);
1493 auto attName = prop->propertyName();
1494 if (attName ==
"FileName") {
1496 }
else if (attName ==
"Formula") {
1498 }
else if (attName ==
"Workspace") {
1552 throw std::runtime_error(
"Unknown function attribute " + attrName.toStdString());
1557 QString
index, name;
1560 auto children = prop->subProperties();
1561 foreach (QtProperty *child, children) {
1562 if (
isParameter(child) && child->propertyName() == name) {
1567 std::string message =
"Unknown function parameter " + paramName.toStdString() +
1568 "\n\n This may happen if there is a CompositeFunction "
1569 "containing only one function.";
1570 throw std::runtime_error(message);
1574 QString
index, name;
1577 if (!variableIsPrefixed(attributeName.toStdString())) {
1584 auto children = prop->subProperties();
1585 foreach (QtProperty *child, children) {
1586 if (
isAttribute(child) && child->propertyName() == name) {
1590 std::string message =
"Unknown function attribute " + attributeName.toStdString();
1591 throw std::runtime_error(message);
1598 std::find_if(
m_ties.cbegin(),
m_ties.cend(), [&prop](
const auto &tie) { return tie.tieProp == prop; });
1599 if (itProp !=
m_ties.cend())
1600 return (*itProp).paramProp;
1603 return (constraint.lower == prop || constraint.upper == prop);
1606 return (*itConstr).paramProp;
1607 throw std::logic_error(
"QtProperty " + prop->propertyName().toStdString() +
1608 " is not a child of a property for any function parameter.");
1618 QtProperty *prop = item->property();
1621 auto const functionString = QString::fromStdString(
getFunction(prop)->asString());
1622 auto const functionIndex =
getIndex(prop);
1632 if (!props.isEmpty()) {
1637 auto topProp = props[0];
1638 auto cf = std::dynamic_pointer_cast<Mantid::API::CompositeFunction>(
getFunction(topProp));
1644 if (cf->nFunctions() == 1 && cf->name() ==
"CompositeFunction") {
1647 auto func =
getFunction(props[0]->subProperties()[1]);
1648 std::transform(globalParameters.begin(), globalParameters.end(), globalParameters.begin(),
1670 QtProperty *prop = item->property();
1680 auto children = prop->subProperties();
1681 foreach (QtProperty *child, children) {
1682 if (child->propertyName() ==
"Tie") {
1696 QtProperty *prop = item->property();
1713 QtProperty *prop = item->property();
1718 QString tie = QInputDialog::getText(
this,
"Add a tie",
"Tie:", QLineEdit::Normal,
"", &ok);
1719 if (ok && !tie.isEmpty()) {
1724 QMessageBox::critical(
this,
"Mantid - Error",
"Syntax errors found in tie: " + tie);
1725 }
catch (std::exception &e) {
1726 QMessageBox::critical(
this,
"Mantid - Error", QString::fromLatin1(
"Errors found in tie: ") + e.what());
1735 QString funStr = QApplication::clipboard()->text();
1736 if (funStr.isEmpty())
1746 QMessageBox::warning(
this,
"Mantid - Warning",
1747 "Text in the clipboard isn't a function definition"
1748 " or contains errors.");
1764 QtProperty *prop = item->property();
1767 QString functionIndex, name;
1770 auto const constraint =
value +
"<" + name +
"<" +
value;
1782 QtProperty *prop = item->property();
1786 QString functionIndex, name;
1788 auto const constraint = QString::number(val * 0.9) +
"<" + name +
"<" + QString::number(val * 1.1);
1800 QtProperty *prop = item->property();
1804 QString functionIndex, name;
1806 auto const constraint = QString::number(val * 0.5) +
"<" + name +
"<" + QString::number(val * 1.5);
1812 auto props = prop->subProperties();
1813 foreach (QtProperty *p, props) {
1827 QtProperty *prop = item->property();
1841 QtProperty *prop = item->property();
1848 QString functionIndex, constraint;
1850 if (!constraint.isEmpty()) {
1861 QtProperty *prop = item->property();
1877 for (
auto p : prop->subProperties()) {
1878 if (p->propertyName() ==
"LowerBound")
1880 if (p->propertyName() ==
"UpperBound")
1884 QString functionIndex, name;
1888 return std::make_pair(
"",
"");
1902 if (std::find(REQUIRESRECONSTRUCTIONATTRIBUTES.begin(), REQUIRESRECONSTRUCTIONATTRIBUTES.end(),
1903 removePrefix(attributeName)) != REQUIRESRECONSTRUCTIONATTRIBUTES.end()) {
1921 }
catch (std::exception &expt) {
1922 QMessageBox::critical(
this,
"Mantid - Error", QString::fromStdString(expt.what()));
1932 throw std::logic_error(
"FunctionTreeView: inconsistency in vector "
1933 "properties.\nAttribute property not found.");
1936 throw std::logic_error(
"FunctionTreeView: inconsistency in vector "
1937 "properties.\nFunction property not found.");
1940 throw std::logic_error(
"FunctionTreeView: inconsistency in vector "
1941 "properties.\nFunction undefined.");
1942 auto attName = vectorProp->propertyName().toStdString();
1943 auto attribute = fun->getAttribute(attName).asVector();
1947 if (attribute.size() !=
static_cast<size_t>(newSize)) {
1951 attribute.resize(newSize);
1953 fun->setAttributeValue(attName, attribute);
1967 throw std::runtime_error(
"FunctionTreeView: inconsistency in vector properties.");
1973 if (tieProp && !tieProp->isEnabled()) {
1975 QString newTie = QString(
"%1=%2").arg(prop->propertyName()).arg(
m_parameterManager->value(prop));
1976 if (!newTie.isEmpty()) {
1988 for (
const auto &atie :
m_ties) {
1989 if (atie.tieProp == prop) {
1998 const bool isLower = constr.lower == prop;
1999 const bool isUpper = constr.upper == prop;
2000 if (isLower || isUpper) {
2002 QString functionIndex, constraint;
2004 if (!constraint.isEmpty()) {
2073 boost::optional<QString> newIndex;
2075 if (
auto item =
m_browser->currentItem()) {
2076 auto prop = item->property();
2089 if (!tie.isEmpty()) {
2095 }
else if (tieProp) {
2109 QStringList globals;
2111 if (prop.prop->checkOption(globalOptionName)) {
2121 auto prop = ap.prop;
2122 if (!prop->hasOption(globalOptionName))
2126 auto const isGlobal = std::any_of(globals.cbegin(), globals.cend(), [&](QString
const &global) {
2127 return m_multiDomainFunctionPrefix + global == parameterName;
2129 prop->setOption(globalOptionName, isGlobal);
2141 return item->treeWidget()->visualItemRect(item);
2148 }
catch (std::exception &) {
2157 }
catch (std::exception &) {
2165 return item->treeWidget()->itemWidget(item, 1);
2166 }
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.
static T & Instance()
Return a reference to the Singleton instance, creating it if it does not already exist Creation is do...
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)