diff --git a/Code/Mantid/Framework/Kernel/test/MultiFileNameParserTest.h b/Code/Mantid/Framework/Kernel/test/MultiFileNameParserTest.h index 206d7e90e237..5e6ec38ab140 100644 --- a/Code/Mantid/Framework/Kernel/test/MultiFileNameParserTest.h +++ b/Code/Mantid/Framework/Kernel/test/MultiFileNameParserTest.h @@ -311,44 +311,6 @@ class MultiFileNameParserTest : public CxxTest::TestSuite std::string(re.what()), "There does not appear to be an instrument name present."); } - - /*void test_errorThrownIfPassedInvalidInstrumentName() - { - Parser parser; - - TS_ASSERT_THROWS_EQUALS(parser.parse("TSSC20:30.raw"), - const std::runtime_error & re, - std::string(re.what()), - "There does not appear to be a valid instrument name present."); - }*/ - - ///////////////////////////////////////////////////////////////////////////// - // Testing of flatten function. - ///////////////////////////////////////////////////////////////////////////// - - /*void test_flattenVecOfVecs() - { - Parser parser; - - parser.parse("TSC10-15, 30:40:2.raw"); - - std::vector > filenames = parser.fileNames(); - std::vector flattenedFilenames = flatten(filenames); - - TS_ASSERT_EQUALS(flattenedFilenames[0], "TSC00010.raw"); - TS_ASSERT_EQUALS(flattenedFilenames[1], "TSC00011.raw"); - TS_ASSERT_EQUALS(flattenedFilenames[2], "TSC00012.raw"); - TS_ASSERT_EQUALS(flattenedFilenames[3], "TSC00013.raw"); - TS_ASSERT_EQUALS(flattenedFilenames[4], "TSC00014.raw"); - TS_ASSERT_EQUALS(flattenedFilenames[5], "TSC00015.raw"); - - TS_ASSERT_EQUALS(flattenedFilenames[6], "TSC00030.raw"); - TS_ASSERT_EQUALS(flattenedFilenames[7], "TSC00032.raw"); - TS_ASSERT_EQUALS(flattenedFilenames[8], "TSC00034.raw"); - TS_ASSERT_EQUALS(flattenedFilenames[9], "TSC00036.raw"); - TS_ASSERT_EQUALS(flattenedFilenames[10], "TSC00038.raw"); - TS_ASSERT_EQUALS(flattenedFilenames[11], "TSC00040.raw"); - }*/ }; #endif /* MANTID_KERNEL_MULTIFILENAMEPARSERTEST_H_ */ \ No newline at end of file diff --git a/WorkForHome b/WorkForHome deleted file mode 100644 index bd3e6538b8cf..000000000000 --- a/WorkForHome +++ /dev/null @@ -1,1621 +0,0 @@ -diff --git a/Code/Mantid/Framework/API/inc/MantidAPI/MultipleFileProperty.h b/Code/Mantid/Framework/API/inc/MantidAPI/MultipleFileProperty.h -index 3dca5a1..6717a37 100644 ---- a/Code/Mantid/Framework/API/inc/MantidAPI/MultipleFileProperty.h -+++ b/Code/Mantid/Framework/API/inc/MantidAPI/MultipleFileProperty.h -@@ -2,8 +2,9 @@ - #define MANTID_API_MULTIPLEFILEPROPERTY_H_ - - #include "MantidKernel/System.h" --#include "MantidKernel/ArrayProperty.h" -- -+#include "MantidKernel/MultiFileNameParser.h" -+#include -+#include - - namespace Mantid - { -@@ -32,33 +33,42 @@ namespace API - File change history is stored at: - Code Documentation is available at: - */ -- class DLLExport MultipleFileProperty : public Kernel::ArrayProperty -+ class DLLExport MultipleFileProperty : public Kernel::PropertyWithValue< std::vector< std::vector< std::string> > > - { - public: -- MultipleFileProperty(const std::string & name, const std::vector & exts = std::vector(), -- bool optional=false); -+ ///Constructor -+ MultipleFileProperty(const std::string & name,const std::vector & exts = std::vector()); - - ~MultipleFileProperty(); - -- ///Overridden setValue method -+ /// 'Virtual copy constructor -+ virtual MultipleFileProperty* clone() { return new MultipleFileProperty(*this); } -+ -+ /// Overridden setValue method - virtual std::string setValue(const std::string & propValue); - /// Set a property value via a DataItem - virtual std::string setValue(const boost::shared_ptr data); - - /// @return the vector of suggested extensions. For use in GUIs showing files. -- const std::set & getExts() const -- { return m_exts; } -+ std::set getExts() const -+ { return std::set(m_exts.begin(), m_exts.end()); } -+ /// @return the vector of ws names. For use by loading algorithm to name multiple workspaces, especially summed workspaces. -+ const std::vector & getWsNames() const -+ { return m_wsNames; } - - // Unhide the PropertyWithValue assignment operator -- using Kernel::ArrayProperty::operator=; -+ using Kernel::PropertyWithValue< std::vector< std::vector< std::string> > >::operator=; -+ -+ /// Return a "flattened" vector with the contents of the given vector of vectors. -+ static std::vector flattenFileNames(const std::vector > & fileNames); - - private: - /// Suggested extensions -- std::set m_exts; -- -- /// Is the file optional? -- bool m_optional; -- -+ std::vector m_exts; -+ /// Workspace names for each of the multiple files (and combinations of files). -+ std::vector m_wsNames; -+ /// Parser used to parse multi-file strings. -+ Kernel::MultiFileNameParser m_parser; - }; - - -diff --git a/Code/Mantid/Framework/API/src/MultipleFileProperty.cpp b/Code/Mantid/Framework/API/src/MultipleFileProperty.cpp -index 661cc94..a87e073 100644 ---- a/Code/Mantid/Framework/API/src/MultipleFileProperty.cpp -+++ b/Code/Mantid/Framework/API/src/MultipleFileProperty.cpp -@@ -1,10 +1,14 @@ - #include "MantidAPI/MultipleFileProperty.h" -+#include "MantidAPI/FileProperty.h" - #include "MantidKernel/System.h" --#include "MantidKernel/FileValidator.h" -+#include "MantidKernel/MultiFileValidator.h" - #include "MantidKernel/Property.h" - #include - #include "MantidAPI/FileFinder.h" - -+#include -+#include -+ - using namespace Mantid::Kernel; - using namespace Mantid::API; - -@@ -12,67 +16,80 @@ namespace Mantid - { - namespace API - { -- -+ // Forward declaration of functor wrapped in anonymous namespace. -+ namespace -+ { -+ class AppendFullFileName; -+ } -+ - /** Constructor - * - * @param name :: The name of the property - * @param exts :: The allowed/suggested extensions - * @param optional :: If ture, the property is optional - */ -- MultipleFileProperty::MultipleFileProperty(const std::string & name, -- const std::vector & exts, bool optional) -- : ArrayProperty(name), -- m_optional(optional) -- { -- m_exts.insert( exts.begin(), exts.end()); -- } -- -+ MultipleFileProperty::MultipleFileProperty( -+ const std::string & name, -+ const std::vector & exts -+ ) : PropertyWithValue > >( -+ name, -+ std::vector >(), -+ new MultiFileValidator(exts), -+ Direction::Input), -+ m_exts(exts), -+ m_wsNames(), -+ m_parser() -+ {} - -- - //---------------------------------------------------------------------------------------------- - /** Destructor - */ -- MultipleFileProperty::~MultipleFileProperty() -- { -- } -+ MultipleFileProperty::~MultipleFileProperty() {} - -- /** Set the value, the list of files, comma-separated -+ /** Set the value, with a comma- and plus-separated string of filenames - * -- * @param propValue :: comma-separated string of filenames -+ * @param propValue :: comma- and plus-separated string of filenames - * @return A string indicating the outcome of the attempt to set the property. An empty string indicates success. - */ - std::string MultipleFileProperty::setValue(const std::string & propValue) - { -- // Separate the files -- std::vector filenames; -- toValue(propValue, filenames); -+ // No empty value is allowed. -+ if( propValue.empty()) -+ return "No file(s) specified."; -+ -+ // Parse the string into the vector of vectors of filenames. -+ m_parser.parse(propValue); -+ std::vector > fileNames = m_parser.getFileNames(); - -- // Empty value is allowed if optional -- if( filenames.empty()) -- { -- if (m_optional) -- return ""; -- else -- return "No file specified."; -- } -+ // Store the suggested wsNames for use later, by the algorithm that declared this property. -+ m_wsNames = m_parser.getWsNames(); - -- std::string outValue; -- for (size_t i=0; i 0) outValue += ","; -- outValue += filename; -+ // Else, for each file name in the vector, change it into a full file name where possible, -+ // then append it onto a comma- and plus-separated string. -+ else -+ { -+ fullFileNames = std::accumulate( -+ fileNames.begin(), fileNames.end(), -+ fullFileNames, appendFullFileName); -+ } -+ // Now re-set the value using the full paths found. -+ return PropertyWithValue > >::setValue(fullFileNames); -+ } -+ catch(const std::exception & e) -+ { -+ return e.what(); - } -- -- // Now re-set the strings using the full paths found -- return ArrayProperty::setValue(outValue); - } - - /** -@@ -83,11 +100,126 @@ namespace API - std::string MultipleFileProperty::setValue(const boost::shared_ptr data ) - { - // Implemented this method for documentation reasons. Just calls base class method. -- return ArrayProperty::setValue(data); -+ return PropertyWithValue > >::setValue(data); -+ } -+ -+ /** -+ * A convenience function for the cases where we dont use the MultiFileProperty to -+ * *add* workspaces - only to list them. It "flattens" the given vector of vectors -+ * into a single vector which is much easier to traverse. For example: -+ * -+ * ((1), (2), (30), (31), (32), (100), (102)) becomes (1, 2, 30, 31, 32, 100, 102) -+ * -+ * Used on a vector of vectors that *has* added filenames, the following behaviour is observed: -+ * -+ * ((1), (2), (30, 31, 32), (100), (102)) becomes (1, 2, 30, 31, 32, 100, 102) -+ * -+ * @param - a vector of vectors, containing all the file names. -+ * @return a single vector containing all the file names. -+ */ -+ std::vector MultipleFileProperty::flattenFileNames( -+ const std::vector > & fileNames) -+ { -+ std::vector flattenedFileNames; -+ -+ std::vector >::const_iterator it = fileNames.begin(); -+ -+ for(; it != fileNames.end(); ++it) -+ { -+ flattenedFileNames.insert( -+ flattenedFileNames.end(), -+ it->begin(), it->end()); -+ } -+ -+ return flattenedFileNames; - } - -+ ////////////////////////////////////////////////////////////////////// -+ // Anonymous -+ ////////////////////////////////////////////////////////////////////// -+ -+ namespace // anonymous -+ { -+ // Functor with overloaded function operator, for use with the "accumulate" STL algorithm. -+ // Has state to store extensions. -+ class AppendFullFileName -+ { -+ public: -+ /** -+ * Constructor to store a reference to extensions locally. -+ */ -+ AppendFullFileName(const std::vector & exts) : -+ m_exts(exts) -+ {} -+ -+ /** Takes in a vector of filenames, tries to find their full path if possible, then cumulatively appends -+ * them to the result string. -+ * @param result :: the cumulative result so far -+ * @param fileNames :: the name to look for, and append to the result -+ * @return the cumulative result, after the filenames have been appended. -+ */ -+ std::string & operator()(std::string & result, const std::vector & fileNames) -+ { -+ // Append nothing if there are no file names to add. -+ if(fileNames.empty()) -+ return result; - -+ if(!result.empty()) -+ result += ","; -+ -+ AppendFullFileName appendFullFileName(m_exts); -+ -+ // Change each file name into a full file name, and append each one onto a plus-separated string. -+ std::string fullFileNames; -+ fullFileNames = std::accumulate( -+ fileNames.begin(), fileNames.end(), -+ fullFileNames, -+ appendFullFileName); // Call other overloaded operator on each filename in vector -+ -+ // Append the file names to result, and return them. -+ result += fullFileNames; -+ return result; -+ } -+ -+ /** Takes in a filename, tries to find it's full path if possible, then cumulatively appends it to a result string. -+ * @param result :: the cumulative result so far -+ * @param fileName :: the name to look for, and append to the result -+ * @return the cumulative result, after the filename has been appended. -+ * @throws std::runtime_error if an individual filename could not be set to the FileProperty object -+ */ -+ std::string & operator()(std::string & result, const std::string & fileName) -+ { -+ // Append nothing if there is no file name to add. -+ if(fileName.empty()) -+ return result; -+ -+ if(!result.empty()) -+ result += "+"; -+ -+ // Initialise a "slave" FileProperty object to do all the work. -+ FileProperty slaveFileProp( -+ "Slave", -+ "", -+ FileProperty::Load, -+ m_exts, -+ Direction::Input); -+ -+ std::string error = slaveFileProp.setValue(fileName); -+ -+ // If an error was returned then we throw it out of the functor, to be -+ // returned by MultiFileProperty.setvalue(...). -+ if(!error.empty()) -+ throw std::runtime_error(error); -+ -+ // Append the file name to result, and return it. -+ result += slaveFileProp(); -+ return result; -+ } -+ -+ private: -+ const std::vector & m_exts; -+ }; -+ } // anonymous namespace - - } // namespace Mantid - } // namespace API -- -diff --git a/Code/Mantid/Framework/API/test/MultipleFilePropertyTest.h b/Code/Mantid/Framework/API/test/MultipleFilePropertyTest.h -index 8a77cb9..1181cc0 100644 ---- a/Code/Mantid/Framework/API/test/MultipleFilePropertyTest.h -+++ b/Code/Mantid/Framework/API/test/MultipleFilePropertyTest.h -@@ -11,45 +11,51 @@ - - using namespace Mantid; - using namespace Mantid::API; --using namespace Mantid::API; - - class MultipleFilePropertyTest : public CxxTest::TestSuite - { - public: - -- void test_empty_value_not_allowed() -+ void assertCorrectSize(const std::vector & sizes, const std::vector > & fileNames) - { -- MultipleFileProperty p("Filename"); -- TS_ASSERT_DIFFERS( p.setValue(""), ""); -- } -+ TS_ASSERT_EQUALS(sizes.size(),fileNames.size()); -+ -+ std::vector::const_iterator i = sizes.begin(); -+ std::vector::const_iterator iEnd = sizes.end(); -+ std::vector >::const_iterator j = fileNames.begin(); -+ std::vector >::const_iterator jEnd = fileNames.end(); - -- void test_empty_value_allowed_ifOptional() -- { -- MultipleFileProperty p("Filename", std::vector(), true); -- TS_ASSERT_EQUALS( p.setValue(""), ""); -- } -+ for(; i != iEnd; ++i, ++j) -+ { -+ size_t a = *i; -+ size_t b = j->size(); -+ TS_ASSERT_EQUALS(a, b); -+ } - -- void test_getExts() -- { -- std::vector exts; -- exts.push_back(".nxs"); -- exts.push_back(".hdf"); -- -- MultipleFileProperty p("Filename", exts); -- TS_ASSERT_EQUALS( p.getExts().size(), 2); -- TS_ASSERT_EQUALS( p.getExts().count(".nxs"), 1); -- TS_ASSERT_EQUALS( p.getExts().count(".hdf"), 1); -+ //TS_ASSERT_EQUALS(1,1); - } -- -+ - void test_setValue() - { -+ // Here we try to load some files, some of them to be added together. We should end up with a vector of vectors as follows: -+ // -+ // | [dir]MUSR00015189.nxs | [dir]MUSR00015190.nxs | [dir]MUSR00015189.nxs | [dir]MUSR00015191.nxs | -+ // | [dir]MUSR00015190.nxs | -+ // | [dir]MUSR00015191.nxs | -+ - MultipleFileProperty p("Filename"); -- p.setValue("REF_L_32035.nxs, CSP78173.raw"); -- std::vector filenames = p(); -- TS_ASSERT_EQUALS( filenames.size(), 2); -- TSM_ASSERT( "Files with no path are found using ConfigService paths", Poco::Path(filenames[0]).isAbsolute() ); -- TSM_ASSERT( "Files with no path are found using ConfigService paths", Poco::Path(filenames[1]).isAbsolute() ); -+ p.setValue("MUSR15189:15190,15189-15191,15191.nxs"); -+ std::vector sizes; -+ sizes.push_back(1); -+ sizes.push_back(1); -+ sizes.push_back(3); -+ sizes.push_back(1); -+ std::vector > fileNames = p(); -+ std::vector wsNames = p.getWsNames(); -+ -+ TS_ASSERT_EQUALS(wsNames.size(), fileNames.size()); - -+ assertCorrectSize(sizes, fileNames); - } - - -diff --git a/Code/Mantid/Framework/DataHandling/inc/MantidDataHandling/Load.h b/Code/Mantid/Framework/DataHandling/inc/MantidDataHandling/Load.h -index 60b89e6..e6ef60a 100644 ---- a/Code/Mantid/Framework/DataHandling/inc/MantidDataHandling/Load.h -+++ b/Code/Mantid/Framework/DataHandling/inc/MantidDataHandling/Load.h -@@ -72,6 +72,10 @@ namespace Mantid - void init(); - /// Execute - void exec(); -+ -+ void loadSingleFile(); -+ void loadMultipleFiles(); -+ - /// Overrides the cancel() method to call m_loader->cancel() - void cancel()const; - /// Create the concrete instance use for the actual loading. -@@ -85,8 +89,16 @@ namespace Mantid - /// Retrieve a pointer to the output workspace from the sub algorithm - API::Workspace_sptr getOutputWorkspace(const std::string & propName, - const API::IDataFileChecker_sptr loader) const; -- - -+ //API::Workspace_sptr loadFileToWs(const std::string & fileName, const std::string & wsName); -+ API::Workspace_sptr loadFileToHiddenWs(const std::string & fileName, const std::string & wsName); -+ //API::Workspace_sptr plusWs(API::Workspace_sptr ws1, API::Workspace_sptr ws2, const std::string & outputWsName); -+ API::Workspace_sptr plusHiddenWs(API::Workspace_sptr ws1, API::Workspace_sptr ws2, const std::string & outputWsName); -+ void deleteWs(const std::string & wsName); -+ //void renameWs(const std::string & oldName, const std::string & newName); -+ void renameHiddenWs(const std::string & oldName, const std::string & newName); -+ void unhideWs(const std::string & wsName); -+ - private: - /// The base properties - std::set m_baseProps; -diff --git a/Code/Mantid/Framework/DataHandling/src/Load.cpp b/Code/Mantid/Framework/DataHandling/src/Load.cpp -index 0466c96..5aec345 100644 ---- a/Code/Mantid/Framework/DataHandling/src/Load.cpp -+++ b/Code/Mantid/Framework/DataHandling/src/Load.cpp -@@ -33,7 +33,7 @@ Load('event_ws', Filename='INSTR_1000_event.nxs',Precount=True) - // Includes - //---------------------------------------------------------------------- - #include "MantidDataHandling/Load.h" --#include "MantidAPI/FileProperty.h" -+#include "MantidAPI/MultipleFileProperty.h" - #include "MantidAPI/IEventWorkspace.h" - #include "MantidAPI/IWorkspaceProperty.h" - #include "MantidKernel/ArrayProperty.h" -@@ -43,9 +43,27 @@ Load('event_ws', Filename='INSTR_1000_event.nxs',Precount=True) - - #include - #include -+#include -+#include -+#include - #include "MantidAPI/IMDEventWorkspace.h" - #include - -+ -+namespace -+{ -+ bool isSingleFile(const std::vector > & fileNames) -+ { -+ if(fileNames.size() == 1) -+ { -+ std::vector>::const_iterator first = fileNames.begin(); -+ if(first->size() == 1) -+ return true; -+ } -+ return false; -+ } -+} -+ - namespace Mantid - { - namespace DataHandling -@@ -88,9 +106,15 @@ namespace Mantid - std::transform(name.begin(),name.end(),NAME.begin(),toupper); - if( NAME == "FILENAME" ) - { -- // Get back full path before passing to getFileLoader method. -- IDataFileChecker_sptr loader = getFileLoader(getPropertyValue(name)); -- if( loader ) declareLoaderProperties(loader); -+ // Get back full path before passing to getFileLoader method, and also -+ // find out whether this is a multi file load. -+ std::vector > fileNames = getProperty("Filename"); -+ // If it's a single file load, then it's fine to change loader. -+ if(isSingleFile(fileNames)) -+ { -+ IDataFileChecker_sptr loader = getFileLoader(getPropertyValue(name)); -+ if( loader ) declareLoaderProperties(loader); -+ } - } - } - -@@ -249,9 +273,10 @@ namespace Mantid - exts.push_back(".grp"); - exts.push_back(".nxspe"); - -- 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 MultipleFileProperty("Filename", exts), -+ "The name of the file(s) to read, including the full or relative\n" -+ "path. (N.B. case sensitive if running on Linux). Multiple runs\n" -+ "can be loaded and added together, e.g. INST10,11+12,13.ext"); - declareProperty(new WorkspaceProperty("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."); -@@ -272,6 +297,20 @@ namespace Mantid - */ - void Load::exec() - { -+ std::vector > fileNames = getProperty("Filename"); -+ -+ if(isSingleFile(fileNames)) -+ { -+ loadSingleFile(); -+ } -+ else -+ { -+ loadMultipleFiles(); -+ } -+ } -+ -+ void Load::loadSingleFile() -+ { - std::string loaderName = getPropertyValue("LoaderName"); - //IDataFileChecker_sptr loader; - if( loaderName.empty() ) -@@ -308,6 +347,130 @@ namespace Mantid - // Set the workspace. Deals with possible multiple periods - setOutputWorkspace(m_loader); - } -+ void Load::loadMultipleFiles() -+ { -+ MultipleFileProperty * multiFileProp = dynamic_cast(getPointerToProperty("Filename")); -+ -+ const std::vector > values = getProperty("Filename"); -+ const std::vector wsNames = multiFileProp->getWsNames(); -+ std::string outputWsName = getProperty("OutputWorkspace"); -+ -+ std::vector loadedWsNames; -+ -+ std::vector >::const_iterator values_it = values.begin(); -+ std::vector >::const_iterator values_end = values.end(); -+ -+ std::vector::const_iterator wsNames_it = wsNames.begin(); -+ std::vector::const_iterator wsNames_end = wsNames.end(); -+ -+ // Cycle through the fileNames and wsNames. -+ for(; values_it != values_end; ++values_it, ++wsNames_it) -+ { -+ std::vector fileNames = *values_it; -+ std::string wsName = *wsNames_it; -+ -+ // If there is only one filename, then just load it to the given wsName. -+ if(fileNames.size() == 1) -+ { -+ std::set adsContents1 = AnalysisDataService::Instance().getObjectNames(); -+ -+ loadFileToHiddenWs(fileNames.at(0), wsName); -+ -+ loadedWsNames.push_back("__" + wsName); -+ -+ std::set adsContents2 = AnalysisDataService::Instance().getObjectNames(); -+ } -+ // Else there is more than one filename. Load them all, sum them, and rename the -+ // result to the given wsName. -+ else -+ { -+ // Load all files and place the resulting workspaces in a vector. -+ std::vector loadedWs; -+ std::vector::const_iterator vIt = fileNames.begin(); -+ std::vector::const_iterator vEnd = fileNames.end(); -+ -+ std::set adsContents3 = AnalysisDataService::Instance().getObjectNames(); -+ -+ for(; vIt != vEnd; ++vIt) -+ { -+ Workspace_sptr ws = loadFileToHiddenWs(*vIt, (*vIt) + "_temp"); -+ -+ loadedWs.push_back(ws); -+ } -+ -+ std::set adsContents4 = AnalysisDataService::Instance().getObjectNames(); -+ -+ // Add all workspaces together, sticking the result in sum. -+ Workspace_sptr sum; -+ for( -+ size_t i = 1; // Start at second workspace in list. -+ i < loadedWs.size(); -+ i++) -+ { -+ Workspace_sptr firstWsToAdd; -+ // If there have been no workspaces added yet, then the first workspace to add -+ // is the first workspace in the list. -+ if(sum == Workspace_sptr()) -+ firstWsToAdd = loadedWs.at(i-1); -+ // Else the first workspace to add is "sum" itself. -+ else -+ firstWsToAdd = sum; -+ -+ Workspace_sptr secondWsToAdd = loadedWs.at(i); -+ -+ sum = plusHiddenWs(firstWsToAdd, secondWsToAdd, wsName); -+ } -+ -+ std::set adsContents5 = AnalysisDataService::Instance().getObjectNames(); -+ -+ //AnalysisDataService::Instance().add(wsName, sum); -+ -+ std::set adsContents6 = AnalysisDataService::Instance().getObjectNames(); -+ -+ // Delete all of the temporarily loaded workspaces except the first one, so that we are left only -+ // with sum at this point. -+ for(size_t i = 1; i < fileNames.size(); i++) -+ { -+ deleteWs("__" + fileNames.at(i) + "_temp"); -+ } -+ -+ // Rename the sum -+ renameHiddenWs(sum->name(), "__" + wsName); -+ -+ loadedWsNames.push_back("__" + wsName); -+ -+ std::set adsContents7 = AnalysisDataService::Instance().getObjectNames(); -+ } -+ } -+ -+ // If we only have one loaded ws, set it as the output. -+ if(loadedWsNames.size() == 1) -+ { -+ std::set adsContents8 = AnalysisDataService::Instance().getObjectNames(); -+ -+ renameHiddenWs(loadedWsNames.at(0), outputWsName); -+ -+ std::set adsContents9 = AnalysisDataService::Instance().getObjectNames(); -+ -+ setProperty("OutputWorkspace", AnalysisDataService::Instance().retrieve(outputWsName.c_str())); -+ -+ std::set adsContents10 = AnalysisDataService::Instance().getObjectNames(); -+ } -+ // Else we have multiple loaded workspaces - group them and set the group as output. -+ else -+ { -+ Mantid::API::IAlgorithm_sptr groupingAlg = -+ Mantid::API::AlgorithmManager::Instance().create("GroupWorkspaces", 1); -+ -+ groupingAlg->setProperty("InputWorkspaces",loadedWsNames); -+ groupingAlg->setProperty("OutputWorkspace",outputWsName.c_str()); -+ groupingAlg->execute(); -+ -+ unhideWs(outputWsName); -+ -+ setProperty("OutputWorkspace", AnalysisDataService::Instance().retrieve(outputWsName.c_str())); -+ } -+ } - - /** - * Create the concrete instance use for the actual loading. -@@ -449,8 +612,8 @@ namespace Mantid - } - - /* -- * Overrides the default cancel() method. Calls cancel() on the actual loader. -- */ -+ * Overrides the default cancel() method. Calls cancel() on the actual loader. -+ */ - void Load::cancel()const - { - if (m_loader) -@@ -459,5 +622,221 @@ namespace Mantid - } - } - -+ /*API::Workspace_sptr Load::loadFileToWs( -+ const std::string & fileName, -+ const std::string & wsName) -+ { -+ std::set adsContents1 = AnalysisDataService::Instance().getObjectNames(); -+ -+ Mantid::API::IAlgorithm_sptr loadAlg = createSubAlgorithm("Load", 1); -+ -+ loadAlg->setPropertyValue("Filename",fileName); -+ loadAlg->setPropertyValue("OutputWorkspace",wsName); -+ loadAlg->executeAsSubAlg(); -+ -+ std::set adsContents2 = AnalysisDataService::Instance().getObjectNames(); -+ -+ return loadAlg->getProperty("OutputWorkspace"); -+ }*/ -+ -+ API::Workspace_sptr Load::loadFileToHiddenWs( -+ const std::string & fileName, -+ const std::string & wsName) -+ { -+ std::set adsContents1 = AnalysisDataService::Instance().getObjectNames(); -+ -+ Mantid::API::IAlgorithm_sptr loadAlg = createSubAlgorithm("Load", 1); -+ // Here, as a workaround for groupworkspaces who's members have names but no -+ // accompanying entries in the ADS, we set the sub algo to not be a child ... -+ loadAlg->setChild(false); -+ // ... and now, so that the the workspaces dont appear in the window, we prefix -+ // all workspace names with "__". -+ loadAlg->setPropertyValue("Filename",fileName); -+ loadAlg->setPropertyValue("OutputWorkspace","__" + wsName); -+ loadAlg->executeAsSubAlg(); -+ -+ std::set adsContents2 = AnalysisDataService::Instance().getObjectNames(); -+ -+ return AnalysisDataService::Instance().retrieve("__" + wsName);//loadAlg->getProperty("OutputWorkspace"); -+ } -+ -+ //API::Workspace_sptr Load::plusWs( -+ // Workspace_sptr ws1, -+ // Workspace_sptr ws2, -+ // const std::string & outputWsName) -+ //{ -+ // std::set adsContents1 = AnalysisDataService::Instance().getObjectNames(); -+ // -+ // Mantid::API::IAlgorithm_sptr plusAlg = createSubAlgorithm("Plus", 1); -+ // -+ // plusAlg->setProperty("LHSWorkspace", ws1); -+ // plusAlg->setProperty("RHSWorkspace", ws2); -+ // //plusAlg->setPropertyValue("OutputWorkspace", outputWsName); -+ // plusAlg->setProperty("OutputWorkspace", ws1); -+ // plusAlg->executeAsSubAlg(); -+ -+ // std::set adsContents2 = AnalysisDataService::Instance().getObjectNames(); -+ -+ // return ws1;//plusAlg->getProperty("OutputWorkspace"); -+ //} -+ -+ API::Workspace_sptr Load::plusHiddenWs( -+ Workspace_sptr ws1, -+ Workspace_sptr ws2, -+ const std::string & outputWsName) -+ { -+ std::set adsContents1 = AnalysisDataService::Instance().getObjectNames(); -+ -+ Mantid::API::IAlgorithm_sptr plusAlg = createSubAlgorithm("Plus", 1); -+ //plusAlg->setChild(false); -+ plusAlg->setPropertyValue("LHSWorkspace", ws1->name()); -+ plusAlg->setPropertyValue("RHSWorkspace", ws2->name()); -+ //plusAlg->setPropertyValue("OutputWorkspace", outputWsName); -+ plusAlg->setPropertyValue("OutputWorkspace", ws1->name()); -+ plusAlg->executeAsSubAlg(); -+ -+ std::set adsContents2 = AnalysisDataService::Instance().getObjectNames(); -+ -+ return ws1;//plusAlg->getProperty("OutputWorkspace"); -+ } -+ -+ //void Load::renameWs( -+ // const std::string & oldName, -+ // const std::string & newName) -+ //{ -+ // if(oldName == newName) -+ // return; -+ -+ // std::set adsContents1 = AnalysisDataService::Instance().getObjectNames(); -+ // -+ // Mantid::API::IAlgorithm_sptr renameAlg = createSubAlgorithm("RenameWorkspace", 1); -+ // //Mantid::API::AlgorithmManager::Instance().create("RenameWorkspace", 1); -+ -+ // renameAlg->setPropertyValue("InputWorkspace", oldName); -+ // renameAlg->setPropertyValue("OutputWorkspace", newName); -+ // renameAlg->executeAsSubAlg(); -+ -+ // AnalysisDataService::Instance().add(newName, renameAlg->getProperty("OutputWorkspace")); -+ -+ // std::set adsContents2 = AnalysisDataService::Instance().getObjectNames(); -+ //} -+ -+ void Load::renameHiddenWs( -+ const std::string & oldName, -+ const std::string & newName) -+ { -+ if(oldName == newName) -+ return; -+ -+ std::set adsContents1 = AnalysisDataService::Instance().getObjectNames(); -+ -+ Mantid::API::IAlgorithm_sptr renameAlg = createSubAlgorithm("RenameWorkspace", 1); -+ //Mantid::API::AlgorithmManager::Instance().create("RenameWorkspace", 1); -+ renameAlg->setChild(false); -+ renameAlg->setPropertyValue("InputWorkspace", oldName); -+ renameAlg->setPropertyValue("OutputWorkspace", newName); -+ renameAlg->executeAsSubAlg(); -+ -+ //AnalysisDataService::Instance().add(newName, renameAlg->getProperty("OutputWorkspace")); -+ -+ std::set adsContents2 = AnalysisDataService::Instance().getObjectNames(); -+ } -+ -+ //void Load::deleteWs(const std::string & wsName) -+ //{ -+ // Mantid::API::IAlgorithm_sptr deleteAlg = -+ // Mantid::API::AlgorithmManager::Instance().create("DeleteWorkspace", 1); -+ -+ // std::set adsContents1 = AnalysisDataService::Instance().getObjectNames(); -+ -+ // Workspace_sptr ws = AnalysisDataService::Instance().retrieve(wsName); -+ // if(WorkspaceGroup_sptr wsGrpSptr = -+ // boost::dynamic_pointer_cast(ws)) -+ // { -+ // std::vector childWsNames = wsGrpSptr->getNames(); -+ // std::vector::iterator vIt = childWsNames.begin(); -+ // std::vector::iterator vEnd = childWsNames.end(); -+ -+ // for(; vIt != vEnd; ++vIt) -+ // { -+ // // Call this function recursively, to delete each child workspace. -+ // deleteWs(*vIt); -+ // } -+ // } -+ // else -+ // { -+ // deleteAlg->setPropertyValue("Workspace", wsName); -+ // deleteAlg->execute(); -+ // } -+ -+ // std::set adsContents2 = AnalysisDataService::Instance().getObjectNames(); -+ //} -+ -+ void Load::deleteWs(const std::string & wsName) -+ { -+ std::set adsContents1 = AnalysisDataService::Instance().getObjectNames(); -+ -+ Workspace_sptr ws = AnalysisDataService::Instance().retrieve(wsName); -+ if(WorkspaceGroup_sptr wsGrpSptr = -+ boost::dynamic_pointer_cast(ws)) -+ { -+ std::vector childWsNames = wsGrpSptr->getNames(); -+ std::vector::iterator vIt = childWsNames.begin(); -+ std::vector::iterator vEnd = childWsNames.end(); -+ -+ for(; vIt != vEnd; ++vIt) -+ { -+ // Call this function recursively, to delete each child workspace. -+ deleteWs(*vIt); -+ } -+ } -+ else -+ { -+ Mantid::API::IAlgorithm_sptr deleteAlg = createSubAlgorithm("DeleteWorkspace", 1); -+ -+ deleteAlg->setPropertyValue("Workspace", wsName); -+ deleteAlg->execute(); -+ } -+ -+ std::set adsContents2 = AnalysisDataService::Instance().getObjectNames(); -+ } -+ -+ void Load::unhideWs(const std::string & wsName) -+ { -+ std::set adsContents1 = AnalysisDataService::Instance().getObjectNames(); -+ -+ Workspace_sptr ws = AnalysisDataService::Instance().retrieve(wsName); -+ if(WorkspaceGroup_sptr wsGrpSptr = -+ boost::dynamic_pointer_cast(ws)) -+ { -+ std::vector childWsNames = wsGrpSptr->getNames(); -+ std::vector::iterator vIt = childWsNames.begin(); -+ std::vector::iterator vEnd = childWsNames.end(); -+ -+ for(; vIt != vEnd; ++vIt) -+ { -+ // Call this function recursively, to unhide each child workspace. -+ unhideWs(*vIt); -+ } -+ } -+ else -+ { -+ if(boost::starts_with(wsName, "__")) -+ { -+ /*Mantid::API::IAlgorithm_sptr renameAlg = -+ Mantid::API::AlgorithmManager::Instance().create("RenameWorkspace", 1); -+ -+ std::set adsContents1 = AnalysisDataService::Instance().getObjectNames(); -+ renameAlg->setPropertyValue("InputWorkspace", wsName); -+ renameAlg->setPropertyValue("OutputWorkspace", wsName.substr(2,wsName.size() - 2)); -+ renameAlg->execute();*/ -+ std::string newName = wsName.substr(2, (wsName.size() - 2)); -+ renameHiddenWs(wsName, newName); -+ } -+ } -+ -+ std::set adsContents2 = AnalysisDataService::Instance().getObjectNames(); -+ } -+ - } // namespace DataHandling - } // namespace Mantid -diff --git a/Code/Mantid/Framework/DataHandling/test/LoadTest.h b/Code/Mantid/Framework/DataHandling/test/LoadTest.h -index dc01f64..b09025d 100644 ---- a/Code/Mantid/Framework/DataHandling/test/LoadTest.h -+++ b/Code/Mantid/Framework/DataHandling/test/LoadTest.h -@@ -13,6 +13,20 @@ using namespace Mantid::API; - using namespace Mantid::DataObjects; - using namespace Mantid::DataHandling; - -+namespace -+{ -+ void removeGroupFromADS(WorkspaceGroup_sptr group) -+ { -+ const std::vector wsNames = group->getNames(); -+ std::vector::const_iterator it = wsNames.begin(); -+ AnalysisDataService::Instance().remove(group->name()); -+ for(; it != wsNames.end(); ++it) -+ { -+ AnalysisDataService::Instance().remove(*it); -+ } -+ } -+} -+ - class LoadTest : public CxxTest::TestSuite - { - public: -@@ -327,6 +341,143 @@ public: - TS_ASSERT(ws); - AnalysisDataService::Instance().remove("LoadTest_Output"); - } -+ -+ -+ -+ void testList() -+ { -+ Load loader; -+ loader.initialize(); -+ loader.setPropertyValue("Filename", "MUSR15189,15190,15191.nxs"); -+ loader.setPropertyValue("OutputWorkspace","LoadTest_Output"); -+ TS_ASSERT_THROWS_NOTHING(loader.execute()); -+ WorkspaceGroup_sptr output = boost::dynamic_pointer_cast(AnalysisDataService::Instance().retrieve("LoadTest_Output")); -+ TS_ASSERT(output); -+ TS_ASSERT_EQUALS(output->getNumberOfEntries(),6); -+ MatrixWorkspace_sptr ws1 = boost::dynamic_pointer_cast(AnalysisDataService::Instance().retrieve("15189_1")); -+ TS_ASSERT(ws1); -+ MatrixWorkspace_sptr ws2 = boost::dynamic_pointer_cast(AnalysisDataService::Instance().retrieve("15189_2")); -+ TS_ASSERT(ws2); -+ MatrixWorkspace_sptr ws3 = boost::dynamic_pointer_cast(AnalysisDataService::Instance().retrieve("15190_1")); -+ TS_ASSERT(ws3); -+ MatrixWorkspace_sptr ws4 = boost::dynamic_pointer_cast(AnalysisDataService::Instance().retrieve("15190_2")); -+ TS_ASSERT(ws4); -+ MatrixWorkspace_sptr ws5 = boost::dynamic_pointer_cast(AnalysisDataService::Instance().retrieve("15191_1")); -+ TS_ASSERT(ws5); -+ MatrixWorkspace_sptr ws6 = boost::dynamic_pointer_cast(AnalysisDataService::Instance().retrieve("15191_2")); -+ TS_ASSERT(ws6); -+ removeGroupFromADS(output); -+ -+ std::set adsContents = AnalysisDataService::Instance().getObjectNames(); -+ } -+ -+ void testPlus() -+ { -+ Load loader; -+ loader.initialize(); -+ loader.setPropertyValue("Filename", "MUSR15189+15190.nxs"); -+ loader.setPropertyValue("OutputWorkspace","LoadTest_Output"); -+ TS_ASSERT_THROWS_NOTHING(loader.execute()); -+ -+ std::set adsContents = AnalysisDataService::Instance().getObjectNames(); -+ -+ WorkspaceGroup_sptr output = boost::dynamic_pointer_cast(AnalysisDataService::Instance().retrieve("LoadTest_Output")); -+ TS_ASSERT(output); -+ MatrixWorkspace_sptr ws1 = boost::dynamic_pointer_cast(AnalysisDataService::Instance().retrieve("LoadTest_Output_1")); -+ TS_ASSERT(ws1); -+ MatrixWorkspace_sptr ws2 = boost::dynamic_pointer_cast(AnalysisDataService::Instance().retrieve("LoadTest_Output_2")); -+ removeGroupFromADS(output); -+ } -+ -+ void testRange() -+ { -+ Load loader; -+ loader.initialize(); -+ loader.setPropertyValue("Filename", "MUSR15189:15192.nxs"); -+ loader.setPropertyValue("OutputWorkspace","LoadTest_Output"); -+ TS_ASSERT_THROWS_NOTHING(loader.execute()); -+ WorkspaceGroup_sptr output = boost::dynamic_pointer_cast(AnalysisDataService::Instance().retrieve("LoadTest_Output")); -+ TS_ASSERT(output); -+ TS_ASSERT_EQUALS(output->getNumberOfEntries(),8); -+ MatrixWorkspace_sptr ws1 = boost::dynamic_pointer_cast(AnalysisDataService::Instance().retrieve("15189_1")); -+ TS_ASSERT(ws1); -+ MatrixWorkspace_sptr ws2 = boost::dynamic_pointer_cast(AnalysisDataService::Instance().retrieve("15189_2")); -+ TS_ASSERT(ws2); -+ MatrixWorkspace_sptr ws3 = boost::dynamic_pointer_cast(AnalysisDataService::Instance().retrieve("15190_1")); -+ TS_ASSERT(ws3); -+ MatrixWorkspace_sptr ws4 = boost::dynamic_pointer_cast(AnalysisDataService::Instance().retrieve("15190_2")); -+ TS_ASSERT(ws4); -+ MatrixWorkspace_sptr ws5 = boost::dynamic_pointer_cast(AnalysisDataService::Instance().retrieve("15191_1")); -+ TS_ASSERT(ws5); -+ MatrixWorkspace_sptr ws6 = boost::dynamic_pointer_cast(AnalysisDataService::Instance().retrieve("15191_2")); -+ TS_ASSERT(ws6); -+ MatrixWorkspace_sptr ws7 = boost::dynamic_pointer_cast(AnalysisDataService::Instance().retrieve("15192_1")); -+ TS_ASSERT(ws7); -+ MatrixWorkspace_sptr ws8 = boost::dynamic_pointer_cast(AnalysisDataService::Instance().retrieve("15192_2")); -+ TS_ASSERT(ws8); -+ removeGroupFromADS(output); -+ } -+ -+ void testSteppedRange() -+ { -+ Load loader; -+ loader.initialize(); -+ loader.setPropertyValue("Filename", "MUSR15189:15192:2.nxs"); -+ loader.setPropertyValue("OutputWorkspace","LoadTest_Output"); -+ TS_ASSERT_THROWS_NOTHING(loader.execute()); -+ WorkspaceGroup_sptr output = boost::dynamic_pointer_cast(AnalysisDataService::Instance().retrieve("LoadTest_Output")); -+ TS_ASSERT(output); -+ TS_ASSERT_EQUALS(output->getNumberOfEntries(),4); -+ MatrixWorkspace_sptr ws1 = boost::dynamic_pointer_cast(AnalysisDataService::Instance().retrieve("15189_1")); -+ TS_ASSERT(ws1); -+ MatrixWorkspace_sptr ws2 = boost::dynamic_pointer_cast(AnalysisDataService::Instance().retrieve("15189_2")); -+ TS_ASSERT(ws2); -+ MatrixWorkspace_sptr ws3 = boost::dynamic_pointer_cast(AnalysisDataService::Instance().retrieve("15191_1")); -+ TS_ASSERT(ws3); -+ MatrixWorkspace_sptr ws4 = boost::dynamic_pointer_cast(AnalysisDataService::Instance().retrieve("15191_2")); -+ TS_ASSERT(ws4); -+ removeGroupFromADS(output); -+ } -+ -+ void testAddedRange() -+ { -+ Load loader; -+ loader.initialize(); -+ loader.setPropertyValue("Filename", "MUSR15189-15192.nxs"); -+ loader.setPropertyValue("OutputWorkspace","LoadTest_Output"); -+ TS_ASSERT_THROWS_NOTHING(loader.execute()); -+ -+ std::set adsContents = AnalysisDataService::Instance().getObjectNames(); -+ -+ WorkspaceGroup_sptr output = boost::dynamic_pointer_cast(AnalysisDataService::Instance().retrieve("LoadTest_Output")); -+ TS_ASSERT(output); -+ TS_ASSERT_EQUALS(output->getNumberOfEntries(),2); -+ MatrixWorkspace_sptr ws1 = boost::dynamic_pointer_cast(AnalysisDataService::Instance().retrieve("LoadTest_Output_1")); -+ TS_ASSERT(ws1); -+ MatrixWorkspace_sptr ws2 = boost::dynamic_pointer_cast(AnalysisDataService::Instance().retrieve("LoadTest_Output_2")); -+ TS_ASSERT(ws2); -+ removeGroupFromADS(output); -+ } -+ -+ void testAddedSteppedRange() -+ { -+ Load loader; -+ loader.initialize(); -+ loader.setPropertyValue("Filename", "MUSR15189-15192:2.nxs"); -+ loader.setPropertyValue("OutputWorkspace","LoadTest_Output"); -+ TS_ASSERT_THROWS_NOTHING(loader.execute()); -+ -+ std::set adsContents = AnalysisDataService::Instance().getObjectNames(); -+ -+ WorkspaceGroup_sptr output = boost::dynamic_pointer_cast(AnalysisDataService::Instance().retrieve("LoadTest_Output")); -+ TS_ASSERT(output); -+ TS_ASSERT_EQUALS(output->getNumberOfEntries(),2); -+ MatrixWorkspace_sptr ws1 = boost::dynamic_pointer_cast(AnalysisDataService::Instance().retrieve("LoadTest_Output_1")); -+ TS_ASSERT(ws1); -+ MatrixWorkspace_sptr ws2 = boost::dynamic_pointer_cast(AnalysisDataService::Instance().retrieve("LoadTest_Output_2")); -+ TS_ASSERT(ws2); -+ removeGroupFromADS(output); -+ } - }; - - #endif /*LOADTEST_H_*/ -diff --git a/Code/Mantid/Framework/Kernel/inc/MantidKernel/IPropertyManager.h b/Code/Mantid/Framework/Kernel/inc/MantidKernel/IPropertyManager.h -index 78ceb1a..9f0ee49 100644 ---- a/Code/Mantid/Framework/Kernel/inc/MantidKernel/IPropertyManager.h -+++ b/Code/Mantid/Framework/Kernel/inc/MantidKernel/IPropertyManager.h -@@ -306,10 +306,13 @@ protected: - operator std::string (); - /// explicit specialization for Property*() - operator Property* (); -- -+ - /// explicit specialization for std::vector - template - operator std::vector () { return pm.getValue >(prop);} -+ /// explicit specialization for std::vector -+ template -+ operator std::vector > () { return pm.getValue > >(prop);} - /// explicit specialization for boost::shared_ptr - template - operator boost::shared_ptr () { return pm.getValue >(prop); } -diff --git a/Code/Mantid/Framework/Kernel/inc/MantidKernel/MultiFileNameParser.h b/Code/Mantid/Framework/Kernel/inc/MantidKernel/MultiFileNameParser.h -index cf3bedc..d01ffd1 100644 ---- a/Code/Mantid/Framework/Kernel/inc/MantidKernel/MultiFileNameParser.h -+++ b/Code/Mantid/Framework/Kernel/inc/MantidKernel/MultiFileNameParser.h -@@ -53,71 +53,67 @@ namespace Kernel - - /** - This class takes a string representing multiple files and parses it into -- a "VectOfStrings2StringMap" (std::map, std::string>) -- which contains a map of vectors of fileNames to workspace name. -- -- Filenames found together in the same vector are to be added - the workspace -- name reflects this. -+ a vector of vectors of file names. Filenames to be added are placed in the -+ same sub vectors. - -- The string to parse will be of the format [dir][inst][runs][ext], where: -+ The string to parse should be of the format [dir][inst][runs][ext], where: - - [dir] (Optional) = The OS-specific file directory, e.g. "c:\data\" - [inst] (Required) = The instrument name including any underscores, e.g. "IRS" or "PG3_". - [runs] (Required) = The run numbers, e.g. "0102, 0110-0115, 0120, 0130:0140:2" - [ext] (Optional) = The file extension, e.g. ".raw" - */ -- class MANTID_KERNEL_DLL MultiFileNameParser -+ class MANTID_KERNEL_DLL Parser - { - public: - /// Constructor -- MultiFileNameParser(); -+ Parser(); - /// Destructor -- ~MultiFileNameParser(); -- -- /// Parse the multiFileNameString. Returns error if failed, "" if successful. -- std::string parse(const std::string & multiFileName); -- -- /// Returns the result of a call to parse. -- //std::map, std::string> getFileNamesToWsNameMap() const; -- -- /// Returns a vector of all the workspace names. -- std::vector getWsNames() const; -- -- /// Returns a vector of vectors of all the filenames. -- std::vector > getFileNames() const; -- -- static std::string getPathDir(const std::string & path); -+ ~Parser(); -+ -+ /// Parse the given multiFileNameString. -+ void parse(const std::string & multiFileName); -+ -+ /// Return the vector of vectors of parsed file names. -+ std::vector > runs() {return m_runs;} -+ /// Return the vector of vectors of parsed file names. -+ std::vector > fileNames() {return m_fileNames;} -+ /// Return the parsed directory string. -+ std::string dirString() {return m_dirString;} -+ /// Return the parsed instrument string. -+ std::string instString() {return m_instString;} -+ /// Return the parsed underscore string. -+ std::string underscoreString() {return m_underscoreString;} -+ /// Return the parsed run string. -+ std::string runString() {return m_runString;} -+ /// Return the parsed extension string. -+ std::string extString() {return m_extString;} - - private: -- /// Clears all member variables. -+ /// Clear all member variables. - void clear(); -- -- /// Does an initial split of the multiFileName string. -+ /// Split the string to parse into its component parts. - void split(); -- /// Appends run numbers and corresponding wsNames to final map. -- void populateMap(const std::pair, std::string> & pair); -- /// Creates a file name from the given run and currently parsed info -- /// about file type, etc. -- std::string createFileName(unsigned int run); -- /// -- std::string createZeroPaddedFileName(unsigned int run); -- /// Zero pads the run number used in a file name to required length. -- static std::string pad(std::string run, int count); -- /// Returns the part of the given string that matches the given regex. -- static std::string getMatchingString(const std::string & regexString, const std::string & toParse); -- /// Generates a wsName from the given vector of runs. -- static std::string getWorkspaceName(const std::vector runs); -- -+ /// Generate file names for the given runs. -+ std::vector generateFileNamesFromRuns(const std::vector & runs); -+ /// Generate a file name for the given run. -+ std::string generateFileNameFromRun(unsigned int run); -+ -+ /// A vector of vectors of the parsed runs. -+ std::vector > m_runs; -+ /// A vector of vectors of the parsed file names. -+ std::vector > m_fileNames; -+ /// The given string to parse. -+ std::string m_multiFileName; -+ /// The various sections of the given string to parse. -+ std::string m_dirString, m_instString, m_underscoreString, m_runString, m_extString; -+ /// The instrument-specific run zero padding value. - int m_zeroPadding; -+ }; - -- std::string m_multiFileName; -- std::string m_dir, m_inst, m_runs, m_ext; -+ } // namespace MultiFileNameParsing - -- std::map, std::string> m_fileNamesToWsNameMap; -- UserStringParser m_parser; -- }; -+} // namespace Kernel -+} // namespace Mantid - -- } --} --} --#endif -\ No newline at end of file -+#endif -diff --git a/Code/Mantid/Framework/Kernel/inc/MantidKernel/PropertyWithValue.h b/Code/Mantid/Framework/Kernel/inc/MantidKernel/PropertyWithValue.h -index feb4d3d..e90e62d 100644 ---- a/Code/Mantid/Framework/Kernel/inc/MantidKernel/PropertyWithValue.h -+++ b/Code/Mantid/Framework/Kernel/inc/MantidKernel/PropertyWithValue.h -@@ -88,6 +88,28 @@ std::string toString(const std::vector& value) - return result.str(); - } - -+/// Specialisation for a property of type std::vector. -+template -+std::string toString(const std::vector >& value) -+{ -+ std::stringstream result; -+ std::size_t vsize = value.size(); -+ for (std::size_t i = 0; i < vsize; ++i) -+ { -+ std::size_t innervsize = value[i].size(); -+ for (std::size_t j = 0; j < innervsize; ++j) -+ { -+ result << value[i][j]; -+ if (j + 1 != innervsize) -+ result << "+"; -+ } -+ -+ if (i + 1 != vsize) -+ result << ","; -+ } -+ return result.str(); -+} -+ - // ------------- Convert strings to values - template - inline void appendValue(const std::string& strvalue, std::vector& value) -@@ -140,6 +162,28 @@ void toValue(const std::string& strvalue, std::vector& value) - } - } - -+template -+void toValue(const std::string& strvalue, std::vector >& value) -+{ -+ // Split up comma-separated properties -+ typedef Poco::StringTokenizer tokenizer; -+ tokenizer tokens(strvalue, ",", tokenizer::TOK_IGNORE_EMPTY | tokenizer::TOK_TRIM); -+ -+ value.clear(); -+ value.reserve(tokens.count()); -+ -+ for (tokenizer::Iterator oIt = tokens.begin(); oIt != tokens.end(); ++oIt) -+ { -+ tokenizer values(*oIt, "+", tokenizer::TOK_IGNORE_EMPTY | tokenizer::TOK_TRIM); -+ std::vector vect; -+ -+ for (tokenizer::Iterator iIt = values.begin(); iIt != values.end(); ++iIt) -+ vect.push_back(boost::lexical_cast(*iIt)); -+ -+ value.push_back(vect); -+ } -+} -+ - /// Macro for the vector specializations - #define PROPERTYWITHVALUE_TOVALUE(type) \ - template <> \ -diff --git a/Code/Mantid/Framework/Kernel/src/ArrayProperty.cpp b/Code/Mantid/Framework/Kernel/src/ArrayProperty.cpp -index 783434b..9c2a562 100644 ---- a/Code/Mantid/Framework/Kernel/src/ArrayProperty.cpp -+++ b/Code/Mantid/Framework/Kernel/src/ArrayProperty.cpp -@@ -16,6 +16,8 @@ template DLLExport class ArrayProperty; - template DLLExport class ArrayProperty; - template DLLExport class ArrayProperty; - -+template DLLExport class ArrayProperty >; -+ - /// @endcond - - } // namespace Kernel -diff --git a/Code/Mantid/Framework/Kernel/src/IPropertyManager.cpp b/Code/Mantid/Framework/Kernel/src/IPropertyManager.cpp -index 50fa4e6..dade2e8 100644 ---- a/Code/Mantid/Framework/Kernel/src/IPropertyManager.cpp -+++ b/Code/Mantid/Framework/Kernel/src/IPropertyManager.cpp -@@ -23,6 +23,7 @@ DEFINE_IPROPERTYMANAGER_GETVALUE(std::vector); - DEFINE_IPROPERTYMANAGER_GETVALUE(std::vector); - DEFINE_IPROPERTYMANAGER_GETVALUE(std::vector); - DEFINE_IPROPERTYMANAGER_GETVALUE(std::vector); -+DEFINE_IPROPERTYMANAGER_GETVALUE(std::vector >); - - namespace Mantid - { -diff --git a/Code/Mantid/Framework/Kernel/src/MultiFileNameParser.cpp b/Code/Mantid/Framework/Kernel/src/MultiFileNameParser.cpp -index 6f28688..c2b7946 100644 ---- a/Code/Mantid/Framework/Kernel/src/MultiFileNameParser.cpp -+++ b/Code/Mantid/Framework/Kernel/src/MultiFileNameParser.cpp -@@ -3,6 +3,10 @@ - //---------------------------------------------------------------------- - #include "MantidKernel/MultiFileNameParser.h" - -+#include "MantidKernel/ConfigService.h" -+#include "MantidKernel/InstrumentInfo.h" -+#include "MantidKernel/Exception.h" -+ - #include - #include - #include -@@ -15,6 +19,9 @@ - #include - #include - #include -+#include -+ -+#include - - namespace Mantid - { -@@ -47,7 +54,7 @@ namespace Kernel - - const std::string ANY = "(" + ADD_STEP_RANGE + "|" + ADD_RANGE + "|" + ADD_LIST + "|" + STEP_RANGE + "|" + RANGE + "|" + SINGLE + ")"; - const std::string LIST = "(" + ANY + "(" + COMMA + ANY + ")*" + ")"; -- } // namespace Regexs -+ } - - ///////////////////////////////////////////////////////////////////////////// - // Forward declarations. -@@ -55,10 +62,25 @@ namespace Kernel - - namespace - { -+ // Anonymous helper functions. - std::vector > & parseToken(std::vector > & parsedRuns, const std::string & token); - std::vector > generateRange(unsigned int from, unsigned int to, unsigned int stepSize, bool addRuns); - void validateToken(const std::string & token); - bool matchesFully(const std::string & stringToMatch, const std::string & regexString); -+ std::string getMatchingString(const std::string & regexString, const std::string & toParse); -+ std::string pad(std::string run, int count); -+ -+ // Anonymous helper functor. -+ class GenerateFileName -+ { -+ public: -+ GenerateFileName(const std::string & prefix, const std::string & suffix, int zeroPadding); -+ std::vector operator()(const std::vector & runs); -+ std::string operator()(unsigned int run); -+ private: -+ std::string m_prefix, m_suffix; -+ int m_zeroPadding; -+ }; - } - - ///////////////////////////////////////////////////////////////////////////// -@@ -110,7 +132,110 @@ namespace Kernel - } - - ///////////////////////////////////////////////////////////////////////////// -- // Anonymous helper functions. -+ // Public member functions of Parser class. -+ ///////////////////////////////////////////////////////////////////////////// -+ -+ Parser::Parser() : -+ m_runs(), m_fileNames(), m_multiFileName(), m_dirString(), m_instString(), -+ m_underscoreString(), m_runString(), m_extString(), m_zeroPadding() -+ {} -+ -+ Parser::~Parser() -+ {} -+ -+ void Parser::parse(const std::string & multiFileName) -+ { -+ // Clear any contents of the member variables. -+ clear(); -+ -+ // Set the string to parse. -+ m_multiFileName = multiFileName; -+ -+ // Split the string to be parsed into sections, and do some validation. -+ split(); -+ -+ // Parse the run section into unsigned ints we can use. -+ m_runs = parseMultiRunString(m_runString); -+ -+ // Set up helper functor. -+ GenerateFileName generateFileName( -+ m_dirString + m_instString + m_underscoreString, -+ m_extString, -+ m_zeroPadding); -+ -+ // Generate complete file names for each run using helper functor. -+ std::transform( -+ m_runs.begin(), m_runs.end(), -+ m_fileNames.begin(), -+ generateFileName); -+ } -+ -+ ///////////////////////////////////////////////////////////////////////////// -+ // Private member functions of Parser class. -+ ///////////////////////////////////////////////////////////////////////////// -+ -+ void Parser::clear() -+ { -+ m_runs.clear(); -+ m_fileNames.clear(); -+ m_multiFileName.clear(); -+ m_dirString.clear(); -+ m_instString.clear(); -+ m_underscoreString.clear(); -+ m_runString.clear(); -+ m_extString.clear(); -+ } -+ -+ void Parser::split() -+ { -+ if(m_multiFileName.empty()) -+ throw std::runtime_error("No file name to parse."); -+ -+ // (We shun the use of Poco::File here as it is unable to deal with certain -+ // combinations of special characters, for example a double comma.) -+ -+ // Get the extension, if there is one. -+ size_t lastDot = m_multiFileName.find_last_of("."); -+ if(lastDot != std::string::npos) -+ m_extString = m_multiFileName.substr(lastDot); -+ -+ // Get the directory, if there is one. -+ size_t lastSeparator = m_multiFileName.find_last_of("/\\"); -+ if(lastSeparator != std::string::npos) -+ m_dirString = m_multiFileName.substr(0, lastSeparator); -+ -+ // Slice off the directory and extension. -+ std::string base = m_multiFileName.substr( -+ m_dirString.size(), m_multiFileName.size() - (m_dirString.size() + m_extString.size())); -+ -+ // Get the instrument name using a regex. Throw if not found since this is required. -+ m_instString = getMatchingString("^" + Regexs::INST, base); -+ if(m_instString.empty()) -+ throw std::runtime_error("There does not appear to be an instrument name present."); -+ -+ // Now check if instrument exists, if not then clear the parser, then rethrow the exception. -+ try -+ { -+ InstrumentInfo instInfo = ConfigService::Instance().getInstrument(m_instString); -+ m_zeroPadding = instInfo.zeroPadding(); -+ } catch (const Exception::NotFoundError &) -+ { -+ throw std::runtime_error("There does not appear to be a valid instrument name present."); -+ } -+ -+ // Check for an underscore after the instrument name. -+ size_t underscore = base.find_first_of("_"); -+ if(underscore == m_instString.size()) -+ m_underscoreString = "_"; -+ -+ // We can now deduce the run string. Throw if not found since this is required. -+ m_runString = base.substr(m_underscoreString.size() + m_instString.size()); -+ if(m_instString.empty()) -+ throw std::runtime_error("There does not appear to be any runs present."); -+ } -+ -+ ///////////////////////////////////////////////////////////////////////////// -+ // Anonymous helper functions and functors. - ///////////////////////////////////////////////////////////////////////////// - - namespace // anonymous -@@ -329,6 +454,74 @@ namespace Kernel - return boost::regex_match(stringToMatch, regex); - } - -+ /** -+ * Finds a given regex in a given string, and returns the part of the string -+ * that matches the regex. Returns "" if there is no occurance of the regex. -+ * -+ * @param regex - the regular expression to find within the string -+ * @param toParse - the string within to find the regex -+ * -+ * @returns the part (if any) of the given string that matches the given regex -+ */ -+ std::string getMatchingString(const std::string & regexString, const std::string & toParse) -+ { -+ boost::sregex_iterator it( -+ toParse.begin(), toParse.end(), -+ boost::regex(regexString) -+ ); -+ -+ if(it == boost::sregex_iterator()) -+ return ""; -+ -+ return it->str(); -+ } -+ -+ /** -+ * Zero pads the run number used in a file name to required length. -+ * -+ * @param run - the run number of the file. May as well pass by value here. -+ * @param count - the required length of the string. -+ * -+ * @returns the string, padded to the required length. -+ * @throws std::runtime_error if run is longer than size of count. -+ */ -+ std::string pad(std::string run, int count) -+ { -+ if(run.size() < count) -+ return run.insert(0, count - run.size(), '0'); -+ else if(run.size() > count) -+ throw std::runtime_error("Could not parse run number \"" + run + -+ "\" since the instrument run number length required is " + boost::lexical_cast(count)); -+ return run; -+ } -+ -+ GenerateFileName::GenerateFileName(const std::string & prefix, const std::string & suffix, int zeroPadding) : -+ m_prefix(prefix), m_suffix(suffix), m_zeroPadding(zeroPadding) -+ {} -+ -+ std::vector GenerateFileName::operator()(const std::vector & runs) -+ { -+ std::vector fileNames; -+ -+ /*std::transform( -+ runs.begin(), runs.end(), -+ fileNames.begin(), -+ (*this));*/ -+ -+ return fileNames; -+ } -+ -+ std::string GenerateFileName::operator()(unsigned int run) -+ { -+ std::stringstream fileName; -+ -+ fileName << m_prefix -+ << pad(boost::lexical_cast(run), m_zeroPadding) -+ << m_suffix; -+ -+ return fileName.str(); -+ } -+ - } // anonymous namespace - - } // namespace MultiFileNameParsing -diff --git a/Code/Mantid/Framework/Kernel/src/PropertyWithValue.cpp b/Code/Mantid/Framework/Kernel/src/PropertyWithValue.cpp -index e8db6c9..8924b53 100644 ---- a/Code/Mantid/Framework/Kernel/src/PropertyWithValue.cpp -+++ b/Code/Mantid/Framework/Kernel/src/PropertyWithValue.cpp -@@ -23,6 +23,8 @@ namespace Mantid - template DLLExport class PropertyWithValue >; - template DLLExport class PropertyWithValue >; - template DLLExport class PropertyWithValue >; -+ -+ template DLLExport class PropertyWithValue > >; - /// @endcond - - } // namespace Kernel -diff --git a/Code/Mantid/Framework/Kernel/test/MultiFileNameParserTest.h b/Code/Mantid/Framework/Kernel/test/MultiFileNameParserTest.h -index 308a720..17a276d 100644 ---- a/Code/Mantid/Framework/Kernel/test/MultiFileNameParserTest.h -+++ b/Code/Mantid/Framework/Kernel/test/MultiFileNameParserTest.h -@@ -15,6 +15,10 @@ class MultiFileNameParserTest : public CxxTest::TestSuite - public: - typedef std::vector > ParsedRuns; - -+ ///////////////////////////////////////////////////////////////////////////// -+ // Testing of parseMultiRunString. -+ ///////////////////////////////////////////////////////////////////////////// -+ - void test_single() - { - ParsedRuns result = parseMultiRunString("1"); -@@ -250,6 +254,19 @@ public: - std::string(re.what()), - "The token \"1-3-1\" is of an incorrect form."); - } -+ -+ ///////////////////////////////////////////////////////////////////////////// -+ // Testing of Parse class. -+ ///////////////////////////////////////////////////////////////////////////// -+ -+ void test_errorThrownIfPassedEmptyString() -+ { -+ Parser parser; -+ -+ parser.parse("TSC_10-20, 30:40:2.raw"); -+ -+ std::vector > filenames = parser.fileNames(); -+ } - }; - - #endif /* MANTID_KERNEL_MULTIFILENAMEPARSERTEST_H_ */ -\ No newline at end of file -diff --git a/Code/Mantid/Framework/MDAlgorithms/src/MergeMDFiles.cpp b/Code/Mantid/Framework/MDAlgorithms/src/MergeMDFiles.cpp -index ac8b61e..cdf3726 100644 ---- a/Code/Mantid/Framework/MDAlgorithms/src/MergeMDFiles.cpp -+++ b/Code/Mantid/Framework/MDAlgorithms/src/MergeMDFiles.cpp -@@ -641,7 +641,8 @@ namespace MDAlgorithms - */ - void MergeMDFiles::exec() - { -- m_filenames = getProperty("Filenames"); -+ MultipleFileProperty * multiFileProp = dynamic_cast(getPointerToProperty("Filenames")); -+ m_filenames = multiFileProp->getFlatFileNames(); - if (m_filenames.size() == 0) - throw std::invalid_argument("Must specify at least one filename."); - std::string firstFile = m_filenames[0];