Newer
Older
Gigg, Martyn Anthony
committed
//----------------------------------
// Includes
//----------------------------------
#include "MantidAPI/FileProperty.h"
#include "MantidAPI/FrameworkManager.h"
#include "MantidAPI/IAlgorithm.h"
#include "MantidAPI/IWorkspaceProperty.h"
#include "MantidAPI/MultipleFileProperty.h"
Gigg, Martyn Anthony
committed
#include "MantidQtAPI/AlgorithmDialog.h"
#include "MantidQtAPI/AlgorithmInputHistory.h"
Gigg, Martyn Anthony
committed
#include "MantidQtAPI/MantidWidget.h"
Gigg, Martyn Anthony
committed
#include <QIcon>
#include <QLabel>
#include <QMessageBox>
Gigg, Martyn Anthony
committed
#include <QFileDialog>
#include <QFileInfo>
#include <QLineEdit>
Gigg, Martyn Anthony
committed
#include <QComboBox>
#include <QCheckBox>
#include <QPushButton>
#include <QDesktopServices>
#include <QUrl>
#include <QHBoxLayout>
Gigg, Martyn Anthony
committed
#include <QSignalMapper>
#include "MantidQtAPI/FilePropertyWidget.h"
Gigg, Martyn Anthony
committed
using namespace MantidQt::API;
Gigg, Martyn Anthony
committed
//------------------------------------------------------
// Public member functions
//------------------------------------------------------
/**
* Default Constructor
*/
AlgorithmDialog::AlgorithmDialog(QWidget* parent) :
Gigg, Martyn Anthony
committed
QDialog(parent), m_algorithm(NULL), m_algName(""), m_algProperties(),
m_propertyValueMap(), m_tied_properties(), m_forScript(false), m_python_arguments(),
m_enabled(), m_disabled(), m_strMessage(""), m_msgAvailable(false), m_isInitialized(false), m_showHidden(true),
Gigg, Martyn Anthony
committed
m_validators(), m_noValidation(), m_inputws_opts(), m_outputws_fields(), m_wsbtn_tracker(),
Gigg, Martyn Anthony
committed
m_signal_mapper(new QSignalMapper())
Gigg, Martyn Anthony
committed
{
Gigg, Martyn Anthony
committed
connect(m_signal_mapper, SIGNAL(mapped(QWidget*)), this, SLOT(replaceWSClicked(QWidget*)));
Gigg, Martyn Anthony
committed
}
/**
* Destructor
*/
AlgorithmDialog::~AlgorithmDialog()
{
}
void AlgorithmDialog::showHiddenWorkspaces(const bool & show)
{
m_showHidden = show;
}
Gigg, Martyn Anthony
committed
/**
* Create the layout for this dialog.
*/
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
// Check if there is any default input
Gigg, Martyn Anthony
committed
this->parse();
Gigg, Martyn Anthony
committed
Gigg, Martyn Anthony
committed
// Try to set these values. This will validate the defaults and mark those that are invalid, if any.
Steve Williams
committed
setPropertyValues();
Gigg, Martyn Anthony
committed
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
{
Gigg, Martyn Anthony
committed
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
* 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* alg)
{
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()));
}
}
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* 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
{
Gigg, Martyn Anthony
committed
if( m_algProperties.contains(propName) )
{
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);
if( value.isEmpty() )
{
Mantid::Kernel::Property* prop = getAlgorithmProperty(propName);
if( prop ) return QString::fromStdString(prop->getDefault());
else return "";
}
else return value;
return value;
}
Janik Zikovsky
committed
//-------------------------------------------------------------------------------------------------
Gigg, Martyn Anthony
committed
/**
Janik Zikovsky
committed
* Get a property validator label (that little red star)
Gigg, Martyn Anthony
committed
*/
Gigg, Martyn Anthony
committed
QLabel* AlgorithmDialog::getValidatorMarker(const QString & propname) const
Gigg, Martyn Anthony
committed
{
Gigg, Martyn Anthony
committed
if( m_noValidation.contains(propname) ) return NULL;
QLabel *validLbl(NULL);
if( !m_validators.contains(propname) )
{
Gigg, Martyn Anthony
committed
validLbl = new QLabel("*");
Gigg, Martyn Anthony
committed
QPalette pal = validLbl->palette();
pal.setColor(QPalette::WindowText, Qt::darkRed);
validLbl->setPalette(pal);
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);
}
Janik Zikovsky
committed
//-------------------------------------------------------------------------------------------------
/** Go through all the properties, and check their validators to determine
* whether they should be made disabled/invisible.
* It also shows/hids the validators.
* All properties' values should be set already, otherwise the validators
* will be running on old data.
Gigg, Martyn Anthony
committed
*/
Janik Zikovsky
committed
void AlgorithmDialog::hideOrDisableProperties()
Gigg, Martyn Anthony
committed
{
QStringList::const_iterator pend = m_algProperties.end();
for( QStringList::const_iterator pitr = m_algProperties.begin(); pitr != pend; ++pitr )
{
const QString pName = *pitr;
Gigg, Martyn Anthony
committed
Mantid::Kernel::Property *p = getAlgorithmProperty(pName);
Janik Zikovsky
committed
// Find the widget for this property.
if (m_tied_properties.contains(pName))
Gigg, Martyn Anthony
committed
{
Janik Zikovsky
committed
// Set the enabled and visible flags based on what the validators say. Default is always true.
bool enabled = isWidgetEnabled(pName);
bool visible = p->isVisible();
if (p->isConditionChanged())
{
p->getSettings()->applyChanges(p);
// TODO: Handle replacing widgets
// int row = this->deletePropertyWidgets(p);
// this->createSpecificPropertyWidget(p,row);
Janik Zikovsky
committed
// Show/hide the validator label (that red star)
QString error = "";
if (m_errors.contains(pName)) error = m_errors[pName];
// Always show controls that are in error
if (error.length() != 0)
visible = true;
Janik Zikovsky
committed
// Go through all the associated widgets with this property
QList<QWidget*> widgets = m_tied_all_widgets[pName];
for (int i=0; i<widgets.size(); i++)
Gigg, Martyn Anthony
committed
{
Janik Zikovsky
committed
QWidget * widget = widgets[i];
widget->setEnabled( enabled );
widget->setVisible( visible );
Gigg, Martyn Anthony
committed
}
Janik Zikovsky
committed
if (visible)
Gigg, Martyn Anthony
committed
{
Janik Zikovsky
committed
QLabel *validator = getValidatorMarker(pName);
// 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);
}
Gigg, Martyn Anthony
committed
}
Gigg, Martyn Anthony
committed
}
Janik Zikovsky
committed
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
} // for each property
}
//-------------------------------------------------------------------------------------------------
/** 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);
QString value = getInputValue(pName);
std::string error("");
try
{
error = p->setValue(value.toStdString());
}
catch(std::exception & err_details)
{
error = err_details.what();
}
// Save the error string for later
m_errors[pName] = QString::fromStdString(error);
// Go through all the other properties' validators
if (validateOthers)
this->hideOrDisableProperties();
// 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
* @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);
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
// OK all the values have been set once. Time to look for which should be enabled
this->hideOrDisableProperties();
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);
}
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
return property->isEnabled();
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)
{
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
* @param otherWidget1 :: An associated widget that should be hidden if the main one is hidden too.
* @param otherWidget2 :: An associated widget that should be hidden if the main one is hidden too.
* @param otherWidget3 :: An associated widget that should be hidden if the main one is hidden too.
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
*/
Gigg, Martyn Anthony
committed
QWidget* AlgorithmDialog::tie(QWidget* widget, const QString & property, QLayout *parent_layout,
bool readHistory, QWidget * otherWidget1, QWidget * otherWidget2, QWidget * otherWidget3)
Gigg, Martyn Anthony
committed
{
Gigg, Martyn Anthony
committed
if( m_tied_properties.contains(property) )
m_tied_properties.remove(property);
Janik Zikovsky
committed
if (m_tied_all_widgets.contains(property) )
m_tied_all_widgets.remove(property);
Gigg, Martyn Anthony
committed
Mantid::Kernel::Property * prop = getAlgorithmProperty(property);
if( prop )
{ //Set a few things on the widget
Gigg, Martyn Anthony
committed
widget->setToolTip(QString::fromStdString(prop->documentation()));
Gigg, Martyn Anthony
committed
widget->setEnabled(isWidgetEnabled(property));
Janik Zikovsky
committed
// Save in the hashes
Gigg, Martyn Anthony
committed
m_tied_properties.insert(property, widget);
Janik Zikovsky
committed
QList<QWidget*> allWidgets;
allWidgets.push_back(widget);
if (otherWidget1) allWidgets.push_back(otherWidget1);
if (otherWidget2) allWidgets.push_back(otherWidget2);
if (otherWidget3) allWidgets.push_back(otherWidget3);
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 )
{
int item_index = parent_layout->indexOf(widget);
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) )
{
Janik Zikovsky
committed
// Find the last column that has room for a "INVALID" star
Gigg, Martyn Anthony
committed
int row(0), col(0), span(0);
grid->getItemPosition(item_index, &row, &col, &span, &span);
Janik Zikovsky
committed
int max_col = col;
for (int i=0; i<allWidgets.size(); i++)
{
grid->getItemPosition( parent_layout->indexOf(allWidgets[i]), &row, &col, &span, &span);
if (col > max_col) max_col = col;
}
grid->addWidget(validlbl, row, max_col + 1);
Gigg, Martyn Anthony
committed
}
else {}
}
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
}
Janik Zikovsky
committed
// Save all the associated widgets
if (validlbl) allWidgets.push_back(validlbl);
m_tied_all_widgets.insert(property, allWidgets);
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
/**
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
* 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::set<std::string> items = property->allowedValues();
std::set<std::string>::const_iterator vend = items.end();
for(std::set<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);
Gigg, Martyn Anthony
committed
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
QHBoxLayout *
AlgorithmDialog::createDefaultButtonLayout(const QString & helpText,
const QString & loadText,
const QString & cancelText)
Gigg, Martyn Anthony
committed
{
QPushButton *okButton = new QPushButton(loadText);
connect(okButton, SIGNAL(clicked()), this, SLOT(accept()));
okButton->setDefault(true);
QPushButton *exitButton = new QPushButton(cancelText);
connect(exitButton, SIGNAL(clicked()), this, SLOT(close()));
QHBoxLayout *buttonRowLayout = new QHBoxLayout;
buttonRowLayout->addWidget(createHelpButton(helpText));
buttonRowLayout->addStretch();
buttonRowLayout->addWidget(okButton);
buttonRowLayout->addWidget(exitButton);
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
/**
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();
Gigg, Martyn Anthony
committed
Gigg, Martyn Anthony
committed
//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();
QDialog::accept();
}
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()
{
// Default help URL
QString url = QString("http://www.mantidproject.org/") + m_algName;
if (m_algorithm)
{
// Find the latest version
IAlgorithm* alg = Mantid::API::FrameworkManager::Instance().createAlgorithm(m_algName.toStdString(), -1);
int latest_version = alg->version();
// Adjust the link if you're NOT looking at the latest version of the algo
int this_version = m_algorithm->version();
if ((this_version != latest_version))
url += "_v." + QString::number(this_version);
}
// Open the URL
QDesktopServices::openUrl(QUrl(url));
Gigg, Martyn Anthony
committed
}
Gigg, Martyn Anthony
committed
Janik Zikovsky
committed
//-------------------------------------------------------------------------------------------------
Gigg, Martyn Anthony
committed
/**
* A slot to handle the replace workspace button click
Janik Zikovsky
committed
* @param outputEdit :: The line edit that is associated, via the signalmapper, with this click
Gigg, Martyn Anthony
committed
*/
void AlgorithmDialog::replaceWSClicked(QWidget *outputEdit)
{
QPushButton *btn = qobject_cast<QPushButton*>(m_signal_mapper->mapping(outputEdit));
if( !btn ) return;
int input = m_wsbtn_tracker.value(btn);
Gigg, Martyn Anthony
committed
QWidget *wsInputWidget = m_inputws_opts.value(input-1);
QString wsname("");
if( QComboBox *options = qobject_cast<QComboBox*>(wsInputWidget) )
{
wsname = options->currentText();
}
else if( QLineEdit *editField = qobject_cast<QLineEdit*>(wsInputWidget) )
{
wsname = editField->text();
}
else return;
Gigg, Martyn Anthony
committed
//Adjust tracker
input = (input % m_inputws_opts.size() ) + 1;
m_wsbtn_tracker[btn] = input;
// Check if any of the other line edits have this name
QVector<QLineEdit*>::const_iterator iend = m_outputws_fields.constEnd();
for( QVector<QLineEdit*>::const_iterator itr = m_outputws_fields.constBegin();
itr != iend; ++itr )
{
//Check that we are not the field we are actually comparing against
if( (*itr) == outputEdit ) continue;
if( (*itr)->text() == wsname )
{
wsname += "-1";
break;
}
}
QLineEdit *edit = qobject_cast<QLineEdit*>(outputEdit);
if( edit )
{
edit->setText(wsname);
}
}
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
/**
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) )
{
enabled = false;
}
else if( m_enabled.contains(propName) ) // Definitely enable
{
enabled = true;
}
else //Nothing was specified
{
enabled = false;
}
return enabled;
Gigg, Martyn Anthony
committed
}
Gigg, Martyn Anthony
committed
/**
* Set if we are for a script or not
Janik Zikovsky
committed
* @param forScript :: A boolean inidcating whether we are being called from a script
Gigg, Martyn Anthony
committed
*/
void AlgorithmDialog::isForScript(bool forScript)
{
m_forScript = forScript;
}
//-------------------------------------------------------------------------------------------------
Gigg, Martyn Anthony
committed
/**
* Set an optional message to be displayed at the top of the widget
Janik Zikovsky
committed
* @param message :: The message string
Gigg, Martyn Anthony
committed
*/
void AlgorithmDialog::setOptionalMessage(const QString & message)
{
m_strMessage = message;
Gigg, Martyn Anthony
committed
if( message.isEmpty() ) m_strMessage = QString::fromStdString(getAlgorithm()->getOptionalMessage());
if( m_strMessage.isEmpty() ) m_msgAvailable = false;
else m_msgAvailable = true;
Gigg, Martyn Anthony
committed
}
//-------------------------------------------------------------------------------------------------
Gigg, Martyn Anthony
committed
/**
* Get a value from a widget. The function needs to know about the types of widgets
Gigg, Martyn Anthony
committed
* 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();
Gigg, Martyn Anthony
committed
}
else if( QLineEdit *textfield = qobject_cast<QLineEdit*>(widget) )
{
return textfield->text().trimmed();
Gigg, Martyn Anthony
committed
}
else if( QCheckBox *checker = qobject_cast<QCheckBox*>(widget) )
{
if( checker->checkState() == Qt::Checked )
{
return QString("1");
}
else
{
return QString("0");
}
}
Gigg, Martyn Anthony
committed
else if( MantidWidget *mtd_widget = qobject_cast<MantidWidget*>(widget) )
{
return mtd_widget->getUserInput().toString().trimmed();
Gigg, Martyn Anthony
committed
}
Gigg, Martyn Anthony
committed
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 "";
}
}
/**
* 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
*/
Gigg, Martyn Anthony
committed
void AlgorithmDialog::setPreviousValue(QWidget *widget, const QString & propName)
Gigg, Martyn Anthony
committed
{
// Get the value from either the previous input store or from Python argument
QString value("");
Mantid::Kernel::Property *property = getAlgorithmProperty(propName);
if( !isForScript() )
{
Gigg, Martyn Anthony
committed
value = m_propertyValueMap.value(propName);
if( value.isEmpty() )
{
value = AlgorithmInputHistory::Instance().previousInput(m_algName, propName);
}
Gigg, Martyn Anthony
committed
}
else
{
if( !property ) return;
Gigg, Martyn Anthony
committed
value = m_propertyValueMap.value(propName);
Gigg, Martyn Anthony
committed
}
// Do the right thing for the widget type
if( QComboBox *opts = qobject_cast<QComboBox*>(widget) )
{
Gigg, Martyn Anthony
committed
if( property && value.isEmpty() )
{
value = QString::fromStdString(property->value());
}
Gigg, Martyn Anthony
committed
int index = opts->findText(value);
if( index >= 0 )
{
opts->setCurrentIndex(index);
}
Gigg, Martyn Anthony
committed
return;
Gigg, Martyn Anthony
committed
}
Gigg, Martyn Anthony
committed
if( QCheckBox *checker = qobject_cast<QCheckBox*>(widget) )
Gigg, Martyn Anthony
committed
{
if( value.isEmpty() && dynamic_cast<Mantid::Kernel::PropertyWithValue<bool>* >(property) )
{
value = QString::fromStdString(property->value());
}
Gigg, Martyn Anthony
committed
if( value == "0" )
{
checker->setCheckState(Qt::Unchecked);
}
else
{
checker->setCheckState(Qt::Checked);
}