Newer
Older
#include "MantidQtWidgets/Common/FitPropertyBrowser.h"
#include "MantidQtWidgets/Common/HelpWindow.h"
#include "MantidQtWidgets/Common/MantidDesktopServices.h"
#include "MantidQtWidgets/Common/MultifitSetupDialog.h"
#include "MantidQtWidgets/Common/PropertyHandler.h"
#include "MantidQtWidgets/Common/SequentialFitDialog.h"
#include "MantidAPI/CompositeFunction.h"
Federico Montesino Pouzols
committed
#include "MantidAPI/CostFunctionFactory.h"
#include "MantidAPI/FrameworkManager.h"
#include "MantidAPI/FuncMinimizerFactory.h"
#include "MantidAPI/IBackgroundFunction.h"
Federico Montesino Pouzols
committed
#include "MantidAPI/ICostFunction.h"
#include "MantidAPI/IFuncMinimizer.h"
#include "MantidAPI/IPeakFunction.h"
#include "MantidAPI/ITableWorkspace.h"
Federico Montesino Pouzols
committed
#include "MantidAPI/MatrixWorkspace.h"
#include "MantidAPI/ParameterTie.h"
#include "MantidAPI/TableRow.h"
#include "MantidAPI/WorkspaceFactory.h"
#include "MantidKernel/Logger.h"
#include "MantidQtWidgets/Common/QtPropertyBrowser/FilenameDialogEditor.h"
#include "MantidQtWidgets/Common/QtPropertyBrowser/FormulaDialogEditor.h"
#include "MantidQtWidgets/Common/QtPropertyBrowser/StringEditorFactory.h"
#include "MantidQtWidgets/Common/QtPropertyBrowser/DoubleEditorFactory.h"
#include "MantidQtWidgets/Common/QtPropertyBrowser/ParameterPropertyManager.h"
#include "MantidQtWidgets/Common/QtPropertyBrowser/qteditorfactory.h"
#include "MantidQtWidgets/Common/QtPropertyBrowser/qttreepropertybrowser.h"
#include <QApplication>
#include <QClipboard>
#include <QInputDialog>
#include <QPushButton>
Anders Markvardsen
committed
#include <QSignalMapper>
#include <QUrl>
#include <QVBoxLayout>
namespace MantidQt {
using API::MantidDesktopServices;
namespace MantidWidgets {
namespace {
Mantid::Kernel::Logger g_log("FitPropertyBrowser");
}
/**
* Constructor
* @param parent :: The parent widget - must be an ApplicationWindow
* @param mantidui :: The UI form for MantidPlot
FitPropertyBrowser::FitPropertyBrowser(QWidget *parent, QObject *mantidui)
: QDockWidget("Fit Function", parent), m_workspaceIndex(nullptr),
m_startX(nullptr), m_endX(nullptr), m_output(nullptr),
m_minimizer(nullptr), m_ignoreInvalidData(nullptr),
m_costFunction(nullptr), m_maxIterations(nullptr), m_peakRadius(nullptr),
m_logValue(nullptr), m_plotDiff(nullptr), m_plotCompositeMembers(nullptr),
m_convolveMembers(nullptr), m_rawData(nullptr), m_xColumn(nullptr),
m_yColumn(nullptr), m_errColumn(nullptr), m_showParamErrors(nullptr),
m_evaluationType(nullptr), m_compositeFunction(), m_browser(nullptr),
m_fitActionUndoFit(nullptr), m_fitActionSeqFit(nullptr),
m_fitActionFit(nullptr), m_fitActionEvaluate(nullptr),
m_functionsGroup(nullptr), m_settingsGroup(nullptr),
m_customSettingsGroup(nullptr), m_changeSlotsEnabled(false),
m_guessOutputName(true),
m_updateObserver(*this, &FitPropertyBrowser::handleFactoryUpdate),
m_fitMapper(nullptr), m_fitMenu(nullptr),
m_displayActionPlotGuess(nullptr), m_displayActionQuality(nullptr),
m_displayActionClearAll(nullptr), m_setupActionCustomSetup(nullptr),
m_setupActionRemove(nullptr), m_tip(nullptr), m_fitSelector(nullptr),
m_fitTree(nullptr), m_currentHandler(nullptr),
m_defaultFunction("Gaussian"), m_defaultPeak("Gaussian"),
m_defaultBackground("LinearBackground"), m_index_(0), m_peakToolOn(false),
m_auto_back(false),
m_autoBgName(QString::fromStdString(
Mantid::Kernel::ConfigService::Instance().getString(
"curvefitting.autoBackground"))),
m_autoBackground(nullptr), m_decimals(-1), m_mantidui(mantidui),
m_shouldBeNormalised(false) {
Mantid::API::FrameworkManager::Instance().loadPlugins();
// Try to create a Gaussian. Failing will mean that CurveFitting dll is not
// loaded
boost::shared_ptr<Mantid::API::IFunction> f =
boost::shared_ptr<Mantid::API::IFunction>(
Mantid::API::FunctionFactory::Instance().createFunction("Gaussian"));
if (m_autoBgName.toLower() == "none") {
setAutoBackgroundName(m_autoBgName);
}
std::string def = Mantid::Kernel::ConfigService::Instance().getString(
"curvefitting.defaultPeak");
if (!def.empty()) {
def = Mantid::Kernel::ConfigService::Instance().getString(
"curvefitting.autoBackground");
if (!def.empty()) {
m_defaultBackground = def;
}
m_defaultFunction = m_defaultPeak;
setObjectName(
"FitFunction"); // this is needed for QMainWindow::restoreState()
setMinimumHeight(150);
setMinimumWidth(200);
QWidget *w = new QWidget(this);
/* Create property managers: they create, own properties, get and set values
*/
m_groupManager = new QtGroupPropertyManager(w);
m_doubleManager = new QtDoublePropertyManager(w);
m_stringManager = new QtStringPropertyManager(w);
m_enumManager = new QtEnumPropertyManager(w);
m_intManager = new QtIntPropertyManager(w);
m_boolManager = new QtBoolPropertyManager(w);
m_filenameManager = new QtStringPropertyManager(w);
m_formulaManager = new QtStringPropertyManager(w);
m_columnManager = new QtEnumPropertyManager(w);
m_workspace = m_enumManager->addProperty("Workspace");
m_vectorManager = new QtGroupPropertyManager(w);
m_vectorSizeManager = new QtIntPropertyManager(w);
m_vectorDoubleManager = new QtDoublePropertyManager(w);
m_parameterManager = new ParameterPropertyManager(w);
* Initialise the fit property browser
*/
void FitPropertyBrowser::init() {
QWidget *w = new QWidget(this);
QSettings settings;
settings.beginGroup("Mantid/FitBrowser");
Robert Whitley
committed
/* Create function group */
QtProperty *functionsGroup = m_groupManager->addProperty("Functions");
connect(this, SIGNAL(xRangeChanged(double, double)), m_mantidui,
SLOT(x_range_from_picker(double, double)));
/* Create input - output properties */
QtProperty *settingsGroup = m_groupManager->addProperty("Settings");
m_startX = addDoubleProperty("StartX");
m_endX = addDoubleProperty("EndX");
m_workspaceIndex = m_intManager->addProperty("Workspace Index");
m_output = m_stringManager->addProperty("Output");
m_minimizer = m_enumManager->addProperty("Minimizer");
<< "Levenberg-MarquardtMD"
<< "Trust Region"
<< "Conjugate gradient (Fletcher-Reeves imp.)"
<< "Conjugate gradient (Polak-Ribiere imp.)"
<< "Damped GaussNewton";
m_ignoreInvalidData = m_boolManager->addProperty("Ignore invalid data");
setIgnoreInvalidData(settings.value("Ignore invalid data", false).toBool());
m_enumManager->setEnumNames(m_minimizer, m_minimizers);
m_costFunction = m_enumManager->addProperty("Cost function");
m_costFunctions << "Least squares"
<< "Rwp"
<< "Unweighted least squares";
m_enumManager->setEnumNames(m_costFunction, m_costFunctions);
m_maxIterations = m_intManager->addProperty("Max Iterations");
m_intManager->setValue(m_maxIterations,
settings.value("Max Iterations", 500).toInt());
Robert Whitley
committed
m_peakRadius = m_intManager->addProperty("Peak Radius");
m_intManager->setValue(m_peakRadius,
settings.value("Peak Radius", 0).toInt());
m_plotDiff = m_boolManager->addProperty("Plot Difference");
bool plotDiff = settings.value("Plot Difference", QVariant(true)).toBool();
m_boolManager->setValue(m_plotDiff, plotDiff);
m_plotCompositeMembers = m_boolManager->addProperty("Plot Composite Members");
bool plotCompositeItems =
settings.value(m_plotCompositeMembers->propertyName(), QVariant(false))
.toBool();
m_boolManager->setValue(m_plotCompositeMembers, plotCompositeItems);
m_convolveMembers = m_boolManager->addProperty("Convolve Composite Members");
bool convolveCompositeItems =
settings.value(m_plotCompositeMembers->propertyName(), QVariant(false))
.toBool();
m_boolManager->setValue(m_convolveMembers, convolveCompositeItems);
m_showParamErrors = m_boolManager->addProperty("Show Parameter Errors");
bool showParamErrors =
settings.value(m_showParamErrors->propertyName(), false).toBool();
m_boolManager->setValue(m_showParamErrors, showParamErrors);
m_parameterManager->setErrorsEnabled(showParamErrors);
m_evaluationType = m_enumManager->addProperty("Evaluate Function As");
m_evaluationType->setToolTip(
"Consider using Histogram fit which may produce more accurate results.");
m_evaluationTypes << "CentrePoint"
<< "Histogram";
m_enumManager->setEnumNames(m_evaluationType, m_evaluationTypes);
int evaluationType =
settings.value(m_evaluationType->propertyName(), 0).toInt();
m_enumManager->setValue(m_evaluationType, evaluationType);
m_xColumn = m_columnManager->addProperty("XColumn");
m_yColumn = m_columnManager->addProperty("YColumn");
m_errColumn = m_columnManager->addProperty("ErrColumn");
settingsGroup->addSubProperty(m_workspace);
settingsGroup->addSubProperty(m_startX);
settingsGroup->addSubProperty(m_endX);
// Only include the cost function when in the dock widget inside mantid plot,
// not on muon analysis widget
Robert Whitley
committed
// Include minimiser and plot difference under a different settings section.
settingsGroup->addSubProperty(m_output);
settingsGroup->addSubProperty(m_minimizer);
settingsGroup->addSubProperty(m_ignoreInvalidData);
settingsGroup->addSubProperty(m_costFunction);
settingsGroup->addSubProperty(m_maxIterations);
settingsGroup->addSubProperty(m_peakRadius);
settingsGroup->addSubProperty(m_plotDiff);
settingsGroup->addSubProperty(m_plotCompositeMembers);
settingsGroup->addSubProperty(m_convolveMembers);
settingsGroup->addSubProperty(m_showParamErrors);
settingsGroup->addSubProperty(m_evaluationType);
Robert Whitley
committed
/* Create editors and assign them to the managers */
m_functionsGroup = m_browser->addProperty(functionsGroup);
m_settingsGroup = m_browser->addProperty(settingsGroup);
initLayout(w);
}
/**
* @brief Initialise the layout.
* This initialization includes:
* 1. SIGNALs/SLOTs when properties change.
* 2. Action menus and associated SIGNALs/SLOTs.
* 3. Initialize the CompositeFunction, the root from which to build the
* Model. 4. Update the list of available functions
* @param w widget parenting the action menus and the property tree browser
*/
void FitPropertyBrowser::initLayout(QWidget *w) { initBasicLayout(w); }
* @brief Initialise the layout for the fit button.
* This initialization includes:
* 1. SIGNALs/SLOTs when properties change.
* 2. Actions and associated SIGNALs/SLOTs.
* @param w widget parenting the action menus and the property tree browser
* @return push botton for the fit menu
*/
QPushButton *FitPropertyBrowser::createFitMenuButton(QWidget *w) {
QPushButton *btnFit = new QPushButton("Fit");
m_tip = new QLabel("", w);
m_fitMapper = new QSignalMapper(this);
m_fitMenu = new QMenu(this);
connect(m_fitMapper, SIGNAL(mapped(const QString &)), this,
SLOT(executeFitMenu(const QString &)));
btnFit->setMenu(m_fitMenu);
return btnFit;
* @brief Populate the fit button.
* This initialization includes:
* 1. SIGNALs/SLOTs when properties change.
* 2. Actions and associated SIGNALs/SLOTs.
* @param fitMapper the QMap to the fit mapper
* @param fitMenu the QMenu for the fit button
*/
void FitPropertyBrowser::populateFitMenuButton(QSignalMapper *fitMapper,
QMenu *fitMenu) {
// assert(fitmapper);
m_fitActionFit = new QAction("Fit", this);
m_fitActionSeqFit = new QAction("Sequential Fit", this);
m_fitActionUndoFit = new QAction("Undo Fit", this);
m_fitActionEvaluate = new QAction("Evaluate function", this);
fitMapper->setMapping(m_fitActionFit, "Fit");
fitMapper->setMapping(m_fitActionSeqFit, "SeqFit");
fitMapper->setMapping(m_fitActionUndoFit, "UndoFit");
fitMapper->setMapping(m_fitActionEvaluate, "Evaluate");
connect(m_fitActionFit, SIGNAL(triggered()), fitMapper, SLOT(map()));
connect(m_fitActionSeqFit, SIGNAL(triggered()), fitMapper, SLOT(map()));
connect(m_fitActionUndoFit, SIGNAL(triggered()), fitMapper, SLOT(map()));
connect(m_fitActionEvaluate, SIGNAL(triggered()), fitMapper, SLOT(map()));
fitMenu->addAction(m_fitActionFit);
fitMenu->addAction(m_fitActionSeqFit);
fitMenu->addAction(m_fitActionEvaluate);
fitMenu->addSeparator();
fitMenu->addAction(m_fitActionUndoFit);
fitMenu->addSeparator();
* @brief Initialise the layout, except for the fit button in the menu bar.
* This initialization includes:
* 1. SIGNALs/SLOTs when properties change.
* 2. Action menus and associated SIGNALs/SLOTs.
* 3. Initialize the CompositeFunction, the root from which to build the
* Model. 4. Update the list of available functions
* @param w widget parenting the action menus and the property tree browser
*/
void FitPropertyBrowser::initBasicLayout(QWidget *w) {
// to be able to change windows title from tread
connect(this, SIGNAL(changeWindowTitle(const QString &)), this,
SLOT(setWindowTitle(const QString &)));
/* Create the top level group */
Roman Tolchenov
committed
m_groupManager->addProperty("Fit");
connect(m_enumManager, SIGNAL(propertyChanged(QtProperty *)), this,
SLOT(enumChanged(QtProperty *)));
connect(m_boolManager, SIGNAL(propertyChanged(QtProperty *)), this,
SLOT(boolChanged(QtProperty *)));
connect(m_intManager, SIGNAL(propertyChanged(QtProperty *)), this,
SLOT(intChanged(QtProperty *)));
connect(m_doubleManager, SIGNAL(propertyChanged(QtProperty *)), this,
SLOT(doubleChanged(QtProperty *)));
connect(m_stringManager, SIGNAL(propertyChanged(QtProperty *)), this,
SLOT(stringChanged(QtProperty *)));
connect(m_filenameManager, SIGNAL(propertyChanged(QtProperty *)), this,
SLOT(stringChanged(QtProperty *)));
connect(m_formulaManager, SIGNAL(propertyChanged(QtProperty *)), this,
SLOT(stringChanged(QtProperty *)));
connect(m_columnManager, SIGNAL(propertyChanged(QtProperty *)), this,
SLOT(columnChanged(QtProperty *)));
connect(m_vectorDoubleManager, SIGNAL(propertyChanged(QtProperty *)), this,
SLOT(vectorDoubleChanged(QtProperty *)));
connect(m_parameterManager, SIGNAL(propertyChanged(QtProperty *)), this,
SLOT(parameterChanged(QtProperty *)));
connect(m_vectorSizeManager, SIGNAL(propertyChanged(QtProperty *)), this,
SLOT(vectorSizeChanged(QtProperty *)));
QVBoxLayout *layout = new QVBoxLayout(w);
QGridLayout *buttonsLayout = new QGridLayout();
QPushButton *btnDisplay = new QPushButton("Display");
QMenu *displayMenu = new QMenu(this);
m_displayActionPlotGuess = new QAction("Plot Guess", this);
m_displayActionPlotGuess->setEnabled(false);
m_displayActionQuality = new QAction("Quality", this);
Anders Markvardsen
committed
m_displayActionQuality->setCheckable(true);
m_displayActionQuality->setChecked(true);
m_displayActionClearAll = new QAction("Clear fit curves", this);
QSignalMapper *displayMapper = new QSignalMapper(this);
displayMapper->setMapping(m_displayActionPlotGuess, "PlotGuess");
displayMapper->setMapping(m_displayActionQuality, "Quality");
displayMapper->setMapping(m_displayActionClearAll, "ClearAll");
connect(m_displayActionPlotGuess, SIGNAL(triggered()), displayMapper,
connect(m_displayActionQuality, SIGNAL(triggered()), displayMapper,
connect(m_displayActionClearAll, SIGNAL(triggered()), displayMapper,
SLOT(map()));
connect(displayMapper, SIGNAL(mapped(const QString &)), this,
SLOT(executeDisplayMenu(const QString &)));
displayMenu->addAction(m_displayActionPlotGuess);
displayMenu->addAction(m_displayActionClearAll);
Anders Markvardsen
committed
displayMenu->addAction(m_displayActionQuality);
btnDisplay->setMenu(displayMenu);
QPushButton *btnSetup = new QPushButton("Setup");
QMenu *setupMenu = new QMenu(this);
m_setupActionCustomSetup = new QAction("Custom Setup", this);
QAction *setupActionManageSetup = new QAction("Manage Setup", this);
QAction *setupActionFindPeaks = new QAction("Find Peaks", this);
QAction *setupActionClearFit = new QAction("Clear Model", this);
QMenu *setupSubMenuCustom = new QMenu(this);
m_setupActionCustomSetup->setMenu(setupSubMenuCustom);
Federico Montesino Pouzols
committed
// empty menu for now, so set it disabled to avoid confusing users
m_setupActionCustomSetup->setEnabled(false);
QMenu *setupSubMenuManage = new QMenu(this);
QAction *setupActionSave = new QAction("Save Setup", this);
m_setupActionRemove = new QAction("Remove Setup", this);
QAction *setupActionCopyToClipboard = new QAction("Copy To Clipboard", this);
QAction *setupActionLoadFromString = new QAction("Load From String", this);
QSignalMapper *setupManageMapper = new QSignalMapper(this);
setupManageMapper->setMapping(setupActionSave, "SaveSetup");
setupManageMapper->setMapping(setupActionCopyToClipboard, "CopyToClipboard");
setupManageMapper->setMapping(setupActionLoadFromString, "LoadFromString");
connect(setupActionSave, SIGNAL(triggered()), setupManageMapper, SLOT(map()));
connect(setupActionCopyToClipboard, SIGNAL(triggered()), setupManageMapper,
connect(setupActionLoadFromString, SIGNAL(triggered()), setupManageMapper,
SLOT(map()));
connect(setupManageMapper, SIGNAL(mapped(const QString &)), this,
SLOT(executeSetupManageMenu(const QString &)));
setupSubMenuManage->addAction(setupActionSave);
setupSubMenuManage->addAction(m_setupActionRemove);
setupSubMenuManage->addAction(setupActionCopyToClipboard);
setupSubMenuManage->addAction(setupActionLoadFromString);
setupActionManageSetup->setMenu(setupSubMenuManage);
QMenu *setupSubMenuRemove = new QMenu(this);
m_setupActionRemove->setMenu(setupSubMenuRemove);
Federico Montesino Pouzols
committed
// empty menu for now, so set it disabled to avoid confusing users
m_setupActionRemove->setEnabled(false);
QSignalMapper *setupMapper = new QSignalMapper(this);
setupMapper->setMapping(setupActionClearFit, "ClearFit");
setupMapper->setMapping(setupActionFindPeaks, "FindPeaks");
connect(setupActionClearFit, SIGNAL(triggered()), setupMapper, SLOT(map()));
connect(setupActionFindPeaks, SIGNAL(triggered()), setupMapper, SLOT(map()));
connect(setupMapper, SIGNAL(mapped(const QString &)), this,
SLOT(executeSetupMenu(const QString &)));
setupMenu->addAction(m_setupActionCustomSetup);
setupMenu->addAction(setupActionManageSetup);
setupMenu->addSeparator();
setupMenu->addAction(setupActionFindPeaks);
setupMenu->addSeparator();
setupMenu->addAction(setupActionClearFit);
btnSetup->setMenu(setupMenu);
buttonsLayout->addWidget(btnFit, 0, 0);
buttonsLayout->addWidget(btnDisplay, 0, 1);
buttonsLayout->addWidget(btnSetup, 0, 2);
m_status = new QLabel("Status:", w);
m_status->hide();
connect(this, SIGNAL(fitResultsChanged(const QString &)), this,
SLOT(showFitResultStatus(const QString &)), Qt::QueuedConnection);
layout->addWidget(m_status);
layout->addLayout(buttonsLayout);
layout->addWidget(m_tip);
layout->addWidget(m_browser);
setWidget(w);
m_browser->setContextMenuPolicy(Qt::CustomContextMenu);
connect(m_browser, SIGNAL(customContextMenuRequested(const QPoint &)), this,
SLOT(popupMenu(const QPoint &)));
connect(m_browser, SIGNAL(currentItemChanged(QtBrowserItem *)), this,
SLOT(currentItemChanged(QtBrowserItem *)));
connect(this, SIGNAL(multifitFinished()), this,
SLOT(processMultiBGResults()));
// Update tooltips when function structure is (or might've been) changed in
// any way
connect(this, SIGNAL(functionChanged()), SLOT(updateStructureTooltips()));
connect(this, SIGNAL(functionChanged()), SLOT(clearFitResultStatus()));
// Update available functions in this fit property browser, when the function
// factory changes.
using Mantid::API::FunctionFactory;
FunctionFactory::Instance().notificationCenter.addObserver(m_updateObserver);
connect(this, SIGNAL(functionFactoryUpdateReceived()), this,
SLOT(populateFunctionNames()));
FunctionFactory::Instance().enableNotifications();
// Initial call, as function is not changed when it's created for the first
// time
updateStructureTooltips();
* @brief Create editors and assign them to the managers.
* Associates a particular widget factory to each property manager. Thus, the
* factory will automatically create widgets befitting to edit the properties
* that we define.
* @param w :: widget showing the properties tree and the actions buttons
*/
void FitPropertyBrowser::createEditors(QWidget *w) {
QtCheckBoxFactory *checkBoxFactory = new QtCheckBoxFactory(w);
QtEnumEditorFactory *comboBoxFactory = new QtEnumEditorFactory(w);
QtSpinBoxFactory *spinBoxFactory = new QtSpinBoxFactory(w);
DoubleEditorFactory *doubleEditorFactory = new DoubleEditorFactory(w);
StringEditorFactory *stringEditFactory = new StringEditorFactory(w);
FilenameDialogEditorFactory *filenameDialogEditorFactory =
new FilenameDialogEditorFactory(w);
FormulaDialogEditorFactory *formulaDialogEditFactory =
new FormulaDialogEditorFactory(w);
m_browser = new QtTreePropertyBrowser();
m_browser->setFactoryForManager(m_enumManager, comboBoxFactory);
m_browser->setFactoryForManager(m_boolManager, checkBoxFactory);
m_browser->setFactoryForManager(m_intManager, spinBoxFactory);
m_browser->setFactoryForManager(m_doubleManager, doubleEditorFactory);
m_browser->setFactoryForManager(m_stringManager, stringEditFactory);
m_browser->setFactoryForManager(m_filenameManager,
filenameDialogEditorFactory);
m_browser->setFactoryForManager(m_formulaManager, formulaDialogEditFactory);
m_browser->setFactoryForManager(m_columnManager, comboBoxFactory);
m_browser->setFactoryForManager(m_vectorSizeManager, spinBoxFactory);
m_browser->setFactoryForManager(m_vectorDoubleManager, doubleEditorFactory);
m_browser->setFactoryForManager(m_parameterManager,
new ParameterEditorFactory(w));
/// Update setup menus according to how these are set in
/// settings
void FitPropertyBrowser::updateSetupMenus() {
QMenu *menuLoad = m_setupActionCustomSetup->menu();
QMenu *menuRemove = m_setupActionRemove->menu();
QSettings settings;
settings.beginGroup("Mantid/FitBrowser/SavedFunctions");
QStringList names = settings.childKeys();
QSignalMapper *mapperLoad = new QSignalMapper(this);
QSignalMapper *mapperRemove = new QSignalMapper(this);
// enable actions that open the menus only if there will be >=1 entries in
// there
m_setupActionCustomSetup->setEnabled(names.size() >= 1);
m_setupActionRemove->setEnabled(names.size() >= 1);
for (int i = 0; i < names.size(); i++) {
QAction *itemLoad = new QAction(names.at(i), this);
QAction *itemRemove = new QAction(names.at(i), this);
mapperLoad->setMapping(itemLoad, names.at(i));
mapperRemove->setMapping(itemRemove, names.at(i));
connect(itemLoad, SIGNAL(triggered()), mapperLoad, SLOT(map()));
connect(itemRemove, SIGNAL(triggered()), mapperRemove, SLOT(map()));
menuLoad->addAction(itemLoad);
menuRemove->addAction(itemRemove);
}
connect(mapperLoad, SIGNAL(mapped(const QString &)), this,
SLOT(executeCustomSetupLoad(const QString &)));
connect(mapperRemove, SIGNAL(mapped(const QString &)), this,
SLOT(executeCustomSetupRemove(const QString &)));
}
void FitPropertyBrowser::executeCustomSetupLoad(const QString &name) {
QSettings settings;
settings.beginGroup("Mantid/FitBrowser/SavedFunctions");
QStringList names = settings.childKeys();
QString str = settings.value(name).toString();
loadFunction(str);
}
void FitPropertyBrowser::executeCustomSetupRemove(const QString &name) {
QSettings settings;
settings.beginGroup("Mantid/FitBrowser/SavedFunctions");
QStringList names = settings.childKeys();
settings.remove(name);
updateSetupMenus();
/**
* Recursively updates structure tooltips for all the functions
*/
void FitPropertyBrowser::updateStructureTooltips() {
// Call tooltip update func on the root handler - it goes down recursively
getHandler()->updateStructureTooltip();
}
void FitPropertyBrowser::executeFitMenu(const QString &item) {
if (item == "Fit") {
} else if (item == "SeqFit") {
sequentialFit();
} else if (item == "UndoFit") {
undoFit();
} else if (item == "Evaluate") {
doFit(0);
void FitPropertyBrowser::executeDisplayMenu(const QString &item) {
if (item == "PlotGuess") {
plotOrRemoveGuessAll();
} else if (item == "ClearAll") {
clearAllPlots();
}
void FitPropertyBrowser::executeSetupMenu(const QString &item) {
if (item == "ClearFit")
clear();
if (item == "FindPeaks")
findPeaks();
}
void FitPropertyBrowser::executeSetupManageMenu(const QString &item) {
if (item == "SaveSetup")
saveFunction();
if (item == "CopyToClipboard")
copy();
if (item == "LoadFromString")
loadFunctionFromString();
}
FitPropertyBrowser::~FitPropertyBrowser() { m_compositeFunction.reset(); }
/// Get handler to the root composite function
PropertyHandler *FitPropertyBrowser::getHandler() const {
return static_cast<PropertyHandler *>(m_compositeFunction->getHandler());
PropertyHandler *FitPropertyBrowser::addFunction(const std::string &fnName) {
PropertyHandler *h = getHandler()->addFunction(fnName);
emit functionChanged();
return h;
}
void FitPropertyBrowser::removeFunction(PropertyHandler *handler) {
if (handler) {
emit removePlotSignal(getHandler());
handler->removeFunction();
compositeFunction()->checkFunction();
emit functionRemoved();
emit functionChanged();
}
}
/** Slot. Called to add a new function
*/
void FitPropertyBrowser::addFunction() {
QtBrowserItem *ci = m_browser->currentItem();
// Find the function which has ci as its top browser item
auto cf = getHandler()->findCompositeFunction(ci);
if (!cf)
return;
// Declare new widget for picking fit functions
m_fitSelector = new QDialog();
m_fitSelector->setModal(true);
// QTreeWidget *m_fitTree = new QTreeWidget();
m_fitTree = new QTreeWidget;
// Add functions to each of the categories. If it appears in more than one
// category then add to both
// Store in a map. Key = category. Value = vector of fit functions belonging
// to that category.
std::map<std::string, std::vector<std::string>> categories;
for (int i = 0; i < m_registeredFunctions.size(); ++i) {
boost::shared_ptr<Mantid::API::IFunction> f =
Mantid::API::FunctionFactory::Instance().createFunction(
m_registeredFunctions[i].toStdString());
std::vector<std::string> tempCategories = f->categories();
for (size_t j = 0; j < tempCategories.size(); ++j) {
categories[tempCategories[boost::lexical_cast<int>(j)]].push_back(
m_registeredFunctions[i].toStdString());
// Construct the QTreeWidget based on the map information of categories and
// their respective fit functions.
std::map<std::string, std::vector<std::string>>::const_iterator sItr =
categories.end();
for (std::map<std::string, std::vector<std::string>>::const_iterator itr =
categories.begin();
itr != sItr; ++itr) {
QTreeWidgetItem *category = new QTreeWidgetItem(m_fitTree);
category->setText(0, QString::fromStdString(itr->first));
std::vector<std::string>::const_iterator fitItrEnd = itr->second.end();
for (std::vector<std::string>::const_iterator fitItrBegin =
itr->second.begin();
fitItrBegin != fitItrEnd; ++fitItrBegin) {
QTreeWidgetItem *fit = new QTreeWidgetItem(category);
fit->setText(0, QString::fromStdString(fitItrBegin[0]));
// Set the layout of the widget.
m_fitTree->setToolTip("Select a function type and press OK.");
m_fitTree->setHeaderLabel("Fit - Select function type");
QDialogButtonBox *buttonBox =
new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
connect(buttonBox, SIGNAL(accepted()), this, SLOT(acceptFit()));
connect(buttonBox, SIGNAL(rejected()), this, SLOT(closeFit()));
connect(m_fitTree, SIGNAL(itemDoubleClicked(QTreeWidgetItem *, int)), this,
SLOT(acceptFit()));
QVBoxLayout *layout = new QVBoxLayout();
layout->addWidget(m_fitTree);
layout->addWidget(buttonBox);
m_fitSelector->setLayout(layout);
m_fitSelector->show();
}
void FitPropertyBrowser::acceptFit() {
QtBrowserItem *ci = m_browser->currentItem();
boost::shared_ptr<const Mantid::API::CompositeFunction> cf =
getHandler()->findCompositeFunction(ci);
if (!cf)
QList<QTreeWidgetItem *> items(m_fitTree->selectedItems());
if (items.size() != 1)
return;
if (items[0]->parent() == nullptr)
PropertyHandler *h = getHandler()->findHandler(cf);
h->addFunction(items[0]->text(0).toStdString());
closeFit();
}
void FitPropertyBrowser::closeFit() { m_fitSelector->close(); }
/**
* Create CompositeFunction from function pointer
* @param func :: [input] Pointer to function
*/
void FitPropertyBrowser::createCompositeFunction(
const Mantid::API::IFunction_sptr func) {
if (m_compositeFunction) {
m_autoBackground = nullptr;
m_compositeFunction.reset(new Mantid::API::CompositeFunction);
} else {
auto cf = boost::dynamic_pointer_cast<Mantid::API::CompositeFunction>(func);
if (!cf || (cf->name() != "CompositeFunction" && cf->name() != "MultiBG" &&
cf->name() != "MultiDomainFunction")) {
m_compositeFunction.reset(new Mantid::API::CompositeFunction);
m_compositeFunction->addFunction(func);
m_compositeFunction = cf;
}
}
setWorkspace(m_compositeFunction);
PropertyHandler *h = new PropertyHandler(
m_compositeFunction, Mantid::API::CompositeFunction_sptr(), this);
m_compositeFunction->setHandler(h);
setCurrentFunction(h);
if (m_auto_back) {
addAutoBackground();
}
disableUndo();
setFitEnabled(m_compositeFunction->nFunctions() > 0);
emit functionChanged();
}
/**
* Create CompositeFunction from string
* @param str :: [input] Function string
*/
void FitPropertyBrowser::createCompositeFunction(const QString &str) {
if (str.isEmpty()) {
createCompositeFunction(Mantid::API::IFunction_sptr());
} else {
auto f = Mantid::API::FunctionFactory::Instance().createInitialized(
str.toStdString());
if (f) {
createCompositeFunction(f);
} else {
createCompositeFunction(Mantid::API::IFunction_sptr());
}
}
}
void FitPropertyBrowser::popupMenu(const QPoint &) {
QtBrowserItem *ci = m_browser->currentItem();
if (!ci)
return;
QMenu *menu = new QMenu(this);
QAction *action;
bool isFunctionsGroup = ci == m_functionsGroup;
bool isSettingsGroup = ci == m_settingsGroup;
bool isASetting = ci->parent() == m_settingsGroup;
bool isFunction = getHandler()->findFunction(ci) != nullptr;
bool isCompositeFunction =
isFunction && getHandler()->findCompositeFunction(ci);
PropertyHandler *h = getHandler()->findHandler(ci->property());
if (isFunctionsGroup) {
action = new QAction("Add function", this);
connect(action, SIGNAL(triggered()), this, SLOT(addFunction()));
if (m_compositeFunction->name() == "MultiBG" &&
m_compositeFunction->nFunctions() == 1 &&
Mantid::API::AnalysisDataService::Instance().doesExist(
workspaceName())) {
action = new QAction("Setup multifit", this);
connect(action, SIGNAL(triggered()), this, SLOT(setupMultifit()));
menu->addAction(action);
}
if (m_peakToolOn) {
if (h && h->hasPlot()) {
action = new QAction("Remove plot", this);
connect(action, SIGNAL(triggered()), this, SLOT(removeGuessAll()));
} else {
action = new QAction("Plot", this);
connect(action, SIGNAL(triggered()), this, SLOT(plotGuessAll()));
menu->addAction(action);
}
}
menu->addSeparator();
action = new QAction("Save", this);
connect(action, SIGNAL(triggered()), this, SLOT(saveFunction()));
action = new QAction("Load", this);
connect(action, SIGNAL(triggered()), this, SLOT(loadFunction()));
action = new QAction("Copy To Clipboard", this);
connect(action, SIGNAL(triggered()), this, SLOT(copy()));
menu->addAction(action);
menu->addSeparator();
action = new QAction("Help", this);
connect(action, SIGNAL(triggered()), this, SLOT(browserHelp()));
menu->addAction(action);
} else if (isFunctionsGroup || isSettingsGroup || isASetting) {
if (isFitEnabled()) {
action = new QAction("Fit", this);
connect(action, SIGNAL(triggered()), this, SLOT(fit()));
if (isUndoEnabled()) {
action = new QAction("Undo Fit", this);
connect(action, SIGNAL(triggered()), this, SLOT(undoFit()));
action = new QAction("Clear all", this);
connect(action, SIGNAL(triggered()), this, SLOT(clear()));
action = new QAction("Help", this);
connect(action, SIGNAL(triggered()), this, SLOT(browserHelp()));
menu->addAction(action);
} else if (isFunction) {
if (isCompositeFunction) {
action = new QAction("Add function", this);
connect(action, SIGNAL(triggered()), this, SLOT(addFunction()));
action = new QAction("Remove", this);
connect(action, SIGNAL(triggered()), this, SLOT(deleteFunction()));
if (m_peakToolOn) {
if (h && h->hasPlot()) {
action = new QAction("Remove plot", this);
connect(action, SIGNAL(triggered()), this, SLOT(removeGuessCurrent()));
} else {
action = new QAction("Plot", this);
connect(action, SIGNAL(triggered()), this, SLOT(plotGuessCurrent()));
action = new QAction("Help", this);
connect(action, SIGNAL(triggered()), this, SLOT(functionHelp()));
menu->addAction(action);
} else if (h) {
bool isParameter = h->isParameter(ci->property());
bool isTie = !isParameter && ci->property()->propertyName() == "Tie";
bool isLowerBound =
!isParameter && ci->property()->propertyName() == "Lower Bound";
bool isUpperBound =
!isParameter && ci->property()->propertyName() == "Upper Bound";
bool isType = isParameter && ci->property()->propertyName() == "Type";
if (isType) {
isParameter = false;
}
if (isTie) {
action = new QAction("Remove", this);
connect(action, SIGNAL(triggered()), this, SLOT(deleteTie()));
} else if (isLowerBound || isUpperBound) {
action = new QAction("Remove", this);
connect(action, SIGNAL(triggered()), this, SLOT(removeBounds()));
} else if (count() > 0 && isParameter) {
hasConstraints(ci->property(), hasTies, hasBounds);
if (!hasTies && !hasBounds) {
action = new QAction("Fix", this);
connect(action, SIGNAL(triggered()), this, SLOT(addFixTie()));
if (!hasTies) {
QMenu *constraintMenu = menu->addMenu("Constraint");
QMenu *detailMenu = constraintMenu->addMenu("Lower Bound");
action = new QAction("10%", this);
connect(action, SIGNAL(triggered()), this, SLOT(addLowerBound10()));
action = new QAction("50%", this);
connect(action, SIGNAL(triggered()), this, SLOT(addLowerBound50()));
action = new QAction("Custom", this);
connect(action, SIGNAL(triggered()), this, SLOT(addLowerBound()));
detailMenu->addAction(action);
detailMenu = constraintMenu->addMenu("Upper Bound");
action = new QAction("10%", this);
connect(action, SIGNAL(triggered()), this, SLOT(addUpperBound10()));
action = new QAction("50%", this);
connect(action, SIGNAL(triggered()), this, SLOT(addUpperBound50()));
action = new QAction("Custom", this);
connect(action, SIGNAL(triggered()), this, SLOT(addUpperBound()));
detailMenu->addAction(action);
detailMenu = constraintMenu->addMenu("Both Bounds");
action = new QAction("10%", this);
connect(action, SIGNAL(triggered()), this, SLOT(addBothBounds10()));
action = new QAction("50%", this);
connect(action, SIGNAL(triggered()), this, SLOT(addBothBounds50()));
action = new QAction("Custom", this);
connect(action, SIGNAL(triggered()), this, SLOT(addBothBounds()));
if (hasBounds) {
action = new QAction("Remove constraints", this);
connect(action, SIGNAL(triggered()), this, SLOT(removeBounds()));
if (!hasTies && !hasBounds) {
if (count() == 1) {
action = new QAction("Tie", this);
connect(action, SIGNAL(triggered()), this, SLOT(addTie()));
} else {
QMenu *detail = menu->addMenu("Tie");
action = new QAction("To function", this);
connect(action, SIGNAL(triggered()), this, SLOT(addTieToFunction()));