From 5765b43470d08f917569dba1c8da96deeab76daf Mon Sep 17 00:00:00 2001 From: Martyn Gigg <martyn.gigg@stfc.ac.uk> Date: Tue, 8 Feb 2011 11:38:20 +0000 Subject: [PATCH] Implemented a custom dialog for the Load algorithm. It now dynamically generates its properties from those that the concrete loaer has, Refs #2329. Also fixed a problem with loading grouped nexus files through the Load algorithm, Re #2362 --- .../Framework/API/src/AlgorithmProxy.cpp | 8 +- .../inc/MantidDataHandling/Load.h | 6 +- .../Framework/DataHandling/src/Load.cpp | 89 ++--- .../Framework/DataHandling/test/LoadTest.h | 21 + .../API/inc/MantidQtAPI/AlgorithmDialog.h | 62 ++- .../API/inc/MantidQtAPI/MantidWidget.h | 28 +- .../API/inc/MantidQtAPI/PythonRunner.h | 2 +- .../MantidQt/API/src/AlgorithmDialog.cpp | 358 ++++++++++-------- .../Mantid/MantidQt/API/src/GenericDialog.cpp | 5 - .../MantidQt/CustomDialogs/CMakeLists.txt | 8 +- .../MantidQt/CustomDialogs/CustomDialogs.pro | 10 +- .../inc/MantidQtCustomDialogs/LoadDialog.h | 113 ++++++ .../MantidQt/CustomDialogs/src/LoadDialog.cpp | 284 ++++++++++++++ .../inc/MantidQtMantidWidgets/MWDiag.h | 1 + .../inc/MantidQtMantidWidgets/MWRunFiles.h | 21 +- .../inc/MantidQtMantidWidgets/MWRunFiles.ui | 88 +++-- .../MantidQt/MantidWidgets/src/MWRunFiles.cpp | 54 ++- 17 files changed, 816 insertions(+), 342 deletions(-) create mode 100644 Code/Mantid/MantidQt/CustomDialogs/inc/MantidQtCustomDialogs/LoadDialog.h create mode 100644 Code/Mantid/MantidQt/CustomDialogs/src/LoadDialog.cpp diff --git a/Code/Mantid/Framework/API/src/AlgorithmProxy.cpp b/Code/Mantid/Framework/API/src/AlgorithmProxy.cpp index 3dd1aa5c35f..2ab783b8573 100644 --- a/Code/Mantid/Framework/API/src/AlgorithmProxy.cpp +++ b/Code/Mantid/Framework/API/src/AlgorithmProxy.cpp @@ -155,12 +155,8 @@ void AlgorithmProxy::setRethrows(const bool rethrow) void AlgorithmProxy::setPropertyValue(const std::string &name, const std::string &value) { createConcreteAlg(true); - const size_t numPropsAtStart = m_alg->propertyCount(); m_alg->setPropertyValue(name, value); - if( numPropsAtStart != m_alg->propertyCount() ) - { - copyPropertiesFrom(*m_alg); - } + copyPropertiesFrom(*m_alg); m_alg.reset(); } @@ -171,7 +167,7 @@ void AlgorithmProxy::setPropertyValue(const std::string &name, const std::string /** * Creates an unmanaged instance of the actual algorithm and sets its properties - * @param initOenly If true then the algorithm will only having its init step run, otherwise observers will + * @param initOnly If true then the algorithm will only having its init step run, otherwise observers will * also be added and rethrows will be true */ void AlgorithmProxy::createConcreteAlg(bool initOnly) diff --git a/Code/Mantid/Framework/DataHandling/inc/MantidDataHandling/Load.h b/Code/Mantid/Framework/DataHandling/inc/MantidDataHandling/Load.h index 048a7fdefd4..05b7b30d111 100644 --- a/Code/Mantid/Framework/DataHandling/inc/MantidDataHandling/Load.h +++ b/Code/Mantid/Framework/DataHandling/inc/MantidDataHandling/Load.h @@ -72,11 +72,11 @@ namespace Mantid API::IAlgorithm_sptr createLoader(const std::string & name, const double startProgress = -1.0, const double endProgress=-1.0, const bool logging = true) const; /// Set the output workspace(s) - void setOutputWorkspace(API::IAlgorithm_sptr&); + void setOutputWorkspace(const API::IAlgorithm_sptr loader); private: - /// A list of property names that have been dynamically set - std::list<std::string> m_loaderProps; + /// The base properties + std::set<std::string> m_baseProps; }; } // namespace DataHandling diff --git a/Code/Mantid/Framework/DataHandling/src/Load.cpp b/Code/Mantid/Framework/DataHandling/src/Load.cpp index dc48976c32f..f8d12fd54bc 100644 --- a/Code/Mantid/Framework/DataHandling/src/Load.cpp +++ b/Code/Mantid/Framework/DataHandling/src/Load.cpp @@ -23,7 +23,7 @@ namespace Mantid //-------------------------------------------------------------------------- /// Default constructor - Load::Load() : IDataFileChecker(), m_loaderProps() + Load::Load() : IDataFileChecker(), m_baseProps() { } @@ -35,11 +35,22 @@ namespace Mantid void Load::setPropertyValue(const std::string &name, const std::string &value) { IDataFileChecker::setPropertyValue(name, value); + + IAlgorithm_sptr loader; if( name == "Filename" ) { - IAlgorithm_sptr loader = getFileLoader(getPropertyValue(name)); - declareLoaderProperties(loader); + loader = getFileLoader(getPropertyValue(name)); + } + else + { + const std::string loaderName = getProperty("LoaderName"); + if( !loaderName.empty() ) + { + loader = API::AlgorithmManager::Instance().createUnmanaged(loaderName); + loader->initialize(); + } } + if( loader ) declareLoaderProperties(loader); } //-------------------------------------------------------------------------- @@ -124,6 +135,8 @@ namespace Mantid if( !winningLoader ) { + // Clear what may have been here previously + setPropertyValue("LoaderName", ""); throw std::runtime_error("Cannot find a loader for \"" + filePath + "\""); } setPropertyValue("LoaderName", winningLoader->name()); @@ -137,18 +150,17 @@ namespace Mantid */ void Load::declareLoaderProperties(const IAlgorithm_sptr loader) { - if( !m_loaderProps.empty() ) + const std::vector<Property*> existingProps = this->getProperties(); + for( size_t i = 0; i < existingProps.size(); ++i ) { - std::list<std::string>::const_iterator cend = m_loaderProps.end(); - for( std::list<std::string>::const_iterator citr = m_loaderProps.begin(); - citr != cend; ++citr ) + const std::string name = existingProps[i]->name(); + if( m_baseProps.find(name) != m_baseProps.end() ) { - this->removeProperty(*citr); + continue; } - m_loaderProps.clear(); + this->removeProperty(name); } - const std::vector<Property*> &loaderProps = loader->getProperties(); size_t numProps(loaderProps.size()); for (size_t i = 0; i < numProps; ++i) @@ -163,9 +175,6 @@ namespace Mantid // Already exists as a static property continue; } - // Save just in case a this function is called again so that we - // can remove the dynamically generated properties - m_loaderProps.push_back(loadProp->name()); } } @@ -192,7 +201,7 @@ namespace Mantid declareProperty(new FileProperty("Filename", "", FileProperty::Load, exts), "The name of the file to read, including its full or relative\n" "path. (N.B. case sensitive if running on Linux)."); - declareProperty(new WorkspaceProperty<Workspace>("OutputWorkspace", "",Direction::Output, true), + declareProperty(new WorkspaceProperty<Workspace>("OutputWorkspace", "",Direction::Output), "The name of the workspace that will be created, filled with the\n" "read-in data and stored in the Analysis Data Service."); BoundedValidator<int> *mustBePositive = new BoundedValidator<int>(); @@ -204,6 +213,13 @@ namespace Mantid "Load a particular entry, if supported by the file format (default: Load all entries)"); declareProperty("LoaderName", std::string(""), "A string containing the name of the concrete loader used", Direction::Output); + + const std::vector<Property*> & props = this->getProperties(); + for( size_t i = 0; i < this->propertyCount(); ++i ) + { + m_baseProps.insert(props[i]->name()); + } + } /** @@ -216,7 +232,6 @@ namespace Mantid { throw std::invalid_argument("Cannot find loader, LoaderName property has not been set."); } - IAlgorithm_sptr loader = createLoader(loaderName); g_log.information() << "Using " << loaderName << " version " << loader->version() << ".\n"; // Get the list of properties for the Load algorithm @@ -286,37 +301,25 @@ namespace Mantid * Set the output workspace(s) if the load's return workspace has type API::Workspace * @param load :: Shared pointer to load algorithm */ - void Load::setOutputWorkspace(API::IAlgorithm_sptr& load) + void Load::setOutputWorkspace(const API::IAlgorithm_sptr load) { - try + Workspace_sptr childWS = load->getProperty("OutputWorkspace"); + if( WorkspaceGroup_sptr wsGroup = boost::dynamic_pointer_cast<WorkspaceGroup>(childWS) ) { - Workspace_sptr ws = load->getProperty("OutputWorkspace"); - WorkspaceGroup_sptr wsg = boost::dynamic_pointer_cast<WorkspaceGroup>(ws); - if (wsg) - { - setProperty("OutputWorkspace",ws); - std::vector<std::string> names = wsg->getNames(); - for(size_t i = 0; i < names.size(); ++i) - { - std::ostringstream propName; - propName << "OutputWorkspace_" << (i+1); - DataObjects::Workspace2D_sptr memberwsws1 = load->getProperty(propName.str()); - - std::string memberwsName = load->getPropertyValue(propName.str()); - declareProperty(new WorkspaceProperty<>(propName.str(),memberwsName,Direction::Output)); - setProperty(propName.str(),boost::dynamic_pointer_cast<MatrixWorkspace>(memberwsws1)); - } - } - else - { - setProperty("OutputWorkspace",ws); - } - } - catch(std::runtime_error&) - { - MatrixWorkspace_sptr mws=load->getProperty("OutputWorkspace"); - setProperty("OutputWorkspace",boost::dynamic_pointer_cast<Workspace>(mws)); + std::vector<std::string> names = wsGroup->getNames(); + const size_t numMembers(names.size()); + const std::string baseName("OutputWorkspace_"); + for( size_t i = 0; i < numMembers; ++i ) + { + std::ostringstream propName; + propName << baseName << (i+1); + declareProperty(new WorkspaceProperty<Workspace>(propName.str(), load->getPropertyValue(propName.str()), + Direction::Output)); + Workspace_sptr memberWS = load->getProperty(propName.str()); + setProperty(propName.str(), memberWS); + } } + setProperty("OutputWorkspace", childWS); } } // namespace DataHandling diff --git a/Code/Mantid/Framework/DataHandling/test/LoadTest.h b/Code/Mantid/Framework/DataHandling/test/LoadTest.h index 0b3bb5c4935..0ae5598cf6f 100644 --- a/Code/Mantid/Framework/DataHandling/test/LoadTest.h +++ b/Code/Mantid/Framework/DataHandling/test/LoadTest.h @@ -8,6 +8,8 @@ #include "MantidAPI/WorkspaceGroup.h" #include "MantidAPI/AnalysisDataService.h" +#include "MantidAPI/AlgorithmManager.h" + using namespace Mantid::API; using namespace Mantid::DataObjects; using namespace Mantid::DataHandling; @@ -16,6 +18,25 @@ class LoadTest : public CxxTest::TestSuite { public: + void testViaProxy() + { + IAlgorithm_sptr proxy = AlgorithmManager::Instance().create("Load"); + TS_ASSERT_EQUALS(proxy->existsProperty("Filename"), true); + TS_ASSERT_EQUALS(proxy->existsProperty("OutputWorkspace"), true); + + TS_ASSERT_THROWS_NOTHING(proxy->setPropertyValue("Filename","IRS38633.raw")); + TS_ASSERT_EQUALS(proxy->existsProperty("Cache"), true); + TS_ASSERT_EQUALS(proxy->existsProperty("LoadLogFiles"), true); + + proxy->setPropertyValue("Filename","IRS38633.raw"); + TS_ASSERT_EQUALS(proxy->existsProperty("Cache"), true); + TS_ASSERT_EQUALS(proxy->existsProperty("LoadLogFiles"), true); + + TS_ASSERT_THROWS_NOTHING(proxy->setPropertyValue("Filename","LOQ49886.nxs")); + TS_ASSERT_EQUALS(proxy->existsProperty("Cache"), false); + TS_ASSERT_EQUALS(proxy->existsProperty("LoadLogFiles"), false); + } + void testFindLoader() { Load loader; diff --git a/Code/Mantid/MantidQt/API/inc/MantidQtAPI/AlgorithmDialog.h b/Code/Mantid/MantidQt/API/inc/MantidQtAPI/AlgorithmDialog.h index 382e8dc1da2..c2df93b4f7c 100644 --- a/Code/Mantid/MantidQt/API/inc/MantidQtAPI/AlgorithmDialog.h +++ b/Code/Mantid/MantidQt/API/inc/MantidQtAPI/AlgorithmDialog.h @@ -117,20 +117,37 @@ protected: /// Parse out the values entered into the dialog boxes. Use storePropertyValue() /// to store the <name, value> pair in the base class so that they can be retrieved later virtual void parseInput(); + + /// Save the input history of an accepted dialog + virtual void saveInput(); //@} /** @name Algorithm information */ + // InterfaceManager needs to be able to reset the algorithm as I can't pass it in use a + // constructor + friend class InterfaceManagerImpl; + + /// Set the algorithm associated with this dialog + void setAlgorithm(Mantid::API::IAlgorithm*); + /// Get the algorithm pointer Mantid::API::IAlgorithm* getAlgorithm() const; /// Get a pointer to the named property Mantid::Kernel::Property* getAlgorithmProperty(const QString & propName) const; + /// Return a true if the given property requires user input + bool requiresUserInput(const QString & propName) const; + /// Get an input value from the form, dealing with blank inputs etc + QString getInputValue(const QString& propName) const; /// Get a property validator label QLabel* getValidatorMarker(const QString & propname) const; /// Adds a property (name,value) pair to the stored map void storePropertyValue(const QString & name, const QString & value); + + /// Set the properties that have been parsed from the dialog + bool setPropertyValues(); //@} /** @name Dialog information */ @@ -151,7 +168,7 @@ protected: /** @name Helper functions */ //@{ ///Tie a widget to a property - QWidget* tie(QWidget* widget, const QString & property, QLayout* parent_layout); + QWidget* tie(QWidget* widget, const QString & property, QLayout* parent_layout, bool readHistory = true); /// Open a file dialog to select a file. QString openFileDialog(const QString & propName); @@ -186,52 +203,29 @@ protected: virtual void accept(); /// Help button clicked; - void helpClicked(); + virtual void helpClicked(); /// Replace WS void replaceWSClicked(QWidget *outputEdit); private: - // This is so that it can set the algorithm and initialize the layout. - // I can't pass the algorithm as an argument to the constructor as I am using - // the DynamicFactory - friend class InterfaceManagerImpl; - - /// Set the algorithm associated with this dialog - void setAlgorithm(Mantid::API::IAlgorithm*); /// Parse out the input from the dialog void parse(); - - /// Set the properties that have been parsed from the dialog - bool setPropertyValues(); - - /// Save the input history of an accepted dialog - void saveInput(); - /// Set a list of suggested values void setPresetValues(const QString & presetValues); - /// Set comma-separated-list of enabled parameter names void setEnabledNames(const QString & enabledNames); - /// Test if the given name's widget should be left enabled bool isInEnabledList(const QString& propName) const; - /// Set whether this is intended for use from a script or not void isForScript(bool forScript); - /// Set an optional message to be displayed at the top of the dialog void setOptionalMessage(const QString & message); - - /// This sets up the labels that are to be used to mark whether a property is valid. - void createValidatorLabels(); - /// Retrieve a text value for a property from a widget QString getValue(QWidget *widget); - /// Set a value based on any old input that we have - void setValue(QWidget *widget, const QString & property); + void setPreviousValue(QWidget *widget, const QString & property); private: /** @name Member variables. */ @@ -241,28 +235,20 @@ private: ///The name of the algorithm QString m_algName; - - /// The properties associated with this algorithm - QHash<QString, Mantid::Kernel::Property*> m_algProperties; - + /// The properties associated with this dialog + QStringList m_algProperties; /// A map of property <name, value> pairs that have been taken from the dialog QHash<QString, QString> m_propertyValueMap; - /// A list pointers to PropertyWidget objects QHash<QString, QWidget*> m_tied_properties; - /// A boolean indicating whether this is for a script or not bool m_forScript; - /// A list of property names that have been passed from Python QStringList m_python_arguments; - /// A list of property names that should have their widgets enabled QStringList m_enabledNames; - /// The message string to be displayed at the top of the widget; if it exists. QString m_strMessage; - /// Is the message string empty or not bool m_msgAvailable; @@ -270,7 +256,9 @@ private: bool m_isInitialized; /// A list of labels to use as validation markers - QHash<QString, QLabel*> m_validators; + mutable QHash<QString, QLabel*> m_validators; + /// A list of property names whose widgets handle their own validation + QStringList m_noValidation; /// Store a list of the names of input workspace boxes QVector<QWidget*> m_inputws_opts; diff --git a/Code/Mantid/MantidQt/API/inc/MantidQtAPI/MantidWidget.h b/Code/Mantid/MantidQt/API/inc/MantidQtAPI/MantidWidget.h index 34a73f0d121..d285a03ffc8 100644 --- a/Code/Mantid/MantidQt/API/inc/MantidQtAPI/MantidWidget.h +++ b/Code/Mantid/MantidQt/API/inc/MantidQtAPI/MantidWidget.h @@ -1,21 +1,21 @@ #ifndef MANTIDQTAPI_MANTIDWIDGET_H_ #define MANTIDQTAPI_MANTIDWIDGET_H_ +#include "DllOption.h" #include "MantidQtAPI/PythonRunner.h" #include <QWidget> -#include "DllOption.h" -#include <boost/shared_ptr.hpp> +#include <QVariant> -/** The ase class from which mantid custom widgets are derived it contains -* some useful functions -*/ namespace MantidQt { namespace API { /** - This is the base class all customised user interfaces that do not wish to be tied - to a specific Mantid algorithm but rather customised for user's requirements + This is the base class all customised widgets that do not wish to be tied + to a specific Mantid algorithm but rather customised for user's requirements. + + The virtual function getUserInput() must be implemented to return what the widget considers + as user input. @author Martyn Gigg, Tessella Support Services plc @date 18/03/2009 @@ -45,8 +45,15 @@ namespace MantidQt Q_OBJECT public: - /// empty virtual destructor - ~MantidWidget(){} + + /// Returns a QVariant containing what the widget classes as user input so that + /// input can be returned through a common interface. + virtual QVariant getUserInput() const { return QVariant(); } + /** + * Sets a value on a mantid widget through a common interface + * @param :: value The value as a QVariant + */ + virtual void setUserInput(const QVariant & value) { Q_UNUSED(value); } signals: void runAsPythonScript(const QString& code); @@ -54,7 +61,8 @@ namespace MantidQt protected: /// Default constructor MantidWidget(QWidget *parent = NULL); - /// Run python code that is passed to it and, optionally, return anything it wrote to standard output as a string + /// Run python code that is passed to it and, optionally, return + /// anything it wrote to standard output as a string QString runPythonCode(const QString & code, bool no_output = false); private: diff --git a/Code/Mantid/MantidQt/API/inc/MantidQtAPI/PythonRunner.h b/Code/Mantid/MantidQt/API/inc/MantidQtAPI/PythonRunner.h index 0a83e206edd..8dddeae1c6c 100644 --- a/Code/Mantid/MantidQt/API/inc/MantidQtAPI/PythonRunner.h +++ b/Code/Mantid/MantidQt/API/inc/MantidQtAPI/PythonRunner.h @@ -1,8 +1,8 @@ #ifndef MANTIDQTAPI_PYTHONRUNNER_H_ #define MANTIDQTAPI_PYTHONRUNNER_H_ -#include <QObject> #include "DllOption.h" +#include <QObject> #include <QString> /** The ase class from which mantid custom widgets are derived it contains diff --git a/Code/Mantid/MantidQt/API/src/AlgorithmDialog.cpp b/Code/Mantid/MantidQt/API/src/AlgorithmDialog.cpp index e957d4485c8..68592535981 100644 --- a/Code/Mantid/MantidQt/API/src/AlgorithmDialog.cpp +++ b/Code/Mantid/MantidQt/API/src/AlgorithmDialog.cpp @@ -3,8 +3,9 @@ //---------------------------------- #include "MantidQtAPI/AlgorithmDialog.h" #include "MantidQtAPI/AlgorithmInputHistory.h" - +#include "MantidQtAPI/MantidWidget.h" #include "MantidAPI/FileProperty.h" +#include "MantidAPI/IWorkspaceProperty.h" #include <QIcon> #include <QLabel> @@ -31,7 +32,7 @@ AlgorithmDialog::AlgorithmDialog(QWidget* parent) : QDialog(parent), m_algorithm(NULL), m_algName(""), m_algProperties(), m_propertyValueMap(), m_tied_properties(), m_forScript(false), m_python_arguments(), m_enabledNames(), m_strMessage(""), m_msgAvailable(false), m_isInitialized(false), - m_validators(), m_inputws_opts(), m_outputws_fields(), m_wsbtn_tracker(), + m_validators(), m_noValidation(), m_inputws_opts(), m_outputws_fields(), m_wsbtn_tracker(), m_signal_mapper(new QSignalMapper()) { connect(m_signal_mapper, SIGNAL(mapped(QWidget*)), this, SLOT(replaceWSClicked(QWidget*))); @@ -56,9 +57,6 @@ void AlgorithmDialog::initializeLayout() //Set the icon setWindowIcon(QIcon(":/MantidPlot_Icon_32offset.png")); - // Fill the map of properties<->validator markers - createValidatorLabels(); - // These containers are for ensuring the 'replace input workspace; button works correctly // Store all combo boxes that relate to an input workspace m_inputws_opts.clear(); @@ -101,6 +99,51 @@ void AlgorithmDialog::parseInput() { } +/** + * 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)); + } + } +} + + +/** + * 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(); +} + /** * Get the algorithm pointer * @returns A pointer to the algorithm that is associated with the dialog @@ -116,17 +159,59 @@ Mantid::API::IAlgorithm* AlgorithmDialog::getAlgorithm() const */ Mantid::Kernel::Property* AlgorithmDialog::getAlgorithmProperty(const QString & propName) const { - if( m_algProperties.contains(propName) ) return m_algProperties.value(propName); + if( m_algProperties.contains(propName) ) + { + return m_algorithm->getProperty(propName.toStdString()); + } else return NULL; } +/** + * 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); +} + +/** + * 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; +} + /** * Get a property validator label */ QLabel* AlgorithmDialog::getValidatorMarker(const QString & propname) const { - if( m_validators.contains(propname) ) return m_validators.value(propname); - return m_validators.value(propname); + if( m_noValidation.contains(propname) ) return NULL; + QLabel *validLbl(NULL); + if( !m_validators.contains(propname) ) + { + validLbl = new QLabel("*", const_cast<AlgorithmDialog*>(this)); + 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; } /** @@ -139,6 +224,41 @@ void AlgorithmDialog::storePropertyValue(const QString & name, const QString & v m_propertyValueMap.insert(name, value); } +/** + * Set the properties that have been parsed from the dialog. + * @returns A boolean that indicates if the validation was successful. + */ +bool AlgorithmDialog::setPropertyValues() +{ + 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; + QString value = getInputValue(pName); + QLabel *validator = getValidatorMarker(pName); + std::string error(""); + Mantid::Kernel::Property *p = getAlgorithmProperty(pName); + try + { + //m_algorithm->setPropertyValue(pName.toStdString(), value.toStdString()); + error = p->setValue(value.toStdString()); + } + catch(std::exception & err_details) + { + error = err_details.what(); + allValid = false; + } + if( validator ) + { + validator->setToolTip(QString::fromStdString(error)); + if( error.empty() ) validator->hide(); + else validator->show(); + } + } + return allValid; +} + /** * Return the message string * @returns the message string @@ -197,42 +317,57 @@ bool AlgorithmDialog::isWidgetEnabled(const QString & propName) const * Tie together an input widget and a property * @param widget :: The widget that will collect the input * @param property :: The name of the property to tie the given widget to - * @param An :: optional pointer to a QLayout class that is reponsible for managing the passed widget. + * @param parent_layout :: An optional pointer to a QLayout class that is reponsible for managing the passed widget. * If given, a validator label will be added for the given input widget + * @param readHistory :: If true then a history value will be retrieved * @returns 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 */ -QWidget* AlgorithmDialog::tie(QWidget* widget, const QString & property, QLayout *parent_layout) +QWidget* AlgorithmDialog::tie(QWidget* widget, const QString & property, QLayout *parent_layout, + bool readHistory) { if( m_tied_properties.contains(property) ) { m_tied_properties.remove(property); } - Mantid::Kernel::Property * prop=getAlgorithmProperty(property); - if(prop) + Mantid::Kernel::Property * prop = getAlgorithmProperty(property); + if( prop ) { //Set a few things on the widget - QString docstring = QString::fromStdString(prop->documentation()); - widget->setToolTip(docstring); + widget->setToolTip(QString::fromStdString(prop->documentation())); } widget->setEnabled(isWidgetEnabled(property)); - setValue(widget, property); m_tied_properties.insert(property, widget); - QLabel *validlbl = getValidatorMarker(property); - // if( !parent_layout ) return validlbl; - - int item_index = parent_layout->indexOf(widget); - if( QBoxLayout *box = qobject_cast<QBoxLayout*>(parent_layout) ) + + // If the widget's layout has been given then assume that a validator is required, else assume not + QWidget* validlbl(NULL); + if( parent_layout ) { - box->insertWidget(item_index + 1, validlbl); + // 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) ) + { + box->insertWidget(item_index + 1, validlbl); + } + else if( QGridLayout *grid = qobject_cast<QGridLayout*>(parent_layout) ) + { + int row(0), col(0), span(0); + grid->getItemPosition(item_index, &row, &col, &span, &span); + grid->addWidget(validlbl, row, col + 1); + } + else {} + } } - else if( QGridLayout *grid = qobject_cast<QGridLayout*>(parent_layout) ) + else { - int row(0), col(0), span(0); - grid->getItemPosition(item_index, &row, &col, &span, &span); - grid->addWidget(validlbl, row, col + 1); + m_noValidation.append(property); } - else + + if( readHistory ) { + setPreviousValue(widget, property); } return validlbl; @@ -573,23 +708,6 @@ void AlgorithmDialog::replaceWSClicked(QWidget *outputEdit) //------------------------------------------------------ // Private member functions //------------------------------------------------------ -/** - * 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(); - 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 ) - { - m_algProperties.insert(QString::fromStdString((*itr)->name()), *itr); - } -} - /** * Parse out information from the dialog */ @@ -607,86 +725,6 @@ void AlgorithmDialog::parse() parseInput(); } - -/** - * Set the properties that have been parsed from the dialog. - * @returns A boolean that indicates if the validation was successful. - */ -bool AlgorithmDialog::setPropertyValues() -{ - QHash<QString, Mantid::Kernel::Property*>::const_iterator pend = m_algProperties.end(); - bool allValid(true); - for( QHash<QString, Mantid::Kernel::Property*>::const_iterator pitr = m_algProperties.begin(); - pitr != pend; ++pitr ) - { - Mantid::Kernel::Property *prop = pitr.value(); - QString pName = pitr.key(); - QString value = m_propertyValueMap.value(pName); - QLabel *validator = getValidatorMarker(pitr.key()); - - std::string error = ""; - if ( !value.isEmpty() ) - {//if there something in the box then use it - try - { - error = prop->setValue(value.toStdString()); - } - catch(std::exception & err_details) - { - error = err_details.what(); - } - } - else - {//else use the default which may or may not be a valid property value - try - { - error = prop->setValue(prop->getDefault()); - } - catch(std::exception& err_details) - { - error = err_details.what(); - } - } - - if( error.empty() ) - {//no error - if( validator ) validator->hide(); - //Store value for future input if it is not default - } - else - {//the property could not be set - allValid = false; - if( validator && validator->parent() ) - { - //a description of the problem will be visible to users if they their mouse pointer lingers over validator star mark - validator->setToolTip( QString::fromStdString(error) ); - validator->show(); - } - } - } - return allValid; -} - -/** -* Save the property values to the input history -*/ -void AlgorithmDialog::saveInput() -{ - AlgorithmInputHistory::Instance().clearAlgorithmInput(m_algName); - QHash<QString, Mantid::Kernel::Property*>::const_iterator pend = m_algProperties.end(); - - for( QHash<QString, Mantid::Kernel::Property*>::const_iterator pitr = m_algProperties.begin(); - pitr != pend; ++pitr ) - { - if ( pitr.value()->remember() ) - { - QString pName = pitr.key(); - QString value = m_propertyValueMap.value(pName); - AlgorithmInputHistory::Instance().storeNewValue(m_algName, QPair<QString, QString>(pName, value)); - } - } -} - /** * 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 @@ -744,27 +782,9 @@ void AlgorithmDialog::setOptionalMessage(const QString & message) if( message.isEmpty() ) m_msgAvailable = false; } -/** - * This sets up the labels that are to be used to mark whether a property is valid. It has - * a default implmentation but can be overridden if some other marker is required - */ -void AlgorithmDialog::createValidatorLabels() -{ - QHash<QString, Mantid::Kernel::Property*>::const_iterator pend = m_algProperties.end(); - for( QHash<QString, Mantid::Kernel::Property*>::const_iterator pitr = m_algProperties.begin(); - pitr != pend; ++pitr ) - { - QLabel *validLbl = new QLabel("*"); - QPalette pal = validLbl->palette(); - pal.setColor(QPalette::WindowText, Qt::darkRed); - validLbl->setPalette(pal); - m_validators[pitr.key()] = validLbl; - } -} - /** * 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 and QCheckBox + * that are being used. Currently it knows about QComboBox, QLineEdit, QCheckBox and MWRunFiles * @param widget :: A pointer to the widget */ QString AlgorithmDialog::getValue(QWidget *widget) @@ -788,6 +808,10 @@ QString AlgorithmDialog::getValue(QWidget *widget) return QString("0"); } } + else if( MantidWidget *mtd_widget = qobject_cast<MantidWidget*>(widget) ) + { + return mtd_widget->getUserInput().toString(); + } else { QMessageBox::warning(this, windowTitle(), @@ -803,7 +827,7 @@ QString AlgorithmDialog::getValue(QWidget *widget) * @param widget :: A pointer to the widget * @param property :: The property name */ -void AlgorithmDialog::setValue(QWidget *widget, const QString & propName) +void AlgorithmDialog::setPreviousValue(QWidget *widget, const QString & propName) { // Get the value from either the previous input store or from Python argument QString value(""); @@ -835,23 +859,9 @@ void AlgorithmDialog::setValue(QWidget *widget, const QString & propName) { opts->setCurrentIndex(index); } + return; } - else if( QLineEdit *textfield = qobject_cast<QLineEdit*>(widget) ) - { - if( !isForScript() ) - { - textfield->setText(value); - } - else - { - //Need to check if this is the default value as we don't fill them in if they are - if( m_python_arguments.contains(propName) || !property->isDefault() ) - { - textfield->setText(value); - } - } - } - else if( QCheckBox *checker = qobject_cast<QCheckBox*>(widget) ) + if( QCheckBox *checker = qobject_cast<QCheckBox*>(widget) ) { if( value.isEmpty() && dynamic_cast<Mantid::Kernel::PropertyWithValue<bool>* >(property) ) { @@ -865,12 +875,32 @@ void AlgorithmDialog::setValue(QWidget *widget, const QString & propName) { checker->setCheckState(Qt::Checked); } - + return; } - else + + QLineEdit *textfield = qobject_cast<QLineEdit*>(widget); + MantidWidget *mtdwidget = qobject_cast<MantidWidget*>(widget); + if( textfield || mtdwidget ) { - QMessageBox::warning(this, windowTitle(), - QString("Cannot set value for ") + widget->metaObject()->className() + - ". Update AlgorithmDialog::setValue() to cope with this widget."); + if( !isForScript() ) + { + if( textfield ) textfield->setText(value); + else mtdwidget->setUserInput(value); + } + else + { + //Need to check if this is the default value as we don't fill them in if they are + if( m_python_arguments.contains(propName) || !property->isDefault() ) + { + if( textfield ) textfield->setText(value); + else mtdwidget->setUserInput(value); + } + } + return; } + + // Reaching here means we have a widget type we don't understand. Tell the developer + QMessageBox::warning(this, windowTitle(), + QString("Cannot set value for ") + widget->metaObject()->className() + + ". Update AlgorithmDialog::setValue() to cope with this widget."); } diff --git a/Code/Mantid/MantidQt/API/src/GenericDialog.cpp b/Code/Mantid/MantidQt/API/src/GenericDialog.cpp index 86158db6571..fbe912f3354 100644 --- a/Code/Mantid/MantidQt/API/src/GenericDialog.cpp +++ b/Code/Mantid/MantidQt/API/src/GenericDialog.cpp @@ -142,11 +142,8 @@ void GenericDialog::initLayout() //For everything else render a text box else { - - QLineEdit *textBox = new QLineEdit; nameLbl->setBuddy(textBox); - //check this is a masked property Mantid::Kernel::MaskedProperty<std::string> * maskedProp = dynamic_cast<Mantid::Kernel::MaskedProperty<std::string> *>(prop); if(maskedProp) @@ -155,8 +152,6 @@ void GenericDialog::initLayout() } m_editBoxes[textBox] = propName; - - //Add the widgets to the grid m_inputGrid->addWidget(nameLbl, row, 0, 0); m_inputGrid->addWidget(textBox, row, 1, 0); diff --git a/Code/Mantid/MantidQt/CustomDialogs/CMakeLists.txt b/Code/Mantid/MantidQt/CustomDialogs/CMakeLists.txt index 3cf0d3a4eb8..ecfcd16c551 100644 --- a/Code/Mantid/MantidQt/CustomDialogs/CMakeLists.txt +++ b/Code/Mantid/MantidQt/CustomDialogs/CMakeLists.txt @@ -1,4 +1,5 @@ set ( SRC_FILES src/CreateSampleShapeDialog.cpp + src/LoadDialog.cpp src/LoadAsciiDialog.cpp src/LoadDAEDialog.cpp src/LoadRawDialog.cpp @@ -10,6 +11,7 @@ set ( SRC_FILES src/CreateSampleShapeDialog.cpp # Include files aren't required, but this makes them appear in Visual Studio set ( INC_FILES inc/MantidQtCustomDialogs/CreateSampleShapeDialog.h + inc/MantidQtCustomDialogs/LoadDialog.h inc/MantidQtCustomDialogs/LoadAsciiDialog.h inc/MantidQtCustomDialogs/LoadDAEDialog.h inc/MantidQtCustomDialogs/LoadRawDialog.h @@ -20,6 +22,7 @@ set ( INC_FILES inc/MantidQtCustomDialogs/CreateSampleShapeDialog.h ) set ( MOC_FILES inc/MantidQtCustomDialogs/CreateSampleShapeDialog.h + inc/MantidQtCustomDialogs/LoadDialog.h inc/MantidQtCustomDialogs/LoadAsciiDialog.h inc/MantidQtCustomDialogs/LoadDAEDialog.h inc/MantidQtCustomDialogs/LoadRawDialog.h @@ -36,6 +39,9 @@ set ( UI_FILES inc/MantidQtCustomDialogs/CreateSampleShapeDialog.ui ) include_directories ( inc ) +include_directories ( ../MantidWidgets/inc ) +include_directories ( ${CMAKE_CURRENT_BINARY_DIR}/../MantidWidgets ) +include_directories ( ${CMAKE_CURRENT_BINARY_DIR}/../API ) qt4_wrap_cpp ( MOCCED_FILES ${MOC_FILES} ) @@ -48,4 +54,4 @@ set_target_properties ( CustomDialogs PROPERTIES OUTPUT_NAME MantidQtCustomDialo # Add to the 'MantidQt' group in VS set_property ( TARGET CustomDialogs PROPERTY FOLDER "MantidQt" ) -target_link_libraries ( CustomDialogs MantidQtAPI ) \ No newline at end of file +target_link_libraries ( CustomDialogs MantidQtAPI ) diff --git a/Code/Mantid/MantidQt/CustomDialogs/CustomDialogs.pro b/Code/Mantid/MantidQt/CustomDialogs/CustomDialogs.pro index 8350ce05c2c..c290980b851 100644 --- a/Code/Mantid/MantidQt/CustomDialogs/CustomDialogs.pro +++ b/Code/Mantid/MantidQt/CustomDialogs/CustomDialogs.pro @@ -32,9 +32,9 @@ SOURCES = $$SRCDIR/LoadRawDialog.cpp \ $$SRCDIR/MantidGLWidget.cpp \ $$SRCDIR/PlotAsymmetryByLogValueDialog.cpp \ $$SRCDIR/LoadDAEDialog.cpp \ - $$SRCDIR/LoadAsciiDialog.cpp - - + $$SRCDIR/LoadAsciiDialog.cpp \ + $$SRCDIR/LoadDialog.cpp + HEADERS = $$HEADERDIR/LoadRawDialog.h \ $$HEADERDIR/LOQScriptInputDialog.h \ $$HEADERDIR/CreateSampleShapeDialog.h \ @@ -42,8 +42,8 @@ HEADERS = $$HEADERDIR/LoadRawDialog.h \ $$HEADERDIR/MantidGLWidget.h \ $$HEADERDIR/PlotAsymmetryByLogValueDialog.h \ $$HEADERDIR/LoadDAEDialog.h \ - $$HEADERDIR/LoadAsciiDialog.h - + $$HEADERDIR/LoadAsciiDialog.h \ + $$HEADERDIR/LoadDialog.h UI_DIR = $$HEADERDIR diff --git a/Code/Mantid/MantidQt/CustomDialogs/inc/MantidQtCustomDialogs/LoadDialog.h b/Code/Mantid/MantidQt/CustomDialogs/inc/MantidQtCustomDialogs/LoadDialog.h new file mode 100644 index 00000000000..d0fc453b1ea --- /dev/null +++ b/Code/Mantid/MantidQt/CustomDialogs/inc/MantidQtCustomDialogs/LoadDialog.h @@ -0,0 +1,113 @@ +#ifndef MANTIDQT_CUSTOM_DIALOGS_LOADDIALOG_H +#define MANTIDQT_CUSTOM_DIALOGS_LOADDIALOG_H + +//------------------------------------------------------------------------------ +// Includes +//------------------------------------------------------------------------------ +#include "MantidQtAPI/AlgorithmDialog.h" + +//------------------------------------------------------------------------------ +// Qt Forward declarations +//------------------------------------------------------------------------------ +class QLineEdit; +class QBoxLayout; +class QVBoxLayout; +class QHBoxLayout; +class QGridLayout; +class QSignalMapper; + +namespace MantidQt +{ + //------------------------------------------------------------------------------ + // Mantid Forward declarations + //------------------------------------------------------------------------------ + namespace MantidWidgets + { + class MWRunFiles; + } + + namespace CustomDialogs + { + + /** + This class gives specialised dialog for the Load algorithm. It requires that the specific + load algorithm has at least 2 properties with these names: + + <UL> + <LI>Filename - A text property containing the filename </LI> + <LI>OutputWorkspace - A text property containing the name of the OutputWorkspace </LI> + </UL> + + There is no UI form as the most of the thing is dynamic. + + @author Martyn Gigg, Tessella plc + @date 31/01/2011 + + Copyright © 2011 ISIS Rutherford Appleton Laboratory & NScD Oak Ridge National Laboratory + + This file is part of Mantid. + + Mantid is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + Mantid is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + + File change history is stored at: <https://svn.mantidproject.org/mantid/trunk/Code/Mantid> + Code Documentation is available at: <http://doxygen.mantidproject.org> + */ + class LoadDialog : public API::AlgorithmDialog + { + Q_OBJECT + + public: + /// Default constructor + LoadDialog(QWidget *parent = NULL); + + private: + /// Initialize the layout + void initLayout(); + /// Save the input history + void saveInput(); + /// Create the widgets and layouts that are static, i.e do not depend on + /// the specific load algorithm + void createStaticWidgets(QBoxLayout* layout); + /// Tie static widgets to their properties + void tieStaticWidgets(const bool readHistory); + /// Clears all of the widgets from the old layout + void setupDynamicLayout(); + /// Create the widgets for a given property + QBoxLayout* createWidgetsForProperty(const Mantid::Kernel::Property* prop, + QGridLayout *loaderGrid); + + private slots: + /// Create the widgets and layouts that are dynamic, i.e they depend on + /// the specific load algorithm + void createDynamicWidgets(); + /// Override the help button clicked method + void helpClicked(); + + private: + /// A widget for the filename text input + MantidWidgets::MWRunFiles *m_fileWidget; + /// The workspace name widget + QLineEdit *m_wkspaceWidget; + /// The HBox layout for the workspace line + QHBoxLayout *m_wkspaceLayout; + /// The top-level layout + QVBoxLayout *m_dialogLayout; + /// The dynamic layout + QGridLayout *m_loaderLayout; + }; + + } +} + +#endif //MANTIDQT_CUSTOM_DIALOGS_LOADDIALOG_H diff --git a/Code/Mantid/MantidQt/CustomDialogs/src/LoadDialog.cpp b/Code/Mantid/MantidQt/CustomDialogs/src/LoadDialog.cpp new file mode 100644 index 00000000000..fbabc3e9b55 --- /dev/null +++ b/Code/Mantid/MantidQt/CustomDialogs/src/LoadDialog.cpp @@ -0,0 +1,284 @@ +//------------------------------------------------------------------------------ +// Includes +//------------------------------------------------------------------------------ +#include "MantidQtCustomDialogs/LoadDialog.h" +#include "MantidQtMantidWidgets/MWRunFiles.h" +// Qt +#include <QLineEdit> +#include <QCheckBox> +#include <QComboBox> +#include <QUrl> +#include <QDesktopServices> +// Mantid +#include "MantidKernel/Property.h" +#include "MantidKernel/MaskedProperty.h" +#include "MantidAPI/IWorkspaceProperty.h" +#include "MantidAPI/FileProperty.h" + +namespace MantidQt +{ + namespace CustomDialogs + { + // Declare the dialog. Name must match the class name + DECLARE_DIALOG(LoadDialog); + + //-------------------------------------------------------------------------- + // Public methods + //--------------------------------------------------------------------------- + + /// Default constructor + LoadDialog:: LoadDialog(QWidget *parent) + : API::AlgorithmDialog(parent), m_fileWidget(NULL), m_wkspaceWidget(NULL), + m_wkspaceLayout(NULL), m_dialogLayout(NULL), m_loaderLayout(NULL) + + { + QSizePolicy sizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum); + setSizePolicy(sizePolicy); + } + + //-------------------------------------------------------------------------- + // Private methods (non-slot) + //--------------------------------------------------------------------------- + + /// Initialize the layout + void LoadDialog::initLayout() + { + m_dialogLayout = new QVBoxLayout(this); + createStaticWidgets(m_dialogLayout); + m_dialogLayout->addLayout(createDefaultButtonLayout()); + + // Now we have the static widgets in place, connect the file editing finished signal and + // then tie the widget so that this will trigger the dynamic form generation if + // there is any input history + + // Connect the file finder's file found signal to the dynamic property create method. + // When the file text is set the Load algorithm finds the concrete loader and then we + // know what extra properties to create + connect(m_fileWidget, SIGNAL(fileEditingFinished()), this, SLOT(createDynamicWidgets())); + tieStaticWidgets(true); + } + + /** + * Save the input after OK is clicked + */ + void LoadDialog::saveInput() + { + m_fileWidget->saveSettings("Mantid/Algorithms/Load"); + AlgorithmDialog::saveInput(); + } + + /** + * Create the widgets and layouts that are static, i.e do not depend on + * the specific load algorithm + * @param layout The layout to hold the widgets + */ + void LoadDialog::createStaticWidgets(QBoxLayout *widgetLayout) + { + QVBoxLayout *staticLayout = new QVBoxLayout(); + if( isMessageAvailable() ) + { + QLabel *inputMessage = new QLabel(this); + inputMessage->setFrameStyle(QFrame::Panel | QFrame::Sunken); + inputMessage->setText(getOptionalMessage()); + QHBoxLayout *msgArea = new QHBoxLayout; + msgArea->addWidget(inputMessage); + staticLayout->addLayout(msgArea); + } + + // Filename widget + m_fileWidget = new MantidWidgets::MWRunFiles(this); + m_fileWidget->setLabelText("File"); + m_fileWidget->isForRunFiles(true); + m_fileWidget->allowMultipleFiles(false); + m_fileWidget->isOptional(false); + m_fileWidget->doMultiEntry(false); + m_fileWidget->readSettings("Mantid/Algorithms/Load"); + QHBoxLayout *propLine = new QHBoxLayout; + propLine->addWidget(m_fileWidget); + staticLayout->addLayout(propLine); + + // Workspace property + m_wkspaceLayout = new QHBoxLayout; + m_wkspaceLayout->addWidget(new QLabel("Workspace")); + m_wkspaceWidget = new QLineEdit(this); + m_wkspaceLayout->addWidget(m_wkspaceWidget); + staticLayout->addLayout(m_wkspaceLayout); + + // Add to the static layout + widgetLayout->addLayout(staticLayout); + } + + /** + * Tie static widgets to their properties + * @param readHistory :: If true then the history will be re read. + */ + void LoadDialog::tieStaticWidgets(const bool readHistory) + { + tie(m_wkspaceWidget, "OutputWorkspace", m_wkspaceLayout, readHistory); + tie(m_fileWidget, "Filename", NULL, readHistory); + } + + /** + * Clear the old widgets for a new Loader type + */ + void LoadDialog::setupDynamicLayout() + { + // Remove the old widgets if necessary + if( m_loaderLayout ) + { + m_dialogLayout->takeAt(1); + QLayoutItem *child; + while( (child = m_loaderLayout->takeAt(0)) != NULL ) + { + delete child->widget(); + delete child; + } + delete m_loaderLayout; + m_loaderLayout = NULL; + this->adjustSize(); + } + + m_loaderLayout = new QGridLayout; + m_dialogLayout->insertLayout(1, m_loaderLayout); + // Remove the old workspace validator label as it's simpler to just create another one + QLayoutItem *child = m_wkspaceLayout->takeAt(2); + if( child ) + { + delete child->widget(); + delete child; + } + } + + /** + * Return a layout containing suitable widgets for the given property + * @param prop A pointer to the algorithm property + * @param loaderGrid A layout where the widgets are to be placed + */ + QBoxLayout* LoadDialog::createWidgetsForProperty(const Mantid::Kernel::Property* prop, + QGridLayout *loaderGrid) + { + using namespace Mantid::API; + using namespace Mantid::Kernel; + using MantidQt::MantidWidgets::MWRunFiles; + + QString propName = QString::fromStdString(prop->name()); + QWidget *inputWidget(NULL); + bool addValidator(true); + const int row = loaderGrid->rowCount(); + + // Boolean properties use the name labels differently + if( const FileProperty* fileType = dynamic_cast<const FileProperty*>(prop) ) + { + MWRunFiles *fileFinder = new MWRunFiles(); + inputWidget = fileFinder; + fileFinder->setLabelText(propName); + fileFinder->isForRunFiles(false); + fileFinder->isOptional(fileType->isOptional()); + fileFinder->doMultiEntry(false); + // Ensure this spans the whole width of the grid + loaderGrid->addWidget(inputWidget, row, 0, 1, 3); + addValidator = false; + } + else + { + QLabel *nameLbl = new QLabel(propName); + nameLbl->setToolTip(QString::fromStdString(prop->documentation())); + if( dynamic_cast<const PropertyWithValue<bool>* >(prop) ) + { + QCheckBox *checkBox = new QCheckBox(); + inputWidget = checkBox; + addValidator = false; + } + // Options box + else if( !prop->allowedValues().empty() ) + { + QComboBox *optionsBox = new QComboBox(); + inputWidget = optionsBox; + std::set<std::string> items = prop->allowedValues(); + std::set<std::string>::const_iterator vend = items.end(); + for(std::set<std::string>::const_iterator vitr = items.begin(); vitr != vend; + ++vitr) + { + optionsBox->addItem(QString::fromStdString(*vitr)); + } + addValidator = false; + } + // else render a text box + else + { + QLineEdit *textBox = new QLineEdit(); + inputWidget = textBox; + if( dynamic_cast<const MaskedProperty<std::string> *>(prop) ) + { + textBox->setEchoMode(QLineEdit::Password); + } + } + nameLbl->setBuddy(inputWidget); + loaderGrid->addWidget(nameLbl, row, 0); + loaderGrid->addWidget(inputWidget, row, 1); + } + + if( addValidator ) tie(inputWidget, propName, loaderGrid); + else tie(inputWidget, propName, NULL); + + return NULL; + } + + //-------------------------------------------------------------------------- + // Private methods (slot) + //--------------------------------------------------------------------------- + + /** + * Create the widgets and layouts that are dynamic + */ + void LoadDialog::createDynamicWidgets() + { + using namespace Mantid::API; + using namespace Mantid::Kernel; + + if( !m_fileWidget->isValid() ) return; + // First step is the get the specific loader that is reponsible + IAlgorithm *loadAlg = getAlgorithm(); + const std::string filename = m_fileWidget->getFirstFilename().toStdString(); + if( filename.empty() ) return; + try + { + loadAlg->setPropertyValue("Filename", filename); + } + catch(std::exception & exc) + { + m_fileWidget->setFileProblem(QString::fromStdString(exc.what())); + return; + } + // Reset the algorithm pointer so that the base class re-reads the properties and drops links from + // old widgets meaning they are safe to remove + this->setAlgorithm(loadAlg); + + setupDynamicLayout(); + tieStaticWidgets(false); + const std::vector<Property*> & inputProps = loadAlg->getProperties(); + for( size_t i = 0; i < inputProps.size(); ++i ) + { + const Property* prop = inputProps[i]; + const QString propName = QString::fromStdString(prop->name()); + if( propName == "OutputWorkspace" || propName == "Filename" ) continue; + if( requiresUserInput(propName) ) + { + createWidgetsForProperty(prop, m_loaderLayout); + } + } + + // Attempt to set any values that may have been retrieved + setPropertyValues(); + } + + /// Override the help button clicked method + void LoadDialog::helpClicked() + { + const std::string & loaderName = getAlgorithm()->getPropertyValue("LoaderName"); + QString helpPage = (loaderName.empty()) ? QString("Load") : QString::fromStdString(loaderName); + QDesktopServices::openUrl(QUrl(QString("http://www.mantidproject.org/") + helpPage)); + } + + } +} diff --git a/Code/Mantid/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/MWDiag.h b/Code/Mantid/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/MWDiag.h index ec58db6a8ad..323ef947345 100644 --- a/Code/Mantid/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/MWDiag.h +++ b/Code/Mantid/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/MWDiag.h @@ -7,6 +7,7 @@ #include <QSettings> #include <QStringList> #include <QComboBox> +#include <boost/shared_ptr.hpp> //----------------------------------------------- // Forward declarations diff --git a/Code/Mantid/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/MWRunFiles.h b/Code/Mantid/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/MWRunFiles.h index f4434128235..1c56c2a1f7f 100644 --- a/Code/Mantid/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/MWRunFiles.h +++ b/Code/Mantid/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/MWRunFiles.h @@ -53,11 +53,11 @@ namespace MantidQt Q_PROPERTY(QStringList fileExtensions READ getFileExtensions WRITE setFileExtensions) public: - /// Flags for workspace entries - enum - { - NO_ENTRY_NUM = -1, ///< error in the entry number setting - ALL_ENTRIES = -2 ///< use all entries (i.e. entry number was left blank) + /// Flags for workspace entries + enum + { + NO_ENTRY_NUM = -1, ///< error in the entry number setting + ALL_ENTRIES = -2 ///< use all entries (i.e. entry number was left blank) }; ///Default constructor @@ -83,7 +83,12 @@ namespace MantidQt QStringList getFilenames() const; QString getFirstFilename() const; int getEntryNum() const; - + /// Overridden from base class to retrieve user input through a common interface + QVariant getUserInput() const; + /// Sets a value on the widget through a common interface + void setUserInput(const QVariant & value); + /// flag a problem with the file the user entered, an empty string means no error + void setFileProblem(const QString & message); /// Read settings from the given group void readSettings(const QString & group); /// Save settings in the given group @@ -108,12 +113,10 @@ namespace MantidQt QStringList getFileExtensionsFromAlgorithm(const QString & algName, const QString &propName); /// Open a file dialog QString openFileDia(); - /// flag a problem with the file the user entered, an empty string means no error - void setFileProblem(const QString & message); /// flag a problem with the supplied entry number, an empty string means no error void setEntryNumProblem(const QString & message); /// displays the validator red star if either m_fileProblem or m_entryNumProblem are not empty - void refreshvalidator(); + void refreshValidator(); private slots: /// Browse clicked slot diff --git a/Code/Mantid/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/MWRunFiles.ui b/Code/Mantid/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/MWRunFiles.ui index 5ac5e82d236..9a37da8e458 100644 --- a/Code/Mantid/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/MWRunFiles.ui +++ b/Code/Mantid/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/MWRunFiles.ui @@ -1,69 +1,73 @@ -<ui version="4.0" > +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> <class>MWRunFiles</class> - <widget class="QWidget" name="MWRunFiles" > - <property name="geometry" > + <widget class="QWidget" name="MWRunFiles"> + <property name="geometry"> <rect> <x>0</x> <y>0</y> - <width>231</width> + <width>238</width> <height>41</height> </rect> </property> - <property name="sizePolicy" > - <sizepolicy vsizetype="Minimum" hsizetype="Preferred" > + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Minimum"> <horstretch>0</horstretch> - <verstretch>41</verstretch> + <verstretch>0</verstretch> </sizepolicy> </property> - <property name="windowTitle" > + <property name="windowTitle"> <string>Form</string> </property> - <layout class="QGridLayout" name="gridLayout" > - <property name="verticalSpacing" > + <layout class="QGridLayout" name="gridLayout"> + <property name="sizeConstraint"> + <enum>QLayout::SetFixedSize</enum> + </property> + <property name="verticalSpacing"> <number>0</number> </property> - <property name="margin" > + <property name="margin"> <number>0</number> </property> - <item row="0" column="1" > - <widget class="QLineEdit" name="fileEditor" > - <property name="sizePolicy" > - <sizepolicy vsizetype="Fixed" hsizetype="Expanding" > + <item row="0" column="1"> + <widget class="QLineEdit" name="fileEditor"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Fixed"> <horstretch>0</horstretch> <verstretch>20</verstretch> </sizepolicy> </property> </widget> </item> - <item row="0" column="5" > - <widget class="QPushButton" name="browseBtn" > - <property name="text" > + <item row="0" column="5"> + <widget class="QPushButton" name="browseBtn"> + <property name="text"> <string>Browse</string> </property> </widget> </item> - <item row="0" column="0" > - <widget class="QLabel" name="textLabel" > - <property name="text" > + <item row="0" column="0"> + <widget class="QLabel" name="textLabel"> + <property name="text"> <string>TextLabel</string> </property> </widget> </item> - <item row="0" column="3" > - <widget class="QLineEdit" name="entryNum" > - <property name="sizePolicy" > - <sizepolicy vsizetype="Fixed" hsizetype="Maximum" > + <item row="0" column="3"> + <widget class="QLineEdit" name="entryNum"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Maximum" vsizetype="Fixed"> <horstretch>40</horstretch> <verstretch>0</verstretch> </sizepolicy> </property> - <property name="minimumSize" > + <property name="minimumSize"> <size> <width>30</width> <height>0</height> </size> </property> - <property name="maximumSize" > + <property name="maximumSize"> <size> <width>20</width> <height>16777215</height> @@ -71,20 +75,20 @@ </property> </widget> </item> - <item row="0" column="4" > - <widget class="QLabel" name="valid" > - <property name="sizePolicy" > - <sizepolicy vsizetype="Fixed" hsizetype="Fixed" > + <item row="0" column="4"> + <widget class="QLabel" name="valid"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> <horstretch>20</horstretch> <verstretch>20</verstretch> </sizepolicy> </property> - <property name="palette" > + <property name="palette"> <palette> <active> - <colorrole role="WindowText" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="WindowText"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>170</red> <green>0</green> <blue>0</blue> @@ -93,9 +97,9 @@ </colorrole> </active> <inactive> - <colorrole role="WindowText" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="WindowText"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>170</red> <green>0</green> <blue>0</blue> @@ -104,9 +108,9 @@ </colorrole> </inactive> <disabled> - <colorrole role="WindowText" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="WindowText"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>118</red> <green>116</green> <blue>108</blue> @@ -116,7 +120,7 @@ </disabled> </palette> </property> - <property name="text" > + <property name="text"> <string>*</string> </property> </widget> diff --git a/Code/Mantid/MantidQt/MantidWidgets/src/MWRunFiles.cpp b/Code/Mantid/MantidQt/MantidWidgets/src/MWRunFiles.cpp index 2fe1f02722b..c5dcfa26523 100644 --- a/Code/Mantid/MantidQt/MantidWidgets/src/MWRunFiles.cpp +++ b/Code/Mantid/MantidQt/MantidWidgets/src/MWRunFiles.cpp @@ -26,10 +26,10 @@ MWRunFiles::MWRunFiles(QWidget *parent) : MantidWidget(parent), m_uiForm.setupUi(this); connect(m_uiForm.fileEditor, SIGNAL(textChanged(const QString &)), this, SIGNAL(fileTextChanged(const QString&))); - connect(m_uiForm.fileEditor, SIGNAL(editingFinished()), this, SLOT(findFiles())); - connect(m_uiForm.fileEditor, SIGNAL(editingFinished()), this, SIGNAL(fileEditingFinished())); connect(m_uiForm.browseBtn, SIGNAL(clicked()), this, SLOT(browseClicked())); + connect(m_uiForm.fileEditor, SIGNAL(editingFinished()), this, SIGNAL(fileEditingFinished())); + connect(this, SIGNAL(fileEditingFinished()), this, SLOT(findFiles())); connect(m_uiForm.entryNum, SIGNAL(textChanged(const QString &)), this, SLOT(checkEntry())); connect(m_uiForm.entryNum, SIGNAL(editingFinished()), this, SLOT(checkEntry())); @@ -141,7 +141,7 @@ void MWRunFiles::doMultiEntry(const bool multiEntry) { m_uiForm.entryNum->hide(); } - refreshvalidator(); + refreshValidator(); } /** @@ -238,6 +238,39 @@ int MWRunFiles::getEntryNum() const return NO_ENTRY_NUM; } +/** + * Retrieve user input from this widget. NOTE: This knows nothing of periods yet + * @returns A qvariant + */ +QVariant MWRunFiles::getUserInput() const +{ + return QVariant(m_uiForm.fileEditor->text()); +} + +/** + * Sets a value on the widget through a common interface. The + * QVariant is assumed to be text and to contain a file string. Note that this + * is primarily here for use within the AlgorithmDialog + * @param value A QVariant containing user text + */ +void MWRunFiles::setUserInput(const QVariant & value) +{ + m_uiForm.fileEditor->setText(value.toString()); + emit fileEditingFinished(); +} + +/** + * Flag a problem with the file the user entered, an empty string means no error but + * there may be an error with the entry box if enabled. Errors passed here are shown first + * @param A message to include or "" for no error + */ +void MWRunFiles::setFileProblem(const QString & message) +{ + m_fileProblem = message; + refreshValidator(); +} + + /** * Save settings to the given group * @param group :: The name of the group key to save to @@ -484,16 +517,6 @@ QString MWRunFiles::openFileDia() return filenames.join(", "); } -/** -* Flag a problem with the file the user entered, an empty string means no error but -* there may be an error with the entry box if enabled. Errors passed here are shown first -* @param A message to include or "" for no error -*/ -void MWRunFiles::setFileProblem(const QString & message) -{ - m_fileProblem = message; - refreshvalidator(); -} /** flag a problem with the supplied entry number, an empty string means no error. * file errors take precedence of these errors @@ -502,13 +525,13 @@ void MWRunFiles::setFileProblem(const QString & message) void MWRunFiles::setEntryNumProblem(const QString & message) { m_entryNumProblem = message; - refreshvalidator(); + refreshValidator(); } /** Checks the data m_fileProblem and m_entryNumProblem to see if the validator label * needs to be displayed */ -void MWRunFiles::refreshvalidator() +void MWRunFiles::refreshValidator() { if ( ! m_fileProblem.isEmpty() ) { @@ -548,7 +571,6 @@ void MWRunFiles::browseClicked() { m_uiForm.fileEditor->setText(uFile); } - findFiles(); emit fileEditingFinished(); } /** Currently just checks that entryNum contains an int > 0 and hence might be a -- GitLab