Newer
Older
#include "MantidAPI/AlgorithmManager.h"
#include "MantidAPI/IWorkspaceProperty.h"
#include "MantidKernel/DateAndTimeHelpers.h"
#include "MantidKernel/Logger.h"
#include "MantidQtWidgets/Common/AlgorithmDialog.h"
#include "MantidQtWidgets/Common/AlgorithmInputHistory.h"
#include "MantidQtWidgets/Common/FilePropertyWidget.h"
#include "MantidQtWidgets/Common/HelpWindow.h"
#include "MantidQtWidgets/Common/MantidWidget.h"
Gigg, Martyn Anthony
committed
Gigg, Martyn Anthony
committed
#include <QIcon>
#include <QLabel>
Gigg, Martyn Anthony
committed
#include <QLineEdit>
Gigg, Martyn Anthony
committed
#include <QPushButton>
#include <Poco/ActiveResult.h>
Gigg, Martyn Anthony
committed
using namespace MantidQt::API;
using namespace Mantid::Kernel::DateAndTimeHelpers;
using Mantid::Types::Core::DateAndTime;
Gigg, Martyn Anthony
committed
namespace {
Mantid::Kernel::Logger g_log("AlgorithmDialog");
Gigg, Martyn Anthony
committed
//------------------------------------------------------
// Public member functions
//------------------------------------------------------
/**
* Default Constructor
*/
AlgorithmDialog::AlgorithmDialog(QWidget *parent)
: QDialog(parent), m_algorithm(), m_algName(""), m_algProperties(),
m_propertyValueMap(), m_tied_properties(), m_forScript(false),
m_python_arguments(), m_enabled(), m_disabled(), m_strMessage(""),
m_keepOpen(false), m_msgAvailable(false), m_isInitialized(false),
m_autoParseOnInit(true), m_validators(), m_noValidation(),
m_inputws_opts(), m_outputws_fields(), m_wsbtn_tracker(),
m_keepOpenCheckBox(nullptr), m_okButton(nullptr), m_exitButton(nullptr),
m_observers(), m_btnTimer(), m_statusTracked(false) {
Gigg, Martyn Anthony
committed
}
/**
* Destructor
*/
AlgorithmDialog::~AlgorithmDialog() {
if (m_statusTracked) {
this->stopObserving(m_algorithm);
}
/**
* Set if the keep open option is shown.
* This must be set after calling initializeLayout.
* @param showOption false to hide the control, otherwise true
*/
void AlgorithmDialog::setShowKeepOpen(const bool showOption) {
if (m_keepOpenCheckBox) {
// if hidden then turn it off
if (!showOption) {
m_keepOpenCheckBox->setCheckState(Qt::CheckState::Unchecked);
}
m_keepOpenCheckBox->setVisible(showOption);
}
}
/**
* Is the keep open option going to be shown?
* @returns true if it will be shown
*/
bool AlgorithmDialog::isShowKeepOpen() const {
if (m_keepOpenCheckBox) {
retval = m_keepOpenCheckBox->isVisible();
}
return retval;
Gigg, Martyn Anthony
committed
}
/**
* Create the layout for this dialog.
*
* The default is to execute the algorithm when accept() is called. This
* assumes that the AlgorithmManager owns the
* algorithm pointer as it must survive after the dialog is destroyed.
Gigg, Martyn Anthony
committed
*/
void AlgorithmDialog::initializeLayout() {
if (isInitialized())
return;
Gigg, Martyn Anthony
committed
// Set a common title
setWindowTitle(QString::fromStdString(getAlgorithm()->name()) +
" input dialog");
// Set the icon
Gigg, Martyn Anthony
committed
setWindowIcon(QIcon(":/MantidPlot_Icon_32offset.png"));
// These containers are for ensuring the 'replace input workspace; button
// works correctly
Gigg, Martyn Anthony
committed
// Store all combo boxes that relate to an input workspace
Gigg, Martyn Anthony
committed
m_inputws_opts.clear();
Gigg, Martyn Anthony
committed
// Store all line edit fields that relate to an output workspace name
Gigg, Martyn Anthony
committed
m_outputws_fields.clear();
// Keep track of the input workspace that has been used to fill the output
// workspace. Each button click
Gigg, Martyn Anthony
committed
// cycles through all of the input workspaces
Gigg, Martyn Anthony
committed
m_wsbtn_tracker.clear();
Gigg, Martyn Anthony
committed
// This derived class function creates the layout of the widget. It can also
// add default input if the
Gigg, Martyn Anthony
committed
// dialog has been written this way
Gigg, Martyn Anthony
committed
this->initLayout();
Gigg, Martyn Anthony
committed
if (m_autoParseOnInit) {
// Check if there is any default input
this->parse();
// Unless told not to, try to set these values. This will validate the
// defaults and mark those that are invalid, if any.
this->setPropertyValues();
}
Gigg, Martyn Anthony
committed
executeOnAccept(true);
connect(this, SIGNAL(algCompletedSignal()), this, SLOT(algorithmCompleted()));
Gigg, Martyn Anthony
committed
m_isInitialized = true;
Gigg, Martyn Anthony
committed
}
/**
* Has this dialog been initialized yet
* @returns Whether initialzedLayout has been called yet
*/
bool AlgorithmDialog::isInitialized() const { return m_isInitialized; }
Gigg, Martyn Anthony
committed
//------------------------------------------------------
// Protected member functions
//------------------------------------------------------
Gigg, Martyn Anthony
committed
/**
* Parse input from widgets on the dialog. This function does nothing in the
Gigg, Martyn Anthony
committed
* base class
*/
void AlgorithmDialog::parseInput() {}
Janik Zikovsky
committed
//-------------------------------------------------------------------------------------------------
Gigg, Martyn Anthony
committed
/**
* Save the property values to the input history
*/
void AlgorithmDialog::saveInput() {
Gigg, Martyn Anthony
committed
AlgorithmInputHistory::Instance().clearAlgorithmInput(m_algName);
QStringList::const_iterator pend = m_algProperties.end();
for (QStringList::const_iterator pitr = m_algProperties.begin(); pitr != pend;
++pitr) {
Mantid::Kernel::Property *p = getAlgorithmProperty(*pitr);
if (p->remember()) {
Gigg, Martyn Anthony
committed
QString pName = *pitr;
QString value = m_propertyValueMap.value(pName);
AlgorithmInputHistory::Instance().storeNewValue(
m_algName, QPair<QString, QString>(pName, value));
Gigg, Martyn Anthony
committed
}
}
}
Janik Zikovsky
committed
//-------------------------------------------------------------------------------------------------
Gigg, Martyn Anthony
committed
/**
* Set the algorithm pointer
* @param alg :: A pointer to the algorithm
*/
void AlgorithmDialog::setAlgorithm(Mantid::API::IAlgorithm_sptr alg) {
Gigg, Martyn Anthony
committed
m_algorithm = alg;
m_algName = QString::fromStdString(alg->name());
m_algProperties.clear();
m_tied_properties.clear();
std::vector<Mantid::Kernel::Property *>::const_iterator iend =
alg->getProperties().end();
for (std::vector<Mantid::Kernel::Property *>::const_iterator itr =
alg->getProperties().begin();
itr != iend; ++itr) {
Gigg, Martyn Anthony
committed
Mantid::Kernel::Property *p = *itr;
if (dynamic_cast<Mantid::API::IWorkspaceProperty *>(p) ||
p->direction() != Mantid::Kernel::Direction::Output) {
m_algProperties.append(QString::fromStdString(p->name()));
Gigg, Martyn Anthony
committed
}
}
Gigg, Martyn Anthony
committed
m_validators.clear();
m_noValidation.clear();
}
Gigg, Martyn Anthony
committed
/**
* Get the algorithm pointer
* @returns A pointer to the algorithm that is associated with the dialog
*/
Mantid::API::IAlgorithm_sptr AlgorithmDialog::getAlgorithm() const {
Gigg, Martyn Anthony
committed
return m_algorithm;
}
/**
Gigg, Martyn Anthony
committed
* Get a named property for this algorithm
Janik Zikovsky
committed
* @param propName :: The name of the property
Gigg, Martyn Anthony
committed
*/
Mantid::Kernel::Property *
AlgorithmDialog::getAlgorithmProperty(const QString &propName) const {
if (m_algProperties.contains(propName)) {
Gigg, Martyn Anthony
committed
return m_algorithm->getProperty(propName.toStdString());
Gigg, Martyn Anthony
committed
}
Gigg, Martyn Anthony
committed
/**
* Return a true if the given property requires user input
* @param propName :: The name of the property
*/
bool AlgorithmDialog::requiresUserInput(const QString &propName) const {
Gigg, Martyn Anthony
committed
return m_algProperties.contains(propName);
}
Janik Zikovsky
committed
//-------------------------------------------------------------------------------------------------
Gigg, Martyn Anthony
committed
* Get an input value from the form, dealing with blank inputs etc
* @param propName :: The name of the property
*/
QString AlgorithmDialog::getInputValue(const QString &propName) const {
Gigg, Martyn Anthony
committed
QString value = m_propertyValueMap.value(propName);
if (value.isEmpty()) {
Mantid::Kernel::Property *prop = getAlgorithmProperty(propName);
if (prop)
return QString::fromStdString(prop->getDefault());
else
return "";
Gigg, Martyn Anthony
committed
}
Gigg, Martyn Anthony
committed
return value;
}
Janik Zikovsky
committed
//-------------------------------------------------------------------------------------------------
/** Get or make a property validator label (that little red star)
*
* @param propname :: name of the Property
* @return the QLabel pointer. Will create one if needed.
Gigg, Martyn Anthony
committed
*/
QLabel *AlgorithmDialog::getValidatorMarker(const QString &propname) {
if (m_noValidation.contains(propname))
return nullptr;
QLabel *validLbl(nullptr);
if (!m_validators.contains(propname)) {
validLbl = new QLabel("*", this);
Gigg, Martyn Anthony
committed
QPalette pal = validLbl->palette();
pal.setColor(QPalette::WindowText, Qt::darkRed);
validLbl->setPalette(pal);
Gigg, Martyn Anthony
committed
m_validators[propname] = validLbl;
Gigg, Martyn Anthony
committed
validLbl = m_validators.value(propname);
}
return validLbl;
Gigg, Martyn Anthony
committed
}
//-------------------------------------------------------------------------------------------------
Gigg, Martyn Anthony
committed
/**
* Adds a property (name,value) pair to the stored map
*/
void AlgorithmDialog::storePropertyValue(const QString &name,
const QString &value) {
if (name.isEmpty())
return;
Gigg, Martyn Anthony
committed
m_propertyValueMap.insert(name, value);
}
//-------------------------------------------------------------------------------------------------
/**
* Adds a property (name,value) pair to the stored map.
* @param name :: The name of the property.
*/
void AlgorithmDialog::removePropertyValue(const QString &name) {
if (name.isEmpty())
return;
m_propertyValueMap.remove(name);
}
Janik Zikovsky
committed
//-------------------------------------------------------------------------------------------------
/** Show the validators for all the properties */
void AlgorithmDialog::showValidators() {
// Do nothing for non-generic algorithm dialogs
QStringList::const_iterator pend = m_algProperties.end();
for (QStringList::const_iterator pitr = m_algProperties.begin(); pitr != pend;
++pitr) {
const QString propName = *pitr;
// Find the widget for this property.
if (m_tied_properties.contains(propName)) {
// Show/hide the validator label (that red star)
QString error = "";
if (m_errors.contains(propName))
error = m_errors[propName];
QLabel *validator = getValidatorMarker(propName);
// If there's no validator then assume it's handling its own validation
// notification
if (validator && validator->parent()) {
validator->setToolTip(error);
validator->setVisible(error.length() != 0);
} // for each property
Janik Zikovsky
committed
}
//-------------------------------------------------------------------------------------------------
/** Sets the value of a single property, using the value previously stored using
* storePropertyValue()
*
* @param pName :: name of the property to set
* @param validateOthers :: set to true to validate, enable, or hide ALL other
* properties after.
* Set false if you are setting ALL property values and do it once at the
* end.
Janik Zikovsky
committed
* @return true if the property is valid.
*/
bool AlgorithmDialog::setPropertyValue(const QString pName,
bool validateOthers) {
// Mantid::Kernel::Property *p = getAlgorithmProperty(pName);
Janik Zikovsky
committed
QString value = getInputValue(pName);
std::string error("");
try {
// error = p->setValue(value.toStdString());
getAlgorithm()->setPropertyValue(pName.toStdString(), value.toStdString());
} catch (std::exception &err_details) {
Janik Zikovsky
committed
error = err_details.what();
}
// Save the error string for later
m_errors[pName] = QString::fromStdString(error).trimmed();
Janik Zikovsky
committed
// Go through all the other properties' validators
if (validateOthers)
Janik Zikovsky
committed
// Prop was valid if the error string is empty
return error.empty();
}
//-------------------------------------------------------------------------------------------------
/** Set the properties that have been parsed from the dialog.
*
* @param skipList :: An optional list of property names whose values will not
* be set
Janik Zikovsky
committed
* @returns A boolean that indicates if the validation was successful.
*/
bool AlgorithmDialog::setPropertyValues(const QStringList &skipList) {
Janik Zikovsky
committed
QStringList::const_iterator pend = m_algProperties.end();
bool allValid(true);
for (QStringList::const_iterator pitr = m_algProperties.begin(); pitr != pend;
++pitr) {
Janik Zikovsky
committed
const QString pName = *pitr;
if (skipList.contains(pName)) {
Janik Zikovsky
committed
// For the load dialog, skips setting some properties
Mantid::Kernel::Property *p = getAlgorithmProperty(pName);
std::string error = p->isValid();
m_errors[pName] = QString::fromStdString(error).trimmed();
if (!error.empty())
allValid = false;
} else {
Janik Zikovsky
committed
bool thisValid = this->setPropertyValue(pName, false);
allValid = allValid && thisValid;
}
Gigg, Martyn Anthony
committed
}
Janik Zikovsky
committed
// Do additional validation on the WHOLE set of properties
// But only if the individual validation passed
if (allValid) {
std::map<std::string, std::string> errs = m_algorithm->validateInputs();
for (auto it = errs.begin(); it != errs.end(); it++) {
// only count as an error if the named property exists
if (m_algorithm->existsProperty(it->first)) {
const QString pName = QString::fromStdString(it->first);
const QString value = QString::fromStdString(it->second);
if (m_errors.contains(pName)) {
if (!m_errors[pName].isEmpty())
m_errors[pName] += "\n";
m_errors[pName] += value;
m_errors[pName] = value;
// There is at least one whole-algo error
allValid = false;
}
// OK all the values have been set once. Time to look for which should be
// enabled
Janik Zikovsky
committed
Gigg, Martyn Anthony
committed
return allValid;
}
Janik Zikovsky
committed
//-------------------------------------------------------------------------------------------------
Gigg, Martyn Anthony
committed
/**
Gigg, Martyn Anthony
committed
* Return the message string
* @returns the message string
Gigg, Martyn Anthony
committed
*/
const QString &AlgorithmDialog::getOptionalMessage() const {
Gigg, Martyn Anthony
committed
return m_strMessage;
Gigg, Martyn Anthony
committed
}
Janik Zikovsky
committed
//-------------------------------------------------------------------------------------------------
/** Add the optional message in a light yellow box to the layout
*
* @param mainLay :: layout
*/
void AlgorithmDialog::addOptionalMessage(QVBoxLayout *mainLay) {
QLabel *inputMessage = new QLabel(this);
inputMessage->setFrameStyle(QFrame::Panel | QFrame::Sunken);
QPalette pal = inputMessage->palette();
pal.setColor(inputMessage->backgroundRole(),
QColor(255, 255, 224)); // Light yellow
pal.setColor(inputMessage->foregroundRole(), Qt::black);
inputMessage->setPalette(pal);
inputMessage->setAutoFillBackground(true);
inputMessage->setWordWrap(true);
inputMessage->setAlignment(Qt::AlignJustify);
inputMessage->setMargin(3);
inputMessage->setText(getOptionalMessage());
QHBoxLayout *msgArea = new QHBoxLayout;
msgArea->addWidget(inputMessage);
mainLay->addLayout(msgArea, 0);
Janik Zikovsky
committed
//-------------------------------------------------------------------------------------------------
Gigg, Martyn Anthony
committed
/**
Gigg, Martyn Anthony
committed
* Was this dialog raised from a script? This is important when deciding what to
* do with properties that have old input
Gigg, Martyn Anthony
committed
* @returns A boolean inidcating whether we are being called from a script
Gigg, Martyn Anthony
committed
*/
bool AlgorithmDialog::isForScript() const { return m_forScript; }
Gigg, Martyn Anthony
committed
Gigg, Martyn Anthony
committed
/*
* Is there a message string available
* @returns A boolean indicating whether the message string is empty
Gigg, Martyn Anthony
committed
*/
bool AlgorithmDialog::isMessageAvailable() const {
Gigg, Martyn Anthony
committed
return !m_strMessage.isEmpty();
Gigg, Martyn Anthony
committed
}
Janik Zikovsky
committed
//-------------------------------------------------------------------------------------------------
Gigg, Martyn Anthony
committed
/**
Gigg, Martyn Anthony
committed
* Check if the control should be enabled for this property
Janik Zikovsky
committed
* @param propName :: The name of the property
Gigg, Martyn Anthony
committed
*/
bool AlgorithmDialog::isWidgetEnabled(const QString &propName) const {
Janik Zikovsky
committed
// To avoid errors
if (propName.isEmpty())
return true;
Gigg, Martyn Anthony
committed
// Otherwise it must be disabled but only if it is valid
Mantid::Kernel::Property *property = getAlgorithmProperty(propName);
if (!property)
return true;
Janik Zikovsky
committed
if (!isForScript()) {
Janik Zikovsky
committed
// Regular C++ algo. Let the property tell us,
// possibly using validators, if it is to be shown enabled
if (property->getSettings())
return property->getSettings()->isEnabled(getAlgorithm().get());
else
return true;
Gigg, Martyn Anthony
committed
// Algorithm dialog was called from a script(i.e. Python)
// Keep things enabled if requested
if (m_enabled.contains(propName))
return true;
Janik Zikovsky
committed
Gigg, Martyn Anthony
committed
/**
* The control is disabled if
* (1) It is contained in the disabled list or
* (2) A user passed a value into the dialog
*/
Janik Zikovsky
committed
return !(m_disabled.contains(propName) ||
m_python_arguments.contains(propName));
Gigg, Martyn Anthony
committed
}
}
Janik Zikovsky
committed
//-------------------------------------------------------------------------------------------------
Lynch, Vickie
committed
/**
* UnTie a property
* @param property :: The name of the property to tie the given widget to
*/
void AlgorithmDialog::untie(const QString &property) {
if (m_tied_properties.contains(property)) {
Lynch, Vickie
committed
m_tied_properties.remove(property);
}
}
Janik Zikovsky
committed
//-------------------------------------------------------------------------------------------------
Gigg, Martyn Anthony
committed
/**
Gigg, Martyn Anthony
committed
* Tie together an input widget and a property
Janik Zikovsky
committed
* @param widget :: The widget that will collect the input
* @param property :: The name of the property to tie the given widget to
* @param parent_layout :: An optional pointer to a QLayout class that is
* reponsible for managing the passed widget.
Gigg, Martyn Anthony
committed
* If given, a validator label will be added for the given input widget
Gigg, Martyn Anthony
committed
* @param readHistory :: If true then a history value will be retrieved
Janik Zikovsky
committed
*
* @return A NULL pointer if a valid label was successfully add to a passed
* parent_layout otherwise it
Janik Zikovsky
committed
* returns a pointer to the QLabel instance marking the validity
Gigg, Martyn Anthony
committed
*/
QWidget *AlgorithmDialog::tie(QWidget *widget, const QString &property,
QLayout *parent_layout, bool readHistory) {
if (m_tied_properties.contains(property))
Gigg, Martyn Anthony
committed
m_tied_properties.remove(property);
Janik Zikovsky
committed
Mantid::Kernel::Property *prop = getAlgorithmProperty(property);
if (prop) { // Set a few things on the widget
widget->setToolTip(QString::fromStdString(prop->briefDocumentation()));
Gigg, Martyn Anthony
committed
widget->setEnabled(isWidgetEnabled(property));
Janik Zikovsky
committed
PropertyWidget *propWidget = qobject_cast<PropertyWidget *>(widget);
Janik Zikovsky
committed
// Save in the hashes
Gigg, Martyn Anthony
committed
m_tied_properties.insert(property, widget);
Gigg, Martyn Anthony
committed
// If the widget's layout has been given then assume that a validator is
// required, else assume not
QWidget *validlbl(nullptr);
if (parent_layout) {
Gigg, Martyn Anthony
committed
// Check if the validator is already there
validlbl = getValidatorMarker(property);
if (validlbl) {
// Find where it was sitting in the layout
int item_index;
if (propWidget)
item_index = parent_layout->indexOf(propWidget->getMainWidget());
else
item_index = parent_layout->indexOf(widget);
if (QBoxLayout *box = qobject_cast<QBoxLayout *>(parent_layout)) {
Gigg, Martyn Anthony
committed
box->insertWidget(item_index + 1, validlbl);
} else if (QGridLayout *grid =
qobject_cast<QGridLayout *>(parent_layout)) {
Gigg, Martyn Anthony
committed
int row(0), col(0), span(0);
grid->getItemPosition(item_index, &row, &col, &span, &span);
grid->addWidget(validlbl, row, col + 2);
} else {
Gigg, Martyn Anthony
committed
}
}
Gigg, Martyn Anthony
committed
m_noValidation.append(property);
Gigg, Martyn Anthony
committed
}
Gigg, Martyn Anthony
committed
if (readHistory) {
Gigg, Martyn Anthony
committed
setPreviousValue(widget, property);
Gigg, Martyn Anthony
committed
}
Gigg, Martyn Anthony
committed
return validlbl;
Gigg, Martyn Anthony
committed
}
Janik Zikovsky
committed
//-------------------------------------------------------------------------------------------------
Gigg, Martyn Anthony
committed
/**
* Open a file selection box. The type of dialog, i.e. load/save will depend on
* the
Gigg, Martyn Anthony
committed
* property type
* @param propName :: The property name that this is associated with.
Gigg, Martyn Anthony
committed
*/
QString AlgorithmDialog::openFileDialog(const QString &propName) {
if (propName.isEmpty())
return "";
return FilePropertyWidget::openFileDialog(
this->getAlgorithmProperty(propName));
Gigg, Martyn Anthony
committed
}
Janik Zikovsky
committed
//-------------------------------------------------------------------------------------------------
Gigg, Martyn Anthony
committed
/**
* Takes a combobox and adds the allowed values of the given property to its
* list.
* It also sets the displayed value to the correct one based on either the
* history
Gigg, Martyn Anthony
committed
* or a script input value
Janik Zikovsky
committed
* @param propName :: The name of the property
* @param optionsBox :: A pointer to a QComoboBox object
Gigg, Martyn Anthony
committed
* @returns A newed QComboBox
*/
void AlgorithmDialog::fillAndSetComboBox(const QString &propName,
QComboBox *optionsBox) const {
if (!optionsBox)
return;
Gigg, Martyn Anthony
committed
Mantid::Kernel::Property *property = getAlgorithmProperty(propName);
if (!property)
return;
std::vector<std::string> items = property->allowedValues();
std::vector<std::string>::const_iterator vend = items.end();
for (std::vector<std::string>::const_iterator vitr = items.begin();
vitr != vend; ++vitr) {
Gigg, Martyn Anthony
committed
optionsBox->addItem(QString::fromStdString(*vitr));
}
// Display the appropriate value
QString displayed("");
if (!isForScript()) {
displayed =
AlgorithmInputHistory::Instance().previousInput(m_algName, propName);
Gigg, Martyn Anthony
committed
}
if (displayed.isEmpty()) {
Gigg, Martyn Anthony
committed
displayed = QString::fromStdString(property->value());
}
int index = optionsBox->findText(displayed);
if (index >= 0) {
Gigg, Martyn Anthony
committed
optionsBox->setCurrentIndex(index);
}
}
Janik Zikovsky
committed
//-------------------------------------------------------------------------------------------------
Gigg, Martyn Anthony
committed
/**
* Set the input for a text box based on either the history or a script value
Janik Zikovsky
committed
* @param propName :: The name of the property
* @param textField :: The QLineEdit field
Gigg, Martyn Anthony
committed
*/
void AlgorithmDialog::fillLineEdit(const QString &propName,
QLineEdit *textField) {
if (!isForScript()) {
textField->setText(
AlgorithmInputHistory::Instance().previousInput(m_algName, propName));
} else {
Gigg, Martyn Anthony
committed
Mantid::Kernel::Property *property = getAlgorithmProperty(propName);
if (property && property->isValid().empty() &&
(m_python_arguments.contains(propName) || !property->isDefault())) {
Gigg, Martyn Anthony
committed
textField->setText(QString::fromStdString(property->value()));
}
Gigg, Martyn Anthony
committed
}
}
Janik Zikovsky
committed
//-------------------------------------------------------------------------------------------------
/** Layout the buttons and others in the generic dialog */
QLayout *AlgorithmDialog::createDefaultButtonLayout(
const QString &helpText, const QString &loadText, const QString &cancelText,
const QString &keepOpenText) {
m_okButton = new QPushButton(loadText);
connect(m_okButton, SIGNAL(clicked()), this, SLOT(accept()));
m_okButton->setDefault(true);
Gigg, Martyn Anthony
committed
m_exitButton = new QPushButton(cancelText);
connect(m_exitButton, SIGNAL(clicked()), this, SLOT(reject()));
Gigg, Martyn Anthony
committed
QHBoxLayout *buttonRowLayout = new QHBoxLayout;
buttonRowLayout->addWidget(createHelpButton(helpText));
buttonRowLayout->addStretch();
m_keepOpenCheckBox = new QCheckBox(keepOpenText);
m_keepOpenCheckBox->setLayoutDirection(Qt::LayoutDirection::RightToLeft);
connect(m_keepOpenCheckBox, SIGNAL(stateChanged(int)), this,
SLOT(keepOpenChanged(int)));
buttonRowLayout->addWidget(m_keepOpenCheckBox);
if (keepOpenText.isEmpty()) {
setShowKeepOpen(false);
}
buttonRowLayout->addWidget(m_okButton);
buttonRowLayout->addWidget(m_exitButton);
Gigg, Martyn Anthony
committed
return buttonRowLayout;
}
Janik Zikovsky
committed
//-------------------------------------------------------------------------------------------------
Gigg, Martyn Anthony
committed
/**
* Create a help button that, when clicked, will open a browser to the Mantid
* wiki page
Gigg, Martyn Anthony
committed
* for that algorithm
*/
QPushButton *AlgorithmDialog::createHelpButton(const QString &helpText) const {
Gigg, Martyn Anthony
committed
QPushButton *help = new QPushButton(helpText);
help->setMaximumWidth(25);
connect(help, SIGNAL(clicked()), this, SLOT(helpClicked()));
return help;
}
Gigg, Martyn Anthony
committed
Gigg, Martyn Anthony
committed
* Flag an input workspace widget
Janik Zikovsky
committed
* @param inputWidget :: A widget used to enter the input workspace
Gigg, Martyn Anthony
committed
*/
void AlgorithmDialog::flagInputWS(QWidget *inputWidget) {
Gigg, Martyn Anthony
committed
m_inputws_opts.push_back(inputWidget);
Gigg, Martyn Anthony
committed
}
Gigg, Martyn Anthony
committed
//-----------------------------------------------------------
// Protected slots
//-----------------------------------------------------------
Gigg, Martyn Anthony
committed
/**
* A slot that can be used to connect a button that accepts the dialog if
* all of the properties are valid
*/
void AlgorithmDialog::accept() {
Gigg, Martyn Anthony
committed
// Get property values
parse();
// Try and set and validate the properties and
if (setPropertyValues()) {
// Store input for next time
Gigg, Martyn Anthony
committed
saveInput();
if (!this->m_keepOpen) {
QDialog::accept();
} else {
executeAlgorithmAsync();
} else {
QMessageBox::critical(
this, "",
"One or more properties are invalid. The invalid properties are\n"
"marked with a *, hold your mouse over the * for more information.");
Gigg, Martyn Anthony
committed
}
//-------------------------------------------------------------------------------------------------
Gigg, Martyn Anthony
committed
/**
* A slot to handle the help button click
*/
void AlgorithmDialog::helpClicked() {
// determine the version to show
int version(-1); // the latest version
version = m_algorithm->version();
// bring up the help window
HelpWindow::showAlgorithm(this->nativeParentWidget(), m_algName, version);
Gigg, Martyn Anthony
committed
}
Gigg, Martyn Anthony
committed
//-------------------------------------------------------------------------------------------------
/**
* A slot to handle the keep open button click
*/
void AlgorithmDialog::keepOpenChanged(int state) {
m_keepOpen = (state == Qt::Checked);
//-------------------------------------------------------------------------------------------------
/**
* Execute the underlying algorithm
*/
void AlgorithmDialog::executeAlgorithmAsync() {
Mantid::API::IAlgorithm_sptr algToExec = m_algorithm;
// Clear any previous trackers so we know what state we are in
this->stopObserving(algToExec);
// Add any custom AlgorithmObservers to the algorithm
for (auto it = m_observers.begin(); it != m_observers.end(); ++it) {
// Only need to observe finish events if we are staying open
if (m_keepOpenCheckBox && m_keepOpenCheckBox->isChecked()) {
this->observeFinish(algToExec);
this->observeError(algToExec);
m_statusTracked = true;
// Disable close button for a short period. If it is clicked to soon then
// Mantid crashes - https://github.com/mantidproject/mantid/issues/13836
if (m_exitButton) {
m_exitButton->setEnabled(false);
m_btnTimer.setInterval(1000);
connect(&m_btnTimer, SIGNAL(timeout()), this, SLOT(enableExitButton()));
} else {
m_statusTracked = false;
if (m_okButton) {
m_okButton->setEnabled(false);
}
} catch (Poco::NoThreadAvailableException &) {
g_log.error() << "No thread was available to run the " << algToExec->name()
<< " algorithm in the background.\n";
//-------------------------------------------------------------------------------------------------
/*
*/
void AlgorithmDialog::removeAlgorithmFromManager() {
using namespace Mantid::API;
AlgorithmManager::Instance().removeById(m_algorithm->getAlgorithmID());
}
void AlgorithmDialog::enableExitButton() { m_exitButton->setEnabled(true); }
Gigg, Martyn Anthony
committed
//------------------------------------------------------
// Private member functions
//------------------------------------------------------
Gigg, Martyn Anthony
committed
/**
* Parse out information from the dialog
*/
void AlgorithmDialog::parse() {
QHashIterator<QString, QWidget *> itr(m_tied_properties);
while (itr.hasNext()) {
Gigg, Martyn Anthony
committed
itr.next();
// Need to do different things depending on the type of the widget. getValue
// sorts this out
Gigg, Martyn Anthony
committed
storePropertyValue(itr.key(), getValue(itr.value()));
}
// Now call parseInput, which can be overridden in an inheriting class
Gigg, Martyn Anthony
committed
parseInput();
}
Janik Zikovsky
committed
//-------------------------------------------------------------------------------------------------
Gigg, Martyn Anthony
committed
/**
* Set a list of values for the properties
* @param presetValues :: A string containing a list of "name=value" pairs with
* each separated by an '|' character
void AlgorithmDialog::setPresetValues(
const QHash<QString, QString> &presetValues) {
if (presetValues.isEmpty())
return;
QHashIterator<QString, QString> itr(presetValues);
Gigg, Martyn Anthony
committed
m_python_arguments.clear();
while (itr.hasNext()) {
Gigg, Martyn Anthony
committed
itr.next();
QString name = itr.key();
Gigg, Martyn Anthony
committed
m_python_arguments.append(name);
Gigg, Martyn Anthony
committed
QString value = itr.value();
storePropertyValue(name, value);
Gigg, Martyn Anthony
committed
}
setPropertyValues();
}
//------------------------------------------------------------------------------------------------
Gigg, Martyn Anthony
committed
* Set list of enabled and disabled parameter names
* @param enabled:: A list of parameter names to keep enabled
* @param disabled:: A list of parameter names whose widgets should be disabled
Gigg, Martyn Anthony
committed
*/
void AlgorithmDialog::addEnabledAndDisableLists(const QStringList &enabled,
const QStringList &disabled) {
Gigg, Martyn Anthony
committed
m_enabled = enabled;
m_disabled = disabled;
Gigg, Martyn Anthony
committed
}
//------------------------------------------------------------------------------------------------
Gigg, Martyn Anthony
committed
/**
* Returns true if the parameter name has been explicity requested to be kept
* enabled. If the parameter
* has been explicity requested to be disabled then return false as well as if
* neither have been specified
Gigg, Martyn Anthony
committed
*/
bool AlgorithmDialog::requestedToKeepEnabled(const QString &propName) const {
Gigg, Martyn Anthony
committed
bool enabled(true);
if (m_disabled.contains(propName)) {
Gigg, Martyn Anthony
committed
enabled = false;
} else if (m_enabled.contains(propName)) // Definitely enable
Gigg, Martyn Anthony
committed
{
enabled = true;
} else // Nothing was specified
Gigg, Martyn Anthony
committed
{
enabled = false;
}
return enabled;
Gigg, Martyn Anthony
committed
}
//------------------------------------------------------------------------------------------------
/** Set if we are for a script or not
* @param forScript :: A boolean indicating whether we are being called from a
* script */
void AlgorithmDialog::isForScript(bool forScript) { m_forScript = forScript; }
Gigg, Martyn Anthony
committed
//------------------------------------------------------------------------------------------------
/**
* @param on If true the algorithm is executed when "ok" is pressed
*/
void AlgorithmDialog::executeOnAccept(bool on) {
if (on) {
connect(this, SIGNAL(accepted()), this, SLOT(executeAlgorithmAsync()));
connect(this, SIGNAL(rejected()), this, SLOT(removeAlgorithmFromManager()));
disconnect(this, SIGNAL(accepted()), this, SLOT(executeAlgorithmAsync()));
disconnect(this, SIGNAL(rejected()), this,
SLOT(removeAlgorithmFromManager()));
}
//-------------------------------------------------------------------------------------------------
/** Set an optional message to be displayed at the top of the widget
* @param message :: The message string */
void AlgorithmDialog::setOptionalMessage(const QString &message) {
Gigg, Martyn Anthony
committed
m_strMessage = message;
if (message.isEmpty())
m_strMessage = QString::fromStdString(getAlgorithm()->summary());
if (m_strMessage.isEmpty())
m_msgAvailable = false;
else
m_msgAvailable = true;
Gigg, Martyn Anthony
committed
}
//-------------------------------------------------------------------------------------------------
/** Get a value from a widget.
*
* The function needs to know about the types of widgets
* that are being used. Currently it knows about QComboBox, QLineEdit, QCheckBox
* and MWRunFiles
Janik Zikovsky
committed
* @param widget :: A pointer to the widget
Gigg, Martyn Anthony
committed
*/
QString AlgorithmDialog::getValue(QWidget *widget) {
if (QComboBox *opts = qobject_cast<QComboBox *>(widget)) {
return opts->currentText().trimmed();
} else if (QLineEdit *textfield = qobject_cast<QLineEdit *>(widget)) {
return textfield->text().trimmed();
} else if (QAbstractButton *checker =
qobject_cast<QAbstractButton *>(widget)) {
if (checker->isChecked())
Gigg, Martyn Anthony
committed
return QString("1");
else
return QString("0");
} else if (QDateTimeEdit *dateEdit = qobject_cast<QDateTimeEdit *>(widget)) {
// String in ISO8601 format /* add toUTC() to go from local time */
QString value = dateEdit->dateTime().toString(Qt::ISODate);
return value;
} else if (MantidWidget *mtd_widget = qobject_cast<MantidWidget *>(widget)) {
return mtd_widget->getUserInput().toString().trimmed();
} else if (PropertyWidget *propWidget =
qobject_cast<PropertyWidget *>(widget)) {
return propWidget->getValue().trimmed();
} else {
QMessageBox::warning(
this, windowTitle(),
QString("Cannot parse input from ") +
widget->metaObject()->className() +
". Update AlgorithmDialog::getValue() to cope with this widget.");
Gigg, Martyn Anthony
committed
return "";
}
}
QString AlgorithmDialog::getPreviousValue(const QString &propName) const {
QString value;
if (!isForScript()) {
value = m_propertyValueMap.value(propName);
if (value.isEmpty())
value =
AlgorithmInputHistory::Instance().previousInput(m_algName, propName);
} else if (getAlgorithmProperty(propName)) {
value = m_propertyValueMap.value(propName);
}
return value;
}
//------------------------------------------------------------------------------------------------
/** Set a value for a widget.
*
* The function needs to know about the types of widgets
* that are being used. Currently it knows about QComboBox, QLineEdit and
* QCheckBox
Janik Zikovsky
committed
* @param widget :: A pointer to the widget
* @param propName :: The property name
Gigg, Martyn Anthony
committed
*/
void AlgorithmDialog::setPreviousValue(QWidget *widget,
const QString &propName) {
// If is called from a script, check if we have such property
if (isForScript() && !getAlgorithmProperty(propName))
Mantid::Kernel::Property *property = getAlgorithmProperty(propName);
Gigg, Martyn Anthony
committed
// Do the right thing for the widget type
if (QComboBox *opts = qobject_cast<QComboBox *>(widget)) {
if (property && value.isEmpty()) {
Gigg, Martyn Anthony
committed
value = QString::fromStdString(property->value());
}
Gigg, Martyn Anthony
committed
int index = opts->findText(value);
if (index >= 0) {
Gigg, Martyn Anthony
committed
opts->setCurrentIndex(index);
}
Gigg, Martyn Anthony
committed
return;
Gigg, Martyn Anthony
committed
}
if (QAbstractButton *checker = qobject_cast<QAbstractButton *>(widget)) {
if (value.isEmpty() &&
dynamic_cast<Mantid::Kernel::PropertyWithValue<bool> *>(property))
value = QString::fromStdString(property->value());
checker->setChecked(value != "0");
return;
}
if (QDateTimeEdit *dateEdit = qobject_cast<QDateTimeEdit *>(widget)) {
// String in ISO8601 format