Newer
Older
Gigg, Martyn Anthony
committed
//----------------------------------
// Includes
//----------------------------------
#include "MantidAPI/AlgorithmManager.h"
#include "MantidAPI/IWorkspaceProperty.h"
#include "MantidKernel/DateAndTime.h"
#include "MantidKernel/Logger.h"
Gigg, Martyn Anthony
committed
#include "MantidQtAPI/AlgorithmDialog.h"
#include "MantidQtAPI/AlgorithmInputHistory.h"
Gigg, Martyn Anthony
committed
#include "MantidQtAPI/MantidWidget.h"
#include "MantidQtAPI/HelpWindow.h"
#include "MantidQtAPI/FilePropertyWidget.h"
Gigg, Martyn Anthony
committed
#include <QIcon>
#include <QLabel>
#include <QMessageBox>
Gigg, Martyn Anthony
committed
#include <QLineEdit>
Gigg, Martyn Anthony
committed
#include <QComboBox>
#include <QCheckBox>
#include <QPushButton>
#include <QHBoxLayout>
#include <QCheckBox>
#include <Poco/ActiveResult.h>
Gigg, Martyn Anthony
committed
using namespace MantidQt::API;
using Mantid::Kernel::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(NULL), m_okButton(NULL), m_exitButton(NULL), m_observers(), m_btnTimer()
Gigg, Martyn Anthony
committed
{
Gigg, Martyn Anthony
committed
}
/**
* Destructor
*/
AlgorithmDialog::~AlgorithmDialog()
{
if(isShowKeepOpen() && m_okButton) {
if(!m_okButton->isEnabled()) {
// Keep open was checked but closing while algorithm is running
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
{
bool retval = true;
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;
//Set a common title
setWindowTitle(QString::fromStdString(getAlgorithm()->name()) + " input dialog");
//Set the icon
setWindowIcon(QIcon(":/MantidPlot_Icon_32offset.png"));
Gigg, Martyn Anthony
committed
// These containers are for ensuring the 'replace input workspace; button works correctly
// 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();
Gigg, Martyn Anthony
committed
// Keep track of the input workspace that has been used to fill the output workspace. Each button click
// cycles through all of the input workspaces
Gigg, Martyn Anthony
committed
m_wsbtn_tracker.clear();
Gigg, Martyn Anthony
committed
Gigg, Martyn Anthony
committed
// This derived class function creates the layout of the widget. It can also add default input if the
// 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()
{
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() )
{
QString pName = *pitr;
QString value = m_propertyValueMap.value(pName);
AlgorithmInputHistory::Instance().storeNewValue(m_algName, QPair<QString, QString>(pName, value));
}
}
}
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 )
{
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
*/
Gigg, Martyn Anthony
committed
Mantid::Kernel::Property* AlgorithmDialog::getAlgorithmProperty(const QString & propName) const
Gigg, Martyn Anthony
committed
{
if( m_algProperties.contains(propName) )
Gigg, Martyn Anthony
committed
{
return m_algorithm->getProperty(propName.toStdString());
}
Gigg, Martyn Anthony
committed
else return NULL;
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
{
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
{
QString value = m_propertyValueMap.value(propName);
Gigg, Martyn Anthony
committed
{
Mantid::Kernel::Property* prop = getAlgorithmProperty(propName);
if( prop ) return QString::fromStdString(prop->getDefault());
else return "";
}
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)
Gigg, Martyn Anthony
committed
{
Gigg, Martyn Anthony
committed
if( m_noValidation.contains(propname) ) return NULL;
QLabel *validLbl(NULL);
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;
}
else
{
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;
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()
Gigg, Martyn Anthony
committed
{
// 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);
}
} // widget is tied
} // 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.
* @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());
Janik Zikovsky
committed
}
catch(std::exception & err_details)
{
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.
*
Janik Zikovsky
committed
* @param skipList :: An optional list of property names whose values will not be set
* @returns A boolean that indicates if the validation was successful.
*/
bool AlgorithmDialog::setPropertyValues(const QStringList & skipList)
{
QStringList::const_iterator pend = m_algProperties.end();
bool allValid(true);
for( QStringList::const_iterator pitr = m_algProperties.begin(); pitr != pend; ++pitr )
{
const QString pName = *pitr;
if( skipList.contains(pName) )
Gigg, Martyn Anthony
committed
{
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();
Janik Zikovsky
committed
if (!error.empty()) allValid = false;
Gigg, Martyn Anthony
committed
}
Janik Zikovsky
committed
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;
}
else
m_errors[pName] = value;
// There is at least one whole-algo error
allValid = false;
}
Janik Zikovsky
committed
// 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
*/
Gigg, Martyn Anthony
committed
const QString & AlgorithmDialog::getOptionalMessage() const
Gigg, Martyn Anthony
committed
{
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
*/
Gigg, Martyn Anthony
committed
bool AlgorithmDialog::isForScript() const
Gigg, Martyn Anthony
committed
{
Gigg, Martyn Anthony
committed
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
*/
Gigg, Martyn Anthony
committed
bool AlgorithmDialog::isMessageAvailable() const
Gigg, Martyn Anthony
committed
{
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
*/
Gigg, Martyn Anthony
committed
bool AlgorithmDialog::isWidgetEnabled(const QString & propName) const
Gigg, Martyn Anthony
committed
{
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);
Janik Zikovsky
committed
if (!property) return true;
if( !isForScript() )
Gigg, Martyn Anthony
committed
{
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
}
else
{
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
*/
if( m_disabled.contains(propName) || m_python_arguments.contains(propName) )
Janik Zikovsky
committed
{
return false;
}
else
{
return true;
}
Gigg, Martyn Anthony
committed
}
Janik Zikovsky
committed
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)
Lynch, Vickie
committed
{
if( m_tied_properties.contains(property) )
{
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
Gigg, Martyn Anthony
committed
* @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
* 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,
Gigg, Martyn Anthony
committed
{
Gigg, Martyn Anthony
committed
if( m_tied_properties.contains(property) )
m_tied_properties.remove(property);
Janik Zikovsky
committed
Gigg, Martyn Anthony
committed
Mantid::Kernel::Property * prop = getAlgorithmProperty(property);
{ //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(NULL);
if( parent_layout )
Gigg, Martyn Anthony
committed
{
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);
Gigg, Martyn Anthony
committed
if( QBoxLayout *box = qobject_cast<QBoxLayout*>(parent_layout) )
{
Gigg, Martyn Anthony
committed
box->insertWidget(item_index + 1, validlbl);
Gigg, Martyn Anthony
committed
}
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);
Gigg, Martyn Anthony
committed
}
Gigg, Martyn Anthony
committed
}
Gigg, Martyn Anthony
committed
}
Gigg, Martyn Anthony
committed
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
{
Gigg, Martyn Anthony
committed
setPreviousValue(widget, property);
Gigg, Martyn Anthony
committed
}
Gigg, Martyn Anthony
committed
return validlbl;
Gigg, Martyn Anthony
committed
}
Janik Zikovsky
committed
Janik Zikovsky
committed
Janik Zikovsky
committed
//-------------------------------------------------------------------------------------------------
Gigg, Martyn Anthony
committed
/**
Gigg, Martyn Anthony
committed
* Open a file selection box. The type of dialog, i.e. load/save will depend on the
* property type
* @param propName :: The property name that this is associated with.
Gigg, Martyn Anthony
committed
*/
Gigg, Martyn Anthony
committed
QString AlgorithmDialog::openFileDialog(const QString & propName)
Gigg, Martyn Anthony
committed
{
if( propName.isEmpty() ) return "";
return FilePropertyWidget::openFileDialog( this->getAlgorithmProperty(propName) );
Gigg, Martyn Anthony
committed
}
Janik Zikovsky
committed
Janik Zikovsky
committed
//-------------------------------------------------------------------------------------------------
Gigg, Martyn Anthony
committed
/**
* Takes a combobox and adds the allowed values of the given property to its list.
Gigg, Martyn Anthony
committed
* It also sets the displayed value to the correct one based on either the history
* 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;
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;
Gigg, Martyn Anthony
committed
++vitr)
{
optionsBox->addItem(QString::fromStdString(*vitr));
}
// Display the appropriate value
QString displayed("");
if( !isForScript() )
{
displayed = AlgorithmInputHistory::Instance().previousInput(m_algName, propName);
}
if( displayed.isEmpty() )
{
displayed = QString::fromStdString(property->value());
}
int index = optionsBox->findText(displayed);
if( index >= 0 )
{
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
*/
Gigg, Martyn Anthony
committed
void AlgorithmDialog::fillLineEdit(const QString & propName, QLineEdit* textField)
Gigg, Martyn Anthony
committed
{
Gigg, Martyn Anthony
committed
if( !isForScript() )
Gigg, Martyn Anthony
committed
{
Gigg, Martyn Anthony
committed
textField->setText(AlgorithmInputHistory::Instance().previousInput(m_algName, propName));
Gigg, Martyn Anthony
committed
}
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 */
Gigg, Martyn Anthony
committed
AlgorithmDialog::createDefaultButtonLayout(const QString & helpText,
const QString & cancelText,
const QString & keepOpenText)
Gigg, Martyn Anthony
committed
{
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(close()));
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
* for that algorithm
*/
QPushButton* AlgorithmDialog::createHelpButton(const QString & helpText) const
{
QPushButton *help = new QPushButton(helpText);
help->setMaximumWidth(25);
connect(help, SIGNAL(clicked()), this, SLOT(helpClicked()));
return help;
}
Gigg, Martyn Anthony
committed
Janik Zikovsky
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
*/
Gigg, Martyn Anthony
committed
void AlgorithmDialog::flagInputWS(QWidget *inputWidget)
Gigg, Martyn Anthony
committed
{
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
*/
Gigg, Martyn Anthony
committed
void AlgorithmDialog::accept()
Gigg, Martyn Anthony
committed
{
Gigg, Martyn Anthony
committed
// Get property values
parse();
//Try and set and validate the properties and
Gigg, Martyn Anthony
committed
if( setPropertyValues() )
{
Gigg, Martyn Anthony
committed
//Store input for next time
Gigg, Martyn Anthony
committed
saveInput();
if (!this->m_keepOpen) {
QDialog::accept();
}
else {
executeAlgorithmAsync();
}
Gigg, Martyn Anthony
committed
}
Gigg, Martyn Anthony
committed
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 == QCheckBox::On);
}
//-------------------------------------------------------------------------------------------------
/**
* Execute the underlying algorithm
*/
void AlgorithmDialog::executeAlgorithmAsync()
{
Mantid::API::IAlgorithm_sptr algToExec = m_algorithm;
// 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(isShowKeepOpen()) {
this->observeFinish(algToExec);
this->observeError(algToExec);
// 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 {
this->stopObserving(algToExec);
}
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." << std::endl;
//-------------------------------------------------------------------------------------------------
/*
*/
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() )
{
itr.next();
//Need to do different things depending on the type of the widget. getValue sorts this out
storePropertyValue(itr.key(), getValue(itr.value()));
}
//Now call parseInput, which can be overridden in an inheriting class
parseInput();
}
Janik Zikovsky
committed
//-------------------------------------------------------------------------------------------------
Gigg, Martyn Anthony
committed
/**
* Set a list of values for the properties
Janik Zikovsky
committed
* @param presetValues :: A string containing a list of "name=value" pairs with each separated by an '|' character
Gigg, Martyn Anthony
committed
*/
Gigg, Martyn Anthony
committed
void AlgorithmDialog::setPresetValues(const QHash<QString,QString> & presetValues)
Gigg, Martyn Anthony
committed
{
Gigg, Martyn Anthony
committed
if( presetValues.isEmpty() ) return;
Gigg, Martyn Anthony
committed
QHashIterator<QString,QString> itr(presetValues);
Gigg, Martyn Anthony
committed
m_python_arguments.clear();
Gigg, Martyn Anthony
committed
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
*/
Gigg, Martyn Anthony
committed
void AlgorithmDialog::addEnabledAndDisableLists(const QStringList & enabled, const QStringList & disabled)
Gigg, Martyn Anthony
committed
{
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
*/
bool AlgorithmDialog::requestedToKeepEnabled(const QString& propName) const
Gigg, Martyn Anthony
committed
{
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
{
enabled = true;
}
else //Nothing was specified
{
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 */
Gigg, Martyn Anthony
committed
void AlgorithmDialog::isForScript(bool forScript)
{
m_forScript = forScript;
}
//------------------------------------------------------------------------------------------------
/**
* @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()));
}
else
{
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 */
Gigg, Martyn Anthony
committed
void AlgorithmDialog::setOptionalMessage(const QString & message)
{
m_strMessage = message;
if( message.isEmpty() ) m_strMessage = QString::fromStdString(getAlgorithm()->summary());
Gigg, Martyn Anthony
committed
if( m_strMessage.isEmpty() ) m_msgAvailable = false;
else m_msgAvailable = true;
Gigg, Martyn Anthony
committed
}
//-------------------------------------------------------------------------------------------------