Skip to content
Snippets Groups Projects
FitPropertyBrowser.cpp 106 KiB
Newer Older
          action = new QAction("To function", this);
          connect(action, SIGNAL(triggered()), this, SLOT(addTieToFunction()));
          detail->addAction(action);

          action = new QAction("Custom Tie", this);
          connect(action, SIGNAL(triggered()), this, SLOT(addTie()));
          detail->addAction(action);
        }
      } else if (hasTies) {
        action = new QAction("Remove tie", this);
        connect(action, SIGNAL(triggered()), this, SLOT(deleteTie()));
        menu->addAction(action);
      }
    }
  }

  menu->popup(QCursor::pos());
}

/** Slot. Called to remove a function
 */
void FitPropertyBrowser::deleteFunction() {
  QtBrowserItem *ci = m_browser->currentItem();
  PropertyHandler *h = getHandler()->findHandler(ci->property());
}

//***********************************************************************************//

// Get the default function name
std::string FitPropertyBrowser::defaultFunctionType() const {
  return m_defaultFunction;
}

// Get the default function name
void FitPropertyBrowser::setDefaultFunctionType(const std::string &fnType) {
  m_defaultFunction = fnType;
}

/// Get the default peak type
std::string FitPropertyBrowser::defaultPeakType() const {
  return m_defaultPeak;
}
/// Set the default peak type
void FitPropertyBrowser::setDefaultPeakType(const std::string &fnType) {
  m_defaultPeak = fnType;
  setDefaultFunctionType(fnType);
  Mantid::Kernel::ConfigService::Instance().setString(
      "curvefitting.defaultPeak", fnType);
}
/// Get the default background type
std::string FitPropertyBrowser::defaultBackgroundType() const {
  return m_defaultBackground;
}
/// Set the default background type
void FitPropertyBrowser::setDefaultBackgroundType(const std::string &fnType) {
  m_defaultBackground = fnType;
  setDefaultFunctionType(fnType);
}

boost::shared_ptr<Mantid::API::Workspace>
FitPropertyBrowser::getWorkspace() const {
  std::string wsName = workspaceName();
  if (wsName.empty())
    return boost::shared_ptr<Mantid::API::Workspace>();
  try {
    if (m_settingsGroup->property()->subProperties().contains(m_xColumn)) {
    return Mantid::API::AnalysisDataService::Instance().retrieve(wsName);
    return boost::shared_ptr<Mantid::API::Workspace>();
  }
}

/// Get the input workspace name
std::string FitPropertyBrowser::workspaceName() const {
  int i = m_enumManager->value(m_workspace);
  std::string res = "";
    res = m_workspaceNames[i].toStdString();
  }
  return res;
}

/// Set the input workspace name
void FitPropertyBrowser::setWorkspaceName(const QString &wsName) {
  int i = m_workspaceNames.indexOf(wsName);
  if (i < 0) {
    // workspace may not be found because add notification hasn't been processed
    // yet
Roman Tolchenov's avatar
Roman Tolchenov committed
    populateWorkspaceNames();
    i = m_workspaceNames.indexOf(wsName);
  }
  if (i >= 0) {
    m_enumManager->setValue(m_workspace, i);
    Mantid::API::MatrixWorkspace_sptr mws;
      mws = boost::dynamic_pointer_cast<Mantid::API::MatrixWorkspace>(
          Mantid::API::AnalysisDataService::Instance().retrieve(
              wsName.toStdString()));
    } catch (Mantid::Kernel::Exception::NotFoundError &) {
      size_t wi = static_cast<size_t>(workspaceIndex());
      if (wi < mws->getNumberHistograms() && !mws->x(wi).empty()) {
        setStartX(mws->x(wi).front());
        setEndX(mws->x(wi).back());
  }
}

/// Get workspace index
int FitPropertyBrowser::workspaceIndex() const {
  return m_intManager->value(m_workspaceIndex);
}

/// Set workspace index
void FitPropertyBrowser::setWorkspaceIndex(int i) {
  m_intManager->setValue(m_workspaceIndex, i);
}

/// Get the output name
std::string FitPropertyBrowser::outputName() const {
  return m_stringManager->value(m_output).toStdString();
}

void FitPropertyBrowser::setOutputName(const std::string &name) {
  m_stringManager->setValue(m_output, QString::fromStdString(name));
}

/// Get the minimizer
std::string FitPropertyBrowser::minimizer(bool withProperties) const {
  int i = m_enumManager->value(m_minimizer);
  QString minimStr = m_minimizers[i];
  // append minimizer properties as name=value pairs
  if (withProperties) {
    foreach (QtProperty *prop, m_minimizerProperties) {
      if (prop->propertyManager() == m_stringManager) {
        QString value = m_stringManager->value(prop);
          minimStr += "," + prop->propertyName() + "=" + value;
        }
        minimStr += "," + prop->propertyName() + "=";
        if (prop->propertyManager() == m_intManager) {
          minimStr += QString::number(m_intManager->value(prop));
        } else if (prop->propertyManager() == m_doubleManager) {
          minimStr += QString::number(m_doubleManager->value(prop));
        } else if (prop->propertyManager() == m_boolManager) {
          minimStr += QString::number(m_boolManager->value(prop));
        } else {
          throw std::runtime_error("The fit browser doesn't support the type "
                                   "of minimizer's property " +
                                   prop->propertyName().toStdString());
/// Get the ignore invalid data option
bool FitPropertyBrowser::ignoreInvalidData() const {
  return m_boolManager->value(m_ignoreInvalidData);
void FitPropertyBrowser::setIgnoreInvalidData(bool on) {
  m_boolManager->setValue(m_ignoreInvalidData, on);
/// Get the cost function
std::string FitPropertyBrowser::costFunction() const {
  int i = m_enumManager->value(m_costFunction);
  return m_costFunctions[i].toStdString();
}

 * Get the "ConvolveMembers" option
 */
bool FitPropertyBrowser::convolveMembers() const {
  return m_boolManager->value(m_convolveMembers);
/// Get "HistogramFit" option
bool FitPropertyBrowser::isHistogramFit() const {
  if (!m_evaluationType->isEnabled()) {
    return false;
  }
  int i = m_enumManager->value(m_evaluationType);
  return m_evaluationTypes[i].toStdString() == "Histogram";
/// Get the max number of iterations
int FitPropertyBrowser::maxIterations() const {
  return m_intManager->value(m_maxIterations);
}

/// Get the peak radius for peak functions
int FitPropertyBrowser::getPeakRadius() const {
  return m_intManager->value(m_peakRadius);
}

/// Get the registered function names
void FitPropertyBrowser::populateFunctionNames() {
  const std::vector<std::string> names =
      Mantid::API::FunctionFactory::Instance().getKeys();
  m_registeredFunctions.clear();
  m_registeredPeaks.clear();
  m_registeredBackgrounds.clear();
  m_registeredOther.clear();

  for (size_t i = 0; i < names.size(); i++) {
    std::string fnName = names[i];
    QString qfnName = QString::fromStdString(fnName);
    if (qfnName == "MultiBG")
      continue;

    auto f = Mantid::API::FunctionFactory::Instance().createFunction(fnName);
    m_registeredFunctions << qfnName;
    Mantid::API::IPeakFunction *pf =
        dynamic_cast<Mantid::API::IPeakFunction *>(f.get());
    // Mantid::API::CompositeFunction* cf =
    // dynamic_cast<Mantid::API::CompositeFunction*>(f.get());
    if (pf) {
      m_registeredPeaks << qfnName;
    } else if (dynamic_cast<Mantid::API::IBackgroundFunction *>(f.get())) {
      m_registeredBackgrounds << qfnName;
/** Called when the function name property changed
 * @param prop :: A pointer to the function name property m_functionName
 */
void FitPropertyBrowser::enumChanged(QtProperty *prop) {
  if (!m_changeSlotsEnabled)
    return;
  bool storeSettings = false;
  if (prop == m_workspace) {
    workspaceChange(QString::fromStdString(workspaceName()));
    setWorkspaceProperties();
    m_storedWorkspaceName = workspaceName();
  } else if (prop->propertyName() == "Type") {
    disableUndo();
    PropertyHandler *h = getHandler()->findHandler(prop);
    if (!h)
      return;
    // if (!h->parentHandler()) return;
    auto f = h->changeType(prop);
    if (!h->parentHandler()) {
      m_compositeFunction =
          boost::dynamic_pointer_cast<Mantid::API::CompositeFunction>(f);
    }
    if (f)
      setCurrentFunction(f);
    emit functionChanged();
  } else if (prop == m_minimizer) {
  } else if (prop == m_evaluationType) {
    storeSettings = true;
  }

  if (storeSettings) {
    QSettings settings;
    settings.beginGroup("Mantid/FitBrowser");
    auto val = m_enumManager->value(prop);
    settings.setValue(prop->propertyName(), val);
}

/** Called when a bool property changed
 * @param prop :: A pointer to the property
void FitPropertyBrowser::boolChanged(QtProperty *prop) {
  if (!m_changeSlotsEnabled)
    return;
  if (prop == m_plotDiff || prop == m_plotCompositeMembers ||
      prop == m_ignoreInvalidData || prop == m_showParamErrors) {
    bool val = m_boolManager->value(prop);

    QSettings settings;
    settings.beginGroup("Mantid/FitBrowser");
    settings.setValue(prop->propertyName(), val);

    if (prop == m_showParamErrors) {
      m_parameterManager->setErrorsEnabled(val);
      emit errorsEnabled(val);
  } else { // it could be an attribute
    PropertyHandler *h = getHandler()->findHandler(prop);
    if (!h)
      return;
}

/** Called when an int property changed
 * @param prop :: A pointer to the property
void FitPropertyBrowser::intChanged(QtProperty *prop) {
  if (!m_changeSlotsEnabled)
    return;
  if (prop == m_workspaceIndex) {
    Mantid::API::MatrixWorkspace_sptr ws =
        boost::dynamic_pointer_cast<Mantid::API::MatrixWorkspace>(
            Mantid::API::AnalysisDataService::Instance().retrieve(
                workspaceName()));
    if (!ws) {
      setWorkspaceIndex(0);
      return;
    }
Doucet, Mathieu's avatar
Doucet, Mathieu committed
    int n = static_cast<int>(ws->getNumberHistograms());
    int wi = workspaceIndex();
      setWorkspaceIndex(0);
    } else if (wi >= n) {
      setWorkspaceIndex(n - 1);
    }
    emit workspaceIndexChanged(wi);
  } else if (prop->propertyName() == "Workspace Index") {
    PropertyHandler *h = getHandler()->findHandler(prop);
    if (!h)
      return;
  } else if (prop == m_maxIterations || prop == m_peakRadius) {
    QSettings settings;
    settings.beginGroup("Mantid/FitBrowser");
    int val = m_intManager->value(prop);
    settings.setValue(prop->propertyName(), val);
    if (prop == m_peakRadius) {
      sendParameterChanged(m_compositeFunction.get());
    }
  } else { // it could be an attribute
    PropertyHandler *h = getHandler()->findHandler(prop);
    if (!h)
      return;
    h->setAttribute(prop);
  }
}

/** Called when a double property changed
 * @param prop :: A pointer to the property
void FitPropertyBrowser::doubleChanged(QtProperty *prop) {
  if (!m_changeSlotsEnabled)
    return;

  double value = m_doubleManager->value(prop);
    // call setWorkspace to change maxX in functions
    setWorkspace(m_compositeFunction);
    getHandler()->setAttribute("StartX", value);
    emit startXChanged(startX());
    emit xRangeChanged(startX(), endX());
    return;
  } else if (prop == m_endX) {
    // call setWorkspace to change minX in functions
    setWorkspace(m_compositeFunction);
    getHandler()->setAttribute("EndX", value);
    emit endXChanged(endX());
    emit xRangeChanged(startX(), endX());
    return;
  } else { // check if it is a constraint
    PropertyHandler *h = getHandler()->findHandler(prop);
    if (!h)
      return;

    QtProperty *parProp = h->getParameterProperty(prop);
    if (parProp) {
      if (prop->propertyName() == "LowerBound") {
        double loBound = m_doubleManager->value(prop);
        h->addConstraint(parProp, true, false, loBound, 0);
      } else if (prop->propertyName() == "UpperBound") {
        double upBound = m_doubleManager->value(prop);
        h->addConstraint(parProp, false, true, 0, upBound);
    } else { // it could be an attribute
      h->setAttribute(prop);
    }
  }
}
 * Called when one of the parameter values gets changed. This could be caused
 * either by user setting
 * the value or programmatically.
 * @param prop :: Parameter property which value got changed
 */
void FitPropertyBrowser::parameterChanged(QtProperty *prop) {
  if (!m_changeSlotsEnabled)
    return;
/** Called when a string property changed
 * @param prop :: A pointer to the property
void FitPropertyBrowser::stringChanged(QtProperty *prop) {
  if (!m_changeSlotsEnabled)
    return;
    std::string oName = outputName();
    if (oName.find_first_not_of(' ') == std::string::npos) {
      setOutputName("");
    } else if (workspaceName() == oName || oName.empty()) {
      m_guessOutputName = true;
      m_guessOutputName = false;
    }
  } else if (prop->propertyName() == "Tie") {
    PropertyHandler *h = getHandler()->findHandler(prop);
    if (!h)
      return;
    QtProperty *parProp = h->getParameterProperty(prop);
    if (!parProp)
      return;
    QString parName = h->functionPrefix() + "." + parProp->propertyName();

    QString str = m_stringManager->value(prop);
    Mantid::API::ParameterTie *tie = new Mantid::API::ParameterTie(
        compositeFunction().get(), parName.toStdString());
    try {
      tie->set(str.toStdString());
      h->addTie(parName + "=" + str);
    } catch (...) {
      std::cerr << "Failed\n";
    }
    delete tie;
  } else if (getHandler()->setAttribute(
                 prop)) { // setting an attribute may change function parameters
    emit functionChanged();
    return;
  }
}

/** Called when a filename property changed
 * @param prop :: A pointer to the property
void FitPropertyBrowser::filenameChanged(QtProperty *prop) {
  if (!m_changeSlotsEnabled)
    return;
  if (getHandler()->setAttribute(prop)) {
    return;
  }
}
// Centre of the current peak
double FitPropertyBrowser::centre() const {
  if (m_currentHandler && m_currentHandler->pfun()) {
    return m_currentHandler->pfun()->centre();
  }
  return 0;
}

/** Set centre of the current peak
 * @param value :: The new centre value
 */
void FitPropertyBrowser::setCentre(double value) {
  if (m_currentHandler) {
    m_currentHandler->setCentre(value);
    m_currentHandler->updateParameters();
    emit parameterChanged(m_currentHandler->function().get());
  }
}

// Height of the current peak
double FitPropertyBrowser::height() const {
  if (m_currentHandler && m_currentHandler->pfun()) {
    return m_currentHandler->pfun()->height();
  }
  return 0.;
}

/** Set height of the current peak
 * @param value :: The new height value
 */
void FitPropertyBrowser::setHeight(double value) {
  if (m_currentHandler) {
    m_currentHandler->setHeight(value);
    m_currentHandler->updateParameters();
    emit parameterChanged(m_currentHandler->function().get());
  }
}

// Width of the current peak
double FitPropertyBrowser::fwhm() const {
  if (m_currentHandler && m_currentHandler->pfun()) {
    return m_currentHandler->pfun()->fwhm();
  }
  return 0;
}

/** Set width of the current peak
 * @param value :: The new width value
 */
void FitPropertyBrowser::setFwhm(double value) {
  if (m_currentHandler) {
    m_currentHandler->setFwhm(value);
    m_currentHandler->updateParameters();
    emit parameterChanged(m_currentHandler->function().get());
  }
}

/// Get number of functions in CompositeFunction
int FitPropertyBrowser::count() const {
Doucet, Mathieu's avatar
Doucet, Mathieu committed
  return static_cast<int>(m_compositeFunction->nFunctions());
}

/// Get the current function
PropertyHandler *FitPropertyBrowser::currentHandler() const {
  return m_currentHandler;
}

/** Set new current function
 * @param h :: New current function
 */
void FitPropertyBrowser::setCurrentFunction(PropertyHandler *h) const {
  m_currentHandler = h;
    m_browser->setCurrentItem(m_currentHandler->item());
    emit currentChanged();
  }
}

/** Set new current function
 * @param f :: New current function
 */
void FitPropertyBrowser::setCurrentFunction(
    Mantid::API::IFunction_const_sptr f) const {
  setCurrentFunction(getHandler()->findHandler(f));
}

/**
 * Creates an instance of Fit algorithm, sets its properties and launches it.
 */
void FitPropertyBrowser::doFit(int maxIterations) {
  const std::string wsName = workspaceName();
  if (wsName.empty()) {
    QMessageBox::critical(this, "Mantid - Error", "Workspace name is not set");
  const auto ws = getWorkspace();
    m_initialParameters.resize(compositeFunction()->nParams());
    for (size_t i = 0; i < compositeFunction()->nParams(); i++) {
      m_initialParameters[i] = compositeFunction()->getParameter(i);
    }
    m_fitActionUndoFit->setEnabled(true);
    const std::string funStr = getFittingFunction()->asString();
    Mantid::API::IAlgorithm_sptr alg =
        Mantid::API::AlgorithmManager::Instance().create("Fit");
    if (isHistogramFit()) {
      alg->setProperty("EvaluationType", "Histogram");
    }
    alg->setPropertyValue("Function", funStr);
    alg->setProperty("InputWorkspace", ws);
    alg->setProperty("WorkspaceIndex", workspaceIndex());
    alg->setProperty("StartX", startX());
    alg->setProperty("EndX", endX());
    alg->setPropertyValue("Output", outputName());
    alg->setPropertyValue("Minimizer", minimizer(true));
    alg->setProperty("IgnoreInvalidData", ignoreInvalidData());
    alg->setPropertyValue("CostFunction", costFunction());
    alg->setProperty("MaxIterations", maxIterations);
    alg->setProperty("PeakRadius", getPeakRadius());
    if (!isHistogramFit()) {
      alg->setProperty("Normalise", m_shouldBeNormalised);
      // Always output each composite function but not necessarily plot it
      alg->setProperty("OutputCompositeMembers", true);
      if (alg->existsProperty("ConvolveMembers")) {
        alg->setProperty("ConvolveMembers", convolveMembers());
      }
    observeFinish(alg);
    alg->executeAsync();
  } catch (const std::exception &e) {
    QString msg = "Fit algorithm failed.\n\n" + QString(e.what()) + "\n";
    QMessageBox::critical(this, "Mantid - Error", msg);
 * Return the function that will be passed to Fit.
 */
Mantid::API::IFunction_sptr FitPropertyBrowser::getFittingFunction() const {
  Mantid::API::IFunction_sptr function;
  if (m_compositeFunction->nFunctions() > 1) {
    function = m_compositeFunction;
  } else {
    function = m_compositeFunction->getFunction(0);
  }
  return function;
}

void FitPropertyBrowser::finishHandle(const Mantid::API::IAlgorithm *alg) {
  // Emit a signal to show that the fitting has completed. (workspaceName that
  // the fit has been done against is sent as a parameter)
  QString name(QString::fromStdString(alg->getProperty("InputWorkspace")));
  if (name.contains('_')) // Must be fitting to raw data, need to group under
    // name without "_Raw".
    emit fittingDone(name.left(name.indexOf('_')));
  else // else fitting to current workspace, group under same name.
    emit fittingDone(name);
  getFitResults();
  if (!isWorkspaceAGroup() && alg->existsProperty("OutputWorkspace")) {
    std::string out = alg->getProperty("OutputWorkspace");
    emit algorithmFinished(QString::fromStdString(out));
  }
  // Update Status string
  auto status = QString::fromStdString(alg->getPropertyValue("OutputStatus"));
  emit fitResultsChanged(status);
  if (m_displayActionQuality->isChecked()) {
    double quality = alg->getProperty("OutputChi2overDoF");
    std::string costFunction = alg->getProperty("CostFunction");
    boost::shared_ptr<Mantid::API::ICostFunction> costfun =
        Mantid::API::CostFunctionFactory::Instance().create(costFunction);
    if (status != "success") {
      status = "failed";
    }
    emit changeWindowTitle(QString("Fit Function (") +
                           costfun->shortName().c_str() + " = " +
                           QString::number(quality) + ", " + status + ")");
    emit changeWindowTitle("Fit Function");
  if (m_compositeFunction->name() == "MultiBG") {
/// Display the status string returned from Fit
/// @param status :: A status string as returned by OutputStatus Fit property.
void FitPropertyBrowser::showFitResultStatus(const QString &status) {
  auto text(status);
  text.replace("\n", "<br>");
  QString color("green");
  if (status != "success") {
    color = "red";
  }
  m_status->setText(
Anthony Lim's avatar
Anthony Lim committed
      QString("Status: <span style='color:%2'>%1</span>").arg(text, color));
  m_status->show();
}

/// Clear the Fit status display
void FitPropertyBrowser::clearFitResultStatus() {
  m_status->setText("Status:");
  m_status->hide();
}

/// Get and store available workspace names
void FitPropertyBrowser::populateWorkspaceNames() {
  m_workspaceNames.clear();
  // QStringList tmp = m_appWindow->mantidUI->getWorkspaceNames();
  auto sv = Mantid::API::AnalysisDataService::Instance().getObjectNames();
  for (auto it = sv.begin(); it != sv.end(); ++it) {
    tmp << QString::fromStdString(*it);
  for (int i = 0; i < tmp.size(); i++) {
    Mantid::API::Workspace_sptr ws =
        Mantid::API::AnalysisDataService::Instance().retrieve(
            tmp[i].toStdString());
    if (isWorkspaceValid(ws)) {
      m_workspaceNames.append(tmp[i]);
    }
  }
  m_enumManager->setEnumNames(m_workspace, m_workspaceNames);
}

Roman Tolchenov's avatar
Roman Tolchenov committed
/**
 * Connect to the AnalysisDataService when shown
void FitPropertyBrowser::showEvent(QShowEvent *e) {
Roman Tolchenov's avatar
Roman Tolchenov committed
  (void)e;
  // Observe what workspaces are added and deleted unless it's a custom fitting,
  // all workspaces for custom fitting (eg muon analysis)
Roman Tolchenov's avatar
Roman Tolchenov committed
  // should be manually added.
  populateWorkspaceNames();
Roman Tolchenov's avatar
Roman Tolchenov committed
/**
 * Disconnect from the AnalysisDataService when hiden
void FitPropertyBrowser::hideEvent(QHideEvent *e) {
Roman Tolchenov's avatar
Roman Tolchenov committed
  (void)e;
void FitPropertyBrowser::setADSObserveEnabled(bool enabled) {
  observeAdd(enabled);
  observePostDelete(enabled);
void FitPropertyBrowser::addHandle(
    const std::string &wsName,
    const boost::shared_ptr<Mantid::API::Workspace> ws) {
  if (!isWorkspaceValid(ws))
    return;
  QStringList oldWorkspaces = m_workspaceNames;
  QString oldName = QString::fromStdString(workspaceName());
  int i = m_workspaceNames.indexOf(QString(wsName.c_str()));

  bool initialSignalsBlocked = m_enumManager->signalsBlocked();

  // if new workspace append this workspace name
  if (i < 0) {
    if (!m_workspaceNames.isEmpty()) {
    m_workspaceNames.append(QString(wsName.c_str()));
    m_workspaceNames.sort();
    m_enumManager->setEnumNames(m_workspace, m_workspaceNames);
  if (i >= 0) {
    m_enumManager->setValue(m_workspace, i);

  m_enumManager->blockSignals(initialSignalsBlocked);
  /*
  if (m_workspaceNames.size() == 1)
  {
    setWorkspaceName(QString::fromStdString(wsName));
  }
/// workspace was removed
void FitPropertyBrowser::postDeleteHandle(const std::string &wsName) {
  QStringList oldWorkspaces = m_workspaceNames;
  QString oldName = QString::fromStdString(workspaceName());
  int i = m_workspaceNames.indexOf(QString(wsName.c_str()));
    m_workspaceNames.removeAt(i);
  }

  bool initialSignalsBlocked = m_enumManager->signalsBlocked();

  if (QString::fromStdString(wsName) != oldName) {
  m_enumManager->setEnumNames(m_workspace, m_workspaceNames);
  i = m_workspaceNames.indexOf(oldName);
  if (i >= 0) {
    m_enumManager->setValue(m_workspace, i);
  }

  m_enumManager->blockSignals(initialSignalsBlocked);
/** Check if the workspace can be used in the fit. The accepted types are
 * MatrixWorkspaces same size
 * @param ws :: The workspace
 */
bool FitPropertyBrowser::isWorkspaceValid(
    Mantid::API::Workspace_sptr ws) const {
  return (dynamic_cast<Mantid::API::MatrixWorkspace *>(ws.get()) != 0 ||
          dynamic_cast<Mantid::API::ITableWorkspace *>(ws.get()) != 0);
bool FitPropertyBrowser::isWorkspaceAGroup() const {
  // MG: Disabled as there is an issue with replacing workspace groups and the
  // browser
  return false;
}

/// Is the current function a peak?
bool FitPropertyBrowser::isPeak() const {
  if (count() == 0) {
    return false;
  }
  return m_currentHandler && m_currentHandler->pfun();
}

/// Get the start X
double FitPropertyBrowser::startX() const {
  return m_doubleManager->value(m_startX);
}

/// Set the start X
void FitPropertyBrowser::setStartX(double value) {
  m_doubleManager->setValue(m_startX, value);
}

/// Get the end X
double FitPropertyBrowser::endX() const {
  return m_doubleManager->value(m_endX);
}

/// Set the end X
void FitPropertyBrowser::setEndX(double value) {
  m_doubleManager->setValue(m_endX, value);
QtBrowserItem *FitPropertyBrowser::findItem(QtBrowserItem *parent,
                                            QtProperty *prop) const {
  QList<QtBrowserItem *> children = parent->children();
  QtBrowserItem *res = nullptr;
  for (int i = 0; i < children.size(); i++) {
    if (children[i]->property() == prop) {
      return children[i];
    }
    QList<QtBrowserItem *> grand_children = children[i]->children();
    if (grand_children.size() > 0)
      res = findItem(children[i], prop);
    if (res)
      return res;
}

/**
 * Slot. Responds to changing the current item
 */
void FitPropertyBrowser::currentItemChanged(QtBrowserItem *current) {
  if (current) {
    m_currentHandler = getHandler()->findHandler(current->property());
    m_currentHandler = nullptr;
  }
  emit currentChanged();
}

/**
 * Slot. Responds to changing a vector attribute member
 * @param prop :: A property managed by m_vectorDoubleManager.
 */
void FitPropertyBrowser::vectorDoubleChanged(QtProperty *prop) {
  PropertyHandler *h = getHandler()->findHandler(prop);
  if (!h)
    return;
  h->setVectorAttribute(prop);
/**
 * Slot. Responds to changing a vector attribute size
 * @param prop :: A property managed by m_vectorSizeManager.
 */
void FitPropertyBrowser::vectorSizeChanged(QtProperty *prop) {
  PropertyHandler *h = getHandler()->findHandler(prop);
  if (!h)
    return;
  h->setVectorAttribute(prop);
 * Update the function parameter properties
void FitPropertyBrowser::updateParameters() {
  getHandler()->updateParameters();
}

/**
 * Slot. Removes all functions.
 */
void FitPropertyBrowser::clear() {
  getHandler()->removeAllPlots();
  clearBrowser();
  createCompositeFunction();
  emit functionCleared();
}

void FitPropertyBrowser::clearBrowser() {
  QList<QtProperty *> props = m_functionsGroup->property()->subProperties();
  foreach (QtProperty *prop, props) {
    m_functionsGroup->property()->removeSubProperty(prop);
  }
}

/// Set the parameters to the fit outcome
void FitPropertyBrowser::getFitResults() {
  std::string wsName = outputName() + "_Parameters";
  if (Mantid::API::AnalysisDataService::Instance().doesExist(wsName)) {
    Mantid::API::ITableWorkspace_sptr ws =
        boost::dynamic_pointer_cast<Mantid::API::ITableWorkspace>(
            Mantid::API::AnalysisDataService::Instance().retrieve(wsName));
    Mantid::API::TableRow row = ws->getFirstRow();
        double value, error;
        row >> name >> value >> error;

        // In case of a single function Fit doesn't create a CompositeFunction
        if (count() == 1) {
          name.insert(0, "f0.");

        size_t paramIndex = compositeFunction()->parameterIndex(name);

        compositeFunction()->setParameter(paramIndex, value);
        compositeFunction()->setError(paramIndex, error);
    updateParameters();
    getHandler()->updateErrors();
  }
}

/**
 * Slot. Undoes the fit: restores the parameters to their initial values.
 */
void FitPropertyBrowser::undoFit() {
  if (m_initialParameters.size() == compositeFunction()->nParams()) {
    for (size_t i = 0; i < compositeFunction()->nParams(); i++) {
      compositeFunction()->setParameter(i, m_initialParameters[i]);
    clearFitResultStatus();
    updateParameters();
    getHandler()->clearErrors();
    emit fitUndone();
  }
  disableUndo();
}

/// disable undo when the function changes
void FitPropertyBrowser::disableUndo() {
  m_initialParameters.clear();
  m_fitActionUndoFit->setEnabled(false);
}

/// Tells if undo can be done
bool FitPropertyBrowser::isUndoEnabled() const {
  return m_initialParameters.size() &&
         compositeFunction()->nParams() == m_initialParameters.size();
}

/// Enable/disable the Fit button;
void FitPropertyBrowser::setFitEnabled(bool yes) {
  m_fitActionFit->setEnabled(yes);
  m_fitActionSeqFit->setEnabled(yes);
}

/// Returns true if the function is ready for a fit
bool FitPropertyBrowser::isFitEnabled() const {
  return m_fitActionFit->isEnabled();
 * Slot. Adds a tie. Full expression to be entered \<name\>=\<formula\>
void FitPropertyBrowser::addTie() {
  QtBrowserItem *ci = m_browser->currentItem();
  QtProperty *paramProp = ci->property();
  PropertyHandler *h = getHandler()->findHandler(paramProp);
  if (!h)
    return;
  if (!h->isParameter(paramProp))
    return;
  auto f = h->function();

  bool ok = false;
  QString tieStr =
      QInputDialog::getText(this, "MantidPlot - Fit", "Enter tie expression",
                            QLineEdit::Normal, "", &ok);
  if (ok) {
    tieStr = tieStr.trimmed();
    if (!tieStr.contains('=')) {