Skip to content
Snippets Groups Projects
GenericDataProcessorPresenter.cpp 42.2 KiB
Newer Older
#include "MantidQtMantidWidgets/DataProcessorUI/GenericDataProcessorPresenter.h"
#include "MantidAPI/AlgorithmManager.h"
#include "MantidAPI/ITableWorkspace.h"
#include "MantidAPI/MatrixWorkspace.h"
#include "MantidAPI/NotebookWriter.h"
#include "MantidAPI/TableRow.h"
#include "MantidAPI/WorkspaceFactory.h"
#include "MantidGeometry/Instrument.h"
#include "MantidKernel/Strings.h"
#include "MantidKernel/TimeSeriesProperty.h"
#include "MantidKernel/Utils.h"
#include "MantidKernel/make_unique.h"
#include "MantidQtMantidWidgets/AlgorithmHintStrategy.h"
#include "MantidQtMantidWidgets/DataProcessorUI/DataProcessorGenerateNotebook.h"
#include "MantidQtMantidWidgets/DataProcessorUI/DataProcessorMainPresenter.h"
#include "MantidQtMantidWidgets/DataProcessorUI/DataProcessorOneLevelTreeManager.h"
#include "MantidQtMantidWidgets/DataProcessorUI/DataProcessorTwoLevelTreeManager.h"
#include "MantidQtMantidWidgets/DataProcessorUI/DataProcessorView.h"
#include "MantidQtMantidWidgets/DataProcessorUI/DataProcessorWorkspaceCommand.h"
#include "MantidQtMantidWidgets/DataProcessorUI/ParseKeyValueString.h"
#include "MantidQtMantidWidgets/DataProcessorUI/QtDataProcessorOptionsDialog.h"
#include "MantidQtMantidWidgets/ProgressPresenter.h"
#include "MantidQtMantidWidgets/ProgressableView.h"
#include <algorithm>
#include <boost/regex.hpp>
#include <boost/tokenizer.hpp>
#include <fstream>
#include <sstream>

using namespace Mantid::API;
using namespace Mantid::Geometry;
using namespace Mantid::Kernel;
using namespace MantidQt::MantidWidgets;

namespace MantidQt {
* @param whitelist : The set of properties we want to show as columns
* @param preprocessMap : A map containing instructions for pre-processing
* @param processor : A DataProcessorProcessingAlgorithm
* @param postprocessor : A DataProcessorPostprocessingAlgorithm
* @param postprocessMap : A map containing instructions for post-processing.
* This map links column name to properties of the post-processing algorithm
* @param loader : The algorithm responsible for loading data
GenericDataProcessorPresenter::GenericDataProcessorPresenter(
    const DataProcessorWhiteList &whitelist,
    const std::map<std::string, DataProcessorPreprocessingAlgorithm> &
        preprocessMap,
    const DataProcessorProcessingAlgorithm &processor,
    const DataProcessorPostprocessingAlgorithm &postprocessor,
    const std::map<std::string, std::string> &postprocessMap,
    const std::string &loader)
    : WorkspaceObserver(), m_view(nullptr), m_progressView(nullptr),
      m_mainPresenter(), m_whitelist(whitelist), m_preprocessMap(preprocessMap),
      m_processor(processor), m_postprocessor(postprocessor),
      m_postprocessMap(postprocessMap), m_loader(loader), m_postprocess(true),
      m_tableDirty(false) {
  // Column Options must be added to the whitelist
  m_whitelist.addElement("Options", "Options",
                         "<b>Override <samp>" + processor.name() +
                             "</samp> properties</b><br /><i>optional</i><br "
                             "/>This column allows you to "
                             "override the properties used when executing "
                             "Options are given as "
                             "key=value pairs, separated by commas. Values "
                             "containing commas must be quoted. In case of "
                             "conflict between options "
                             "specified via this column and options specified "
                             "via the <b>Process</b> line edit, the former "
  m_columns = static_cast<int>(m_whitelist.size());
  if (m_postprocessor.name().empty()) {
    m_postprocess = false;
    m_manager = Mantid::Kernel::make_unique<DataProcessorOneLevelTreeManager>(
        this, m_whitelist);
  } else {
    m_manager = Mantid::Kernel::make_unique<DataProcessorTwoLevelTreeManager>(
        this, m_whitelist);
  }
/**
* Delegating constructor (no pre-processing needed)
* @param whitelist : The set of properties we want to show as columns
* @param processor : A DataProcessorProcessingAlgorithm
* @param postprocessor : A DataProcessorPostprocessingAlgorithm
* workspaces
*/
GenericDataProcessorPresenter::GenericDataProcessorPresenter(
    const DataProcessorWhiteList &whitelist,
    const DataProcessorProcessingAlgorithm &processor,
    const DataProcessorPostprocessingAlgorithm &postprocessor)
    : GenericDataProcessorPresenter(
          whitelist,
          std::map<std::string, DataProcessorPreprocessingAlgorithm>(),
          processor, postprocessor) {}

/**
* Delegating constructor (no post-processing needed)
* @param whitelist : The set of properties we want to show as columns
* @param preprocessMap : A map containing instructions for pre-processing
* @param processor : A DataProcessorProcessingAlgorithm
* workspaces
*/
GenericDataProcessorPresenter::GenericDataProcessorPresenter(
    const DataProcessorWhiteList &whitelist,
    const std::map<std::string, DataProcessorPreprocessingAlgorithm> &
        preprocessMap,
    const DataProcessorProcessingAlgorithm &processor)
    : GenericDataProcessorPresenter(whitelist, preprocessMap, processor,
                                    DataProcessorPostprocessingAlgorithm()) {}

/**
* Delegating constructor (no pre-processing needed, no post-processing needed)
* @param whitelist : The set of properties we want to show as columns
* @param processor : A DataProcessorProcessingAlgorithm
* workspaces
*/
GenericDataProcessorPresenter::GenericDataProcessorPresenter(
    const DataProcessorWhiteList &whitelist,
    const DataProcessorProcessingAlgorithm &processor)
    : GenericDataProcessorPresenter(
          whitelist,
          std::map<std::string, DataProcessorPreprocessingAlgorithm>(),
          processor, DataProcessorPostprocessingAlgorithm()) {}

/**
* Destructor
*/
GenericDataProcessorPresenter::~GenericDataProcessorPresenter() {}

/**
* Sets the views this presenter is going to handle
* @param tableView : The table view
* @param progressView : The progress view
*/
void GenericDataProcessorPresenter::acceptViews(
    DataProcessorView *tableView, ProgressableView *progressView) {

  // As soon as we are given a view, initialize everything
  m_view = tableView;
  m_progressView = progressView;

  // Initialise options
  // Load saved values from disk
  initOptions();
  // Populate an initial list of valid tables to open, and subscribe to the ADS
  // to keep it up to date
  Mantid::API::AnalysisDataServiceImpl &ads =
      Mantid::API::AnalysisDataService::Instance();

  auto items = ads.getObjectNames();
  for (auto const &name : items) {
    Workspace_sptr ws = ads.retrieve(name);

Raquel Alvarez's avatar
Raquel Alvarez committed
    if (m_manager->isValidModel(
            boost::dynamic_pointer_cast<ITableWorkspace>(ws),
            m_whitelist.size()))
      m_workspaceList.insert(name);
  }
  observeAdd();
  observePostDelete();
  observeRename();
  observeADSClear();
  observeAfterReplace();
  m_view->setTableList(m_workspaceList);

  // Provide autocompletion hints for the options column. We use the algorithm's
  // properties minus those we blacklist. We blacklist any useless properties or
  // ones we're handling that the user should'nt touch.
  IAlgorithm_sptr alg = AlgorithmManager::Instance().create(m_processor.name());
  m_view->setOptionsHintStrategy(
      new AlgorithmHintStrategy(alg, m_processor.blacklist()), m_columns - 1);
void GenericDataProcessorPresenter::process() {
  const auto items = m_manager->selectedData(true);
  // Don't bother continuing if there are no items to process
  if (items.size() == 0)
    return;

  // Progress: each group and each row within count as a progress step.
  int progress = 0;
  int maxProgress = (int)(items.size());
  for (const auto subitem : items) {
    maxProgress += (int)(subitem.second.size());
  ProgressPresenter progressReporter(progress, maxProgress, maxProgress,
                                     m_progressView);
  for (const auto &item : items) {
    // Group with updated columns
    GroupData newGroup;

    // Reduce rows sequentially
    // Loop over rows within this group
    for (const auto &data : item.second) {
      // data.first -> index of this row within the group
      // data.second -> vector containing data
        auto newData = reduceRow(data.second);
Raquel Alvarez's avatar
Raquel Alvarez committed
        m_manager->update(item.first, data.first, newData);
Raquel Alvarez's avatar
Raquel Alvarez committed
        newGroup[data.first] = newData;
        progressReporter.report();
      } catch (std::exception &ex) {
        m_mainPresenter->giveUserCritical(ex.what(), "Error");
        progressReporter.clear();
      progressReporter.report();
    // Post-process (if needed)
    if (item.second.size() > 1) {
      try {
        postProcessGroup(newGroup);
        progressReporter.report();
      } catch (std::exception &ex) {
        m_mainPresenter->giveUserCritical(ex.what(), "Error");
        progressReporter.clear();
        return;
      }
    }
  // If "Output Notebook" checkbox is checked then create an ipython notebook
  if (m_view->getEnableNotebook()) {
    saveNotebook(items);
}

/**
Display a dialog to choose save location for notebook, then save the notebook
there
@param data : the processed data
Raquel Alvarez's avatar
Raquel Alvarez committed
void GenericDataProcessorPresenter::saveNotebook(const TreeData &data) {
  std::string filename = m_view->requestNotebookPath();
  // Global pre-processing options as a map where keys are column
  // name and values are pre-processing options as a string
  const std::map<std::string, std::string> preprocessingOptionsMap =
      m_mainPresenter->getPreprocessingOptions();
  // Global processing options as a string
  const std::string processingOptions = m_mainPresenter->getProcessingOptions();
  // Global post-processing options as a string
  const std::string postprocessingOptions =
      m_mainPresenter->getPostprocessingOptions();
  auto notebook = Mantid::Kernel::make_unique<DataProcessorGenerateNotebook>(
      m_wsName, m_view->getProcessInstrument(), m_whitelist, m_preprocessMap,
      m_processor, m_postprocessor, preprocessingOptionsMap, processingOptions,
      postprocessingOptions);
  std::string generatedNotebook = notebook->generateNotebook(data);

  std::ofstream file(filename.c_str(), std::ofstream::trunc);
  file << generatedNotebook;
  file.flush();
  file.close();
Post-processes the workspaces created by the given rows together.
@param groupData : the data in a given group as received from the tree manager
void GenericDataProcessorPresenter::postProcessGroup(
    const GroupData &groupData) {
  if (!m_postprocess)
    throw std::runtime_error("Cannot post-process workspaces");

  // The input workspace names
  std::vector<std::string> inputNames;
  // The name to call the post-processed ws
  const std::string outputWSName =
      getPostprocessedWorkspaceName(groupData, m_postprocessor.prefix());

  // Go through each row and get the input ws names
  for (const auto &row : groupData) {
    // The name of the reduced workspace for this row
    const std::string inputWSName =
        getReducedWorkspaceName(row.second, m_processor.prefix(0));
    if (AnalysisDataService::Instance().doesExist(inputWSName)) {
      inputNames.emplace_back(inputWSName);
  const std::string inputWSNames = boost::algorithm::join(inputNames, ", ");
  // If the previous result is in the ADS already, we'll need to remove it.
  // If it's a group, we'll get an error for trying to group into a used group
  // name
  if (AnalysisDataService::Instance().doesExist(outputWSName))
    AnalysisDataService::Instance().remove(outputWSName);

  IAlgorithm_sptr alg =
      AlgorithmManager::Instance().create(m_postprocessor.name());
  alg->setProperty(m_postprocessor.inputProperty(), inputWSNames);
  alg->setProperty(m_postprocessor.outputProperty(), outputWSName);
  // Global post-processing options
  const std::string options = m_mainPresenter->getPostprocessingOptions();
  auto optionsMap = parseKeyValueString(options);
  for (auto kvp = optionsMap.begin(); kvp != optionsMap.end(); ++kvp) {
    try {
      alg->setProperty(kvp->first, kvp->second);
    } catch (Mantid::Kernel::Exception::NotFoundError &) {
      throw std::runtime_error("Invalid property in options column: " +
                               kvp->first);
    }
  }
  // Options specified via post-process map
  for (const auto &prop : m_postprocessMap) {
    const std::string propName = prop.second;
    const std::string propValueStr =
        groupData.begin()->second[m_whitelist.colIndexFromColName(prop.first)];
    if (!propValueStr.empty()) {
      // Warning: we take minus the value of the properties because in
      // Reflectometry this property refers to the rebin step, and they want a
      // logarithmic binning. If other technique areas need to use a
      // post-process map we'll need to re-think how to do this.
      alg->setPropertyValue(propName, "-" + propValueStr);
    throw std::runtime_error("Failed to post-process workspaces.");
/**
Takes a user specified run, or list of runs, and returns a pointer to the
@param runStr : The run or list of runs (separated by '+')
@param preprocessor : The pre-processing algorithm acting on this column
@param optionsMap : User-specified options as a map
@throws std::runtime_error if the workspace could not be prepared
@returns a shared pointer to the workspace
*/
Workspace_sptr GenericDataProcessorPresenter::prepareRunWorkspace(
    const std::string &runStr,
    const DataProcessorPreprocessingAlgorithm &preprocessor,
    const std::map<std::string, std::string> &optionsMap) {
  const std::string instrument = m_view->getProcessInstrument();
  boost::split(runs, runStr, boost::is_any_of("+,"));

  if (runs.empty())
    throw std::runtime_error("No runs given");

  // Remove leading/trailing whitespace from each run
  for (auto runIt = runs.begin(); runIt != runs.end(); ++runIt)
    boost::trim(*runIt);

  // If we're only given one run, just return that
  if (runs.size() == 1)
    return loadRun(runs[0], instrument, preprocessor.prefix());
  const std::string outputName =
      preprocessor.prefix() + boost::algorithm::join(runs, "_");

  /* Ideally, this should be executed as a child algorithm to keep the ADS tidy,
  * but that doesn't preserve history nicely, so we'll just take care of tidying
  * up in the event of failure.
  IAlgorithm_sptr alg =
      AlgorithmManager::Instance().create(preprocessor.name());
  alg->initialize();
  alg->setProperty(
      preprocessor.lhsProperty(),
      loadRun(runs[0], instrument, preprocessor.prefix())->getName());
  alg->setProperty(preprocessor.outputProperty(), outputName);

  // Drop the first run from the runs list
  runs.erase(runs.begin());

  try {
    // Iterate through all the remaining runs, adding them to the first run
    for (auto runIt = runs.begin(); runIt != runs.end(); ++runIt) {

      for (auto kvp = optionsMap.begin(); kvp != optionsMap.end(); ++kvp) {
        try {
          alg->setProperty(kvp->first, kvp->second);
        } catch (Mantid::Kernel::Exception::NotFoundError &) {
          // We can't apply this option to this pre-processing alg
          throw;
      alg->setProperty(
          loadRun(*runIt, instrument, preprocessor.prefix())->getName());
      alg->execute();

      if (runIt != --runs.end()) {
        // After the first execution we replace the LHS with the previous output
        alg->setProperty(preprocessor.lhsProperty(), outputName);
    }
  } catch (...) {
    // If we're unable to create the full workspace, discard the partial version
    AnalysisDataService::Instance().remove(outputName);

    // We've tidied up, now re-throw.
    throw;
  }

  return AnalysisDataService::Instance().retrieveWS<Workspace>(outputName);
}

Returns the name of the reduced workspace for a given row
@param data :: [input] The data for this row
@param prefix : A prefix to be appended to the generated ws name
@throws std::runtime_error if the workspace could not be prepared
@returns : The name of the workspace
*/
std::string GenericDataProcessorPresenter::getReducedWorkspaceName(
    const std::vector<std::string> &data, const std::string &prefix) {
  if (static_cast<int>(data.size()) != m_columns)
    throw std::invalid_argument("Can't find reduced workspace name");

  /* This method calculates, for a given row, the name of the output (processed)
  * workspace. This is done using the white list, which contains information
  * about the columns that should be included to create the ws name. In
  * Reflectometry for example, we want to include values in the 'Run(s)' and
  * 'Transmission Run(s)' columns. We may also use a prefix associated with
  * the column when specified. Finally, to construct the ws name we may also
  * use a 'global' prefix associated with the processing algorithm (for
  * instance 'IvsQ_' in Reflectometry) this is given by the second argument to
  * this method */
  // Temporary vector of strings to construct the name
  std::vector<std::string> names;
  for (int col = 0; col < m_columns; col++) {
    // Do we want to use this column to generate the name of the output ws?
    if (m_whitelist.showValue(col)) {
      // Get what's in the column
      const std::string valueStr = data.at(col);
      // If it's not empty, use it
      if (!valueStr.empty()) {
        // But we may have things like '1+2' which we want to replace with '1_2'
        std::vector<std::string> value;
        boost::split(value, valueStr, boost::is_any_of("+"));
        names.push_back(m_whitelist.prefix(col) +
                        boost::algorithm::join(value, "_"));
  std::string wsname = prefix;
  wsname += boost::algorithm::join(names, "_");

Returns the name of the reduced workspace for a given group
@param groupData : The data in a given group
@param prefix : A prefix to be appended to the generated ws name
@returns : The name of the workspace
*/
std::string GenericDataProcessorPresenter::getPostprocessedWorkspaceName(
Raquel Alvarez's avatar
Raquel Alvarez committed
    const GroupData &groupData, const std::string &prefix) {
  if (!m_postprocess)
    throw std::runtime_error("Cannot retrieve post-processed workspace name");

  /* This method calculates, for a given set of rows, the name of the output
  * (post-processed) workspace */

  std::vector<std::string> outputNames;

  for (const auto &data : groupData) {
    outputNames.push_back(getReducedWorkspaceName(data.second));
  }
  return prefix + boost::join(outputNames, "_");
}

/**
Loads a run from disk or fetches it from the AnalysisDataService
@param run : The name of the run
@param instrument : The instrument the run belongs to
@param prefix : The prefix to be prepended to the run number
@throws std::runtime_error if the run could not be loaded
@returns a shared pointer to the workspace
*/
Workspace_sptr
GenericDataProcessorPresenter::loadRun(const std::string &run,
                                       const std::string &instrument,
                                       const std::string &prefix) {
  // First, let's see if the run given is the name of a workspace in the ADS
  if (AnalysisDataService::Instance().doesExist(run))
    return AnalysisDataService::Instance().retrieveWS<Workspace>(run);
  // Try with prefix
  if (AnalysisDataService::Instance().doesExist(prefix + run))
    return AnalysisDataService::Instance().retrieveWS<Workspace>(prefix + run);

  // Is the run string is numeric
  if (boost::regex_match(run, boost::regex("\\d+"))) {
    std::string wsName;

    // Look for "<run_number>" in the ADS
    wsName = run;
    if (AnalysisDataService::Instance().doesExist(wsName))
      return AnalysisDataService::Instance().retrieveWS<Workspace>(wsName);

    // Look for "<instrument><run_number>" in the ADS
    wsName = instrument + run;
    if (AnalysisDataService::Instance().doesExist(wsName))
      return AnalysisDataService::Instance().retrieveWS<Workspace>(wsName);
  }

  // We'll just have to load it ourselves
  const std::string filename = instrument + run;
  const std::string outputName = prefix + run;
  IAlgorithm_sptr algLoadRun = AlgorithmManager::Instance().create(m_loader);
  algLoadRun->initialize();
  algLoadRun->setProperty("Filename", filename);
  algLoadRun->setProperty("OutputWorkspace", outputName);
  algLoadRun->execute();

  if (!algLoadRun->isExecuted())
    throw std::runtime_error("Could not open " + filename);

  return AnalysisDataService::Instance().retrieveWS<Workspace>(outputName);
@param data :: [input] The data in this row as a vector where elements
correspond to column contents
@throws std::runtime_error if reduction fails
@return :: Data updated after running the algorithm
std::vector<std::string>
GenericDataProcessorPresenter::reduceRow(const std::vector<std::string> &data) {
  /* Create the processing algorithm */
  IAlgorithm_sptr alg = AlgorithmManager::Instance().create(m_processor.name());
  alg->initialize();
  /* Read input properties from the table */
  /* excluding 'Group' and 'Options' */
  // Global pre-processing options as a map
  std::map<std::string, std::string> globalOptions;
  if (!m_preprocessMap.empty())
    globalOptions = m_mainPresenter->getPreprocessingOptions();
  // Pre-processing values and their associated properties
  auto preProcessValMap = m_mainPresenter->getPreprocessingValues();
  auto preProcessPropMap = m_mainPresenter->getPreprocessingProperties();

  // Properties not to be used in processing
  std::set<std::string> restrictedProps;
  // Loop over all columns in the whitelist except 'Options'
  for (int i = 0; i < m_columns - 1; i++) {
    // The algorithm's property linked to this column
    auto propertyName = m_whitelist.algPropFromColIndex(i);
    auto columnName = m_whitelist.colNameFromColIndex(i);
    // The value for which preprocessing can be conducted on
    std::string preProcessValue;

    if (preProcessValMap.count(columnName) &&
        !preProcessValMap[columnName].empty()) {
      preProcessValue = preProcessValMap[columnName];
    } else if (!data.at(i).empty()) {
      preProcessValue = data.at(i);
    } else {
      continue;
    if (m_preprocessMap.count(columnName)) {
      // We do not want the associated properties to be set again in
      // processing
      for (auto &prop : preProcessPropMap[columnName]) {
        restrictedProps.insert(prop);
      }
      auto preprocessor = m_preprocessMap.at(columnName);
      // Global pre-processing options for this algorithm as a string
      const std::string options = globalOptions.count(columnName) > 0
                                      ? globalOptions.at(columnName)
                                      : "";
      auto optionsMap = parseKeyValueString(options);
      auto runWS =
          prepareRunWorkspace(preProcessValue, preprocessor, optionsMap);
      alg->setProperty(propertyName, runWS->getName());
      // No pre-processing needed
Pranav Bahuguna's avatar
Pranav Bahuguna committed
      alg->setPropertyValue(propertyName, preProcessValue);
  // Global processing options as a string
  std::string options = m_mainPresenter->getProcessingOptions();
  // Parse and set any user-specified options
  auto optionsMap = parseKeyValueString(options);
  for (auto kvp = optionsMap.begin(); kvp != optionsMap.end(); ++kvp) {
    try {
Pranav Bahuguna's avatar
Pranav Bahuguna committed
      if (restrictedProps.find(kvp->first) == restrictedProps.end())
        alg->setProperty(kvp->first, kvp->second);
    } catch (Mantid::Kernel::Exception::NotFoundError &) {
      throw std::runtime_error("Invalid property in options column: " +
                               kvp->first);
    }
  }

  /* Now deal with 'Options' column */
  // Parse and set any user-specified options
  optionsMap = parseKeyValueString(options);
  for (auto kvp = optionsMap.begin(); kvp != optionsMap.end(); ++kvp) {
    try {
      alg->setProperty(kvp->first, kvp->second);
    } catch (Mantid::Kernel::Exception::NotFoundError &) {
      throw std::runtime_error("Invalid property in options column: " +
                               kvp->first);
  /* We need to give a name to the output workspaces */
  for (size_t i = 0; i < m_processor.numberOfOutputProperties(); i++) {
    alg->setProperty(m_processor.outputPropertyName(i),
                     getReducedWorkspaceName(data, m_processor.prefix(i)));
  /* Now run the processing algorithm */
  alg->execute();
  if (alg->isExecuted()) {

    /* The reduction is complete, try to populate the columns */
    for (int i = 0; i < m_columns - 1; i++) {

      auto columnName = m_whitelist.colNameFromColIndex(i);

      if (data.at(i).empty() && !m_preprocessMap.count(columnName)) {

        std::string propValue =
            alg->getPropertyValue(m_whitelist.algPropFromColIndex(i));

        if (m_options["Round"].toBool()) {
Raquel Alvarez's avatar
Raquel Alvarez committed
          std::string exp = (propValue.find("e") != std::string::npos)
                                ? propValue.substr(propValue.find("e"))
                                : "";
          propValue =
              propValue.substr(0, propValue.find(".") +
                                      m_options["RoundPrecision"].toInt() + 1) +
              exp;
void GenericDataProcessorPresenter::appendRow() {
void GenericDataProcessorPresenter::appendGroup() {
void GenericDataProcessorPresenter::deleteRow() {
/**
Delete group(s) from the model
*/
void GenericDataProcessorPresenter::deleteGroup() {
void GenericDataProcessorPresenter::groupRows() {
/**
Expand all groups
*/
void GenericDataProcessorPresenter::expandAll() { m_view->expandAll(); }
Pranav Bahuguna's avatar
Pranav Bahuguna committed
Collapse all groups
void GenericDataProcessorPresenter::collapseAll() { m_view->collapseAll(); }
/**
Used by the view to tell the presenter something has changed
*/
void GenericDataProcessorPresenter::notify(DataProcessorPresenter::Flag flag) {
  case DataProcessorPresenter::SaveAsFlag:
  case DataProcessorPresenter::SaveFlag:
  case DataProcessorPresenter::AppendRowFlag:
  case DataProcessorPresenter::AppendGroupFlag:
    appendGroup();
  case DataProcessorPresenter::DeleteRowFlag:
  case DataProcessorPresenter::DeleteGroupFlag:
    deleteGroup();
    break;
  case DataProcessorPresenter::ProcessFlag:
  case DataProcessorPresenter::GroupRowsFlag:
  case DataProcessorPresenter::NewTableFlag:
  case DataProcessorPresenter::TableUpdatedFlag:
  case DataProcessorPresenter::ExpandSelectionFlag:
  case DataProcessorPresenter::OptionsDialogFlag:
  case DataProcessorPresenter::ClearSelectedFlag:
  case DataProcessorPresenter::CopySelectedFlag:
  case DataProcessorPresenter::CutSelectedFlag:
  case DataProcessorPresenter::PasteSelectedFlag:
  case DataProcessorPresenter::ImportTableFlag:
  case DataProcessorPresenter::OpenTableFlag:
  case DataProcessorPresenter::ExportTableFlag:
  case DataProcessorPresenter::PlotRowFlag:
  case DataProcessorPresenter::PlotGroupFlag:
Pranav Bahuguna's avatar
Pranav Bahuguna committed
  case DataProcessorPresenter::ExpandAllGroupsFlag:
    expandAll();
Pranav Bahuguna's avatar
Pranav Bahuguna committed
  case DataProcessorPresenter::CollapseAllGroupsFlag:
    collapseAll();
  }
  // Not having a 'default' case is deliberate. gcc issues a warning if there's
  // a flag we aren't handling.
}

/**
Press changes to the same item in the ADS
*/
void GenericDataProcessorPresenter::saveTable() {
  if (!m_wsName.empty()) {
    AnalysisDataService::Instance().addOrReplace(
        m_wsName, boost::shared_ptr<ITableWorkspace>(
                      m_manager->getTableWorkspace()->clone().release()));
    m_tableDirty = false;
  } else {
    saveTableAs();
  }
}

/**
Press changes to a new item in the ADS
*/
void GenericDataProcessorPresenter::saveTableAs() {
  const std::string userString = m_mainPresenter->askUserString(
      "Save As", "Enter a workspace name:", "Workspace");
  if (!userString.empty()) {
    m_wsName = userString;
    saveTable();
  }
}

/**
Start a new, untitled table
*/
void GenericDataProcessorPresenter::newTable() {
  if (m_tableDirty && m_options["WarnDiscardChanges"].toBool())
    if (!m_mainPresenter->askUserYesNo(
            "Your current table has unsaved changes. Are you "
            "sure you want to discard them?",
            "Start New Table?"))
  m_manager->newTable(m_whitelist);
  m_view->showTable(m_manager->getModel());

  m_tableDirty = false;
}

/**
Open a table from the ADS
*/
void GenericDataProcessorPresenter::openTable() {
  if (m_tableDirty && m_options["WarnDiscardChanges"].toBool())
    if (!m_mainPresenter->askUserYesNo(
            "Your current table has unsaved changes. Are you "
            "sure you want to discard them?",
            "Open Table?"))
      return;

  auto &ads = AnalysisDataService::Instance();
  const std::string toOpen = m_view->getWorkspaceToOpen();

  if (toOpen.empty())
    return;

  if (!ads.isValid(toOpen).empty()) {
    m_mainPresenter->giveUserCritical("Could not open workspace: " + toOpen,
                                      "Error");
    return;
  }

  ITableWorkspace_sptr origTable =
      AnalysisDataService::Instance().retrieveWS<ITableWorkspace>(toOpen);

  // We create a clone of the table for live editing. The original is not
  // updated unless we explicitly save.
  ITableWorkspace_sptr newTable =
      boost::shared_ptr<ITableWorkspace>(origTable->clone().release());
  try {
Raquel Alvarez's avatar
Raquel Alvarez committed
    m_manager->isValidModel(newTable, m_whitelist.size());
    m_manager->newTable(newTable, m_whitelist);
    m_wsName = toOpen;
    m_view->showTable(m_manager->getModel());
    m_tableDirty = false;
  } catch (std::runtime_error &e) {
        "Could not open workspace: " + std::string(e.what()), "Error");
  }
}

/**
Import a table from TBL file
*/
void GenericDataProcessorPresenter::importTable() {

  std::stringstream pythonSrc;
  pythonSrc << "try:\n";
  pythonSrc << "  algm = "
            << "LoadTBL"
            << "Dialog()\n";
  pythonSrc << "  print algm.getPropertyValue(\"OutputWorkspace\")\n";
  pythonSrc << "except:\n";
  pythonSrc << "  pass\n";

  const std::string result =
      m_mainPresenter->runPythonAlgorithm(pythonSrc.str());

  // result will hold the name of the output workspace
  // otherwise this should be an empty string.
  QString outputWorkspaceName = QString::fromStdString(result);
  std::string toOpen = outputWorkspaceName.trimmed().toStdString();
  if (!toOpen.empty())
    m_view->setModel(toOpen);
void GenericDataProcessorPresenter::exportTable() {

  std::stringstream pythonSrc;
  pythonSrc << "try:\n";
  pythonSrc << "  algm = SaveTBLDialog()\n";
  pythonSrc << "except:\n";
  pythonSrc << "  pass\n";

  m_mainPresenter->runPythonAlgorithm(pythonSrc.str());
void GenericDataProcessorPresenter::addHandle(
    const std::string &name, Mantid::API::Workspace_sptr workspace) {
  if (Mantid::API::AnalysisDataService::Instance().isHiddenDataServiceObject(
          name))
    return;

  if (!m_manager->isValidModel(workspace, m_columns))
  m_view->setTableList(m_workspaceList);
  m_mainPresenter->notify(DataProcessorMainPresenter::ADSChangedFlag);
void GenericDataProcessorPresenter::postDeleteHandle(const std::string &name) {
  m_view->setTableList(m_workspaceList);
  m_mainPresenter->notify(DataProcessorMainPresenter::ADSChangedFlag);