Skip to content
Snippets Groups Projects
SANSRunWindow.cpp 94.9 KiB
Newer Older
//----------------------
// Includes
//----------------------
#include "MantidQtCustomInterfaces/SANSRunWindow.h"
#include "MantidQtCustomInterfaces/SANSUtilityDialogs.h"
#include "MantidQtCustomInterfaces/SANSAddFiles.h"
#include "MantidQtAPI/ManageUserDirectories.h"
#include "MantidQtAPI/FileDialogHandler.h"
#include "MantidKernel/Logger.h"
#include "MantidKernel/Exception.h"
#include "MantidAPI/FrameworkManager.h"
#include "MantidAPI/IAlgorithm.h"
#include "MantidAPI/SpectraDetectorMap.h"
#include <QTreeWidgetItem>
#include <QMessageBox>
#include <QInputDialog>
#include <QApplication>
#include <QClipboard>
#include <QTemporaryFile>
#include <Poco/StringTokenizer.h>
#include <boost/lexical_cast.hpp>
//Add this class to the list of specialised dialogs in this namespace
namespace MantidQt
{
namespace CustomInterfaces
{
  DECLARE_SUBWINDOW(SANSRunWindow);
using namespace MantidQt::MantidWidgets;
using namespace MantidQt::CustomInterfaces;
using namespace Mantid::Kernel;
using namespace Mantid::API;
using Mantid::Geometry::IInstrument_sptr;
using Mantid::Geometry::IInstrument;
Logger& SANSRunWindow::g_log = Logger::get("SANSRunWindow");
//----------------------------------------------
//----------------------------------------------
///Constructor
SANSRunWindow::SANSRunWindow(QWidget *parent) :
  UserSubWindow(parent), m_addFilesTab(NULL), m_diagnosticsTab(NULL),
  m_saveWorkspaces(NULL), m_ins_defdir(""), m_last_dir(""),
  m_cfg_loaded(true), m_userFname(false), m_sample_file(), m_run_no_boxes(),
  m_warnings_issued(false), m_force_reload(false),
  m_log_warnings(false), m_newInDir(*this, &SANSRunWindow::handleInputDirChange),
  m_delete_observer(*this, &SANSRunWindow::handleMantidDeleteWorkspace),
  m_s2d_detlabels(), m_loq_detlabels(), m_allowed_batchtags(), m_lastreducetype(-1),
  m_have_reducemodule(false), m_dirty_batch_grid(false), m_tmp_batchfile("")
  ConfigService::Instance().addObserver(m_newInDir);
    ConfigService::Instance().removeObserver(m_newInDir);
    if( isInitialized() )
    {
      // Seems to crash on destruction of if I don't do this 
      AnalysisDataService::Instance().notificationCenter.removeObserver(m_delete_observer);
      saveSettings();
      delete m_addFilesTab;
    }
    //we've cleaned up the best we can, move on
//--------------------------------------------
//--------------------------------------------
  g_log.debug("Initializing interface layout");
  m_uiForm.setupUi(this);

  m_reducemapper = new QSignalMapper(this);

  //Set column stretch on the mask table
  m_uiForm.mask_table->horizontalHeader()->setStretchLastSection(true);

  m_uiForm.tabWidget->setCurrentWidget(m_uiForm.runNumbers);
  // Disable most things so that load is the only thing that can be done
  m_uiForm.oneDBtn->setEnabled(false);
  m_uiForm.twoDBtn->setEnabled(false);
  m_uiForm.saveDefault_btn->setEnabled(false);
  for( int i = 1; i < 4; ++i)
  {
    m_uiForm.tabWidget->setTabEnabled(i, false);
  }

  //Mode switches
  connect(m_uiForm.single_mode_btn, SIGNAL(clicked()),this,SLOT(switchMode()));
  connect(m_uiForm.batch_mode_btn, SIGNAL(clicked()), this,SLOT(switchMode()));

  //Set a custom context menu for the batch table
  m_uiForm.batch_table->setContextMenuPolicy(Qt::ActionsContextMenu);
  m_batch_paste = new QAction(tr("&Paste"),m_uiForm.batch_table);
  m_batch_paste->setShortcut(tr("Ctrl+P"));
  connect(m_batch_paste, SIGNAL(activated()), this, SLOT(pasteToBatchTable()));
  m_uiForm.batch_table->addAction(m_batch_paste);

  m_batch_clear = new QAction(tr("&Clear"),m_uiForm.batch_table);    
  m_uiForm.batch_table->addAction(m_batch_clear);
  connect(m_batch_clear, SIGNAL(activated()), this, SLOT(clearBatchTable()));

  //Logging
  connect(this, SIGNAL(logMessageReceived(const QString&)), this, SLOT(updateLogWindow(const QString&)));
  connect(m_uiForm.logger_clear, SIGNAL(clicked()), this, SLOT(clearLogger()));
  m_uiForm.logging_field->ensureCursorVisible();

  //Create the widget hash maps
  initWidgetMaps();

  m_runFiles.reserve(6);
  //Text edit map
  m_runFiles.push_back(m_uiForm.scatterSample);
  m_runFiles.push_back(m_uiForm.scatCan);

  m_runFiles.push_back(m_uiForm.transmis);
  m_runFiles.push_back(m_uiForm.transCan);

  m_runFiles.push_back(m_uiForm.direct);
  m_runFiles.push_back(m_uiForm.dirCan);
  std::vector<MWRunFiles *>::const_iterator it = m_runFiles.begin();
  for ( ; it != m_runFiles.end(); ++it )
  {
    (*it)->doButtonOpt(MWRunFiles::Icon);
  }

  initAnalysDetTab();

  if( ! m_addFilesTab )
  {//sets up the AddFiles tab which must be deleted in the destructor
    m_addFilesTab = new SANSAddFiles(this, &m_uiForm);
  } 
  //diagnostics tab
  if(!m_diagnosticsTab)
  {
    m_diagnosticsTab = new SANSDiagnostics(this,&m_uiForm);
  connect(this,SIGNAL(userfileLoaded()),m_diagnosticsTab,SLOT(enableMaskFileControls()));
  AnalysisDataService::Instance().notificationCenter.addObserver(m_delete_observer);
  // Default transmission switch
  connect(m_uiForm.transFit_ck, SIGNAL(stateChanged(int)), this, SLOT(updateTransInfo(int)));
  updateTransInfo(m_uiForm.transFit_ck->state());

  readSettings();
}

void SANSRunWindow::initAnalysDetTab()
{
  //Add shortened forms of step types to step boxes
  m_uiForm.q_dq_opt->setItemData(0, "LIN");
  m_uiForm.q_dq_opt->setItemData(1, "LOG");
  m_uiForm.qy_dqy_opt->setItemData(0, "LIN");
//remove the following two lines once the beamfinder is in the new framework
  m_uiForm.wav_dw_opt->setItemData(0, "LIN");
  m_uiForm.wav_dw_opt->setItemData(1, "LOG");

  //the file widget always has a *.* filter, passing an empty list means we get only that
  m_uiForm.floodFile->setAlgorithmProperty("CorrectToFile|Filename");
  m_uiForm.floodFile->isOptional(true);

  //the unicode code for the angstrom symbol is 197, doing the below keeps this file ASCII compatible
  static const QChar ANGSROM_SYM(197);
  m_uiForm.wavlength_lb->setText(QString("Wavelength (%1)").arg(ANGSROM_SYM));
  m_uiForm.qx_lb->setText(QString("Qx (%1^-1)").arg(ANGSROM_SYM));
  m_uiForm.qxy_lb->setText(QString("Qxy (%1^-1)").arg(ANGSROM_SYM));
  m_uiForm.transFit_ck->setText(QString("Trans Fit (%1)").arg(ANGSROM_SYM));
  AnalysisDataService::Instance().notificationCenter.addObserver(m_delete_observer);
  makeValidator(m_uiForm.wavRanVal_lb, m_uiForm.wavRanges, m_uiForm.tab_2,
             "A comma separated list of numbers is required here");
  connect(m_uiForm.wavRanges, SIGNAL(editingFinished()),
                                    this, SLOT(checkList()));
}
/** Formats a Qlabel to be a validator and adds it to the list
*  @param newValid :: a QLabel to use as a validator
*  @param control :: the control whose entry the validator is validates
*  @param tab :: the tab that contains this widgets
*  @param errorMsg :: the tooltip message that the validator should have
*/
void SANSRunWindow::makeValidator(QLabel * const newValid, QWidget * control, QWidget * tab, const QString & errorMsg)
{
  QPalette pal = newValid->palette();
  pal.setColor(QPalette::WindowText, Qt::darkRed);
  newValid->setPalette(pal);
  newValid->setToolTip(errorMsg);
  // regester the validator       and say      where it's control is
  m_validators[newValid] = std::pair<QWidget *, QWidget *>(control, tab);
}

/**
 * Run local Python initialization code
 */
void SANSRunWindow::initLocalPython()
{
  // Import the SANS module and set the correct instrument
  QString result = runPythonCode("try:\n\timport isis_reducer\nexcept (ImportError,SyntaxError), details:\tprint 'Error importing isis_reducer: ' + str(details)\n");
  if( result.trimmed().isEmpty() )
  {
    m_have_reducemodule = true;
  }
  else
  {
    showInformationBox(result);
    m_have_reducemodule = false;
    setProcessingState(true, -1);    
  }
  runPythonCode("import ISISCommandInterface as i\nimport copy");
  runPythonCode("import isis_instrument\nimport isis_reduction_steps");
/** Initialise some of the data and signal connections in the save box
*/
void SANSRunWindow::setupSaveBox()
{
  connect(m_uiForm.saveDefault_btn, SIGNAL(clicked()), this, SLOT(handleDefSaveClick()));
  connect(m_uiForm.saveSel_btn, SIGNAL(clicked()),
    this, SLOT(saveWorkspacesDialog()));
  connect(m_uiForm.saveFilename_btn, SIGNAL(clicked()),
    this, SLOT(saveFileBrowse()));
  connect(m_uiForm.outfile_edit, SIGNAL(textEdited(const QString &)),
    this, SLOT(setUserFname()));

  //link the save option tick boxes to their save algorithm
  m_savFormats.insert(m_uiForm.saveNex_check, "SaveNexus");
  m_savFormats.insert(m_uiForm.saveCan_check, "SaveCanSAS1D");
  m_savFormats.insert(m_uiForm.saveRKH_check, "SaveRKH");
  m_savFormats.insert(m_uiForm.saveCSV_check, "SaveCSV");

  for(SavFormatsConstIt i=m_savFormats.begin(); i != m_savFormats.end(); ++i)
  {
    connect(i.key(), SIGNAL(stateChanged(int)),
      this, SLOT(enableOrDisableDefaultSave()));
  }
}
/** Raises a saveWorkspaces dialog which allows people to save any workspace or
*  workspaces the user chooses
*/
void SANSRunWindow::saveWorkspacesDialog()
{
  //this dialog must have delete on close selected to aviod a memory leak
  m_saveWorkspaces =
    new SaveWorkspaces(this, m_uiForm.outfile_edit->text(), m_savFormats);
  //this dialog sometimes needs to run Python, pass this to Mantidplot via our runAsPythonScript() signal
  connect(m_saveWorkspaces, SIGNAL(runAsPythonScript(const QString&)),
    this, SIGNAL(runAsPythonScript(const QString&)));
  //we need know if we have a pointer to a valid window or not
  connect(m_saveWorkspaces, SIGNAL(closing()),
    this, SLOT(saveWorkspacesClosed()));
  m_saveWorkspaces->show();
}
/**When the save workspaces dialog box is closes its pointer, m_saveWorkspaces,
* is set to NULL and the raise dialog button is re-enabled
*/
void SANSRunWindow::saveWorkspacesClosed()
{
  m_uiForm.saveSel_btn->setEnabled(true);
  m_saveWorkspaces = NULL;
}
/** Connection the buttons to their signals
*/
void SANSRunWindow::connectButtonSignals()
{
  connect(m_uiForm.data_dirBtn, SIGNAL(clicked()), this, SLOT(selectDataDir()));
  connect(m_uiForm.userfileBtn, SIGNAL(clicked()), this, SLOT(selectUserFile()));
  connect(m_uiForm.csv_browse_btn,SIGNAL(clicked()), this, SLOT(selectCSVFile()));

  connect(m_uiForm.load_dataBtn, SIGNAL(clicked()), this, SLOT(handleLoadButtonClick()));
  connect(m_uiForm.runcentreBtn, SIGNAL(clicked()), this, SLOT(handleRunFindCentre()));

  // Reduction buttons
  connect(m_uiForm.oneDBtn, SIGNAL(clicked()), m_reducemapper, SLOT(map()));
  m_reducemapper->setMapping(m_uiForm.oneDBtn, "1D");
  connect(m_uiForm.twoDBtn, SIGNAL(clicked()), m_reducemapper, SLOT(map()));
  m_reducemapper->setMapping(m_uiForm.twoDBtn, "2D");
  connect(m_reducemapper, SIGNAL(mapped(const QString &)), this, SLOT(handleReduceButtonClick(const QString &)));
    
  connect(m_uiForm.showMaskBtn, SIGNAL(clicked()), this, SLOT(handleShowMaskButtonClick()));
  connect(m_uiForm.clear_log, SIGNAL(clicked()), m_uiForm.centre_logging, SLOT(clear()));
}
/** Connect signals from the textChanged() signal from text boxes, index changed
*  on ComboBoxes etc.
*/
void SANSRunWindow::connectChangeSignals()
{
  //Connect each box's edited signal to flag if the box's text has changed
  {
    connect(m_run_no_boxes.value(idx), SIGNAL(textEdited(const QString&)), this, SLOT(runChanged()));
  }

  connect(m_uiForm.smpl_offset, SIGNAL(textEdited(const QString&)), this, SLOT(runChanged()));
  connect(m_uiForm.outfile_edit, SIGNAL(textEdited(const QString&)),
    this, SLOT(enableOrDisableDefaultSave()));
  connect(m_uiForm.allowPeriods_ck, SIGNAL(stateChanged(int)), this,
    SLOT(disOrEnablePeriods(const int)));

  //controls on the second page
  connect(m_uiForm.wav_dw_opt, SIGNAL(currentIndexChanged(int)), this, 
  connect(m_uiForm.q_dq_opt, SIGNAL(currentIndexChanged(int)), this, 
    SLOT(handleStepComboChange(int)));
  connect(m_uiForm.qy_dqy_opt, SIGNAL(currentIndexChanged(int)), this, 
    SLOT(handleStepComboChange(int)));

  connect(m_uiForm.inst_opt, SIGNAL(currentIndexChanged(int)), this, 
  connect(m_uiForm.enableFlood_ck, SIGNAL(stateChanged(int)), this, SLOT(prepareFlood(int)));
/**
 * Initialize the widget maps
 */
void SANSRunWindow::initWidgetMaps()
{
  //       batch mode settings
  m_allowed_batchtags.insert("sample_sans",0);
  m_allowed_batchtags.insert("sample_trans",1);
  m_allowed_batchtags.insert("sample_direct_beam",2);
  m_allowed_batchtags.insert("can_sans",3);
  m_allowed_batchtags.insert("can_trans",4);
  m_allowed_batchtags.insert("can_direct_beam",5);
  m_allowed_batchtags.insert("background_sans",-1);
  m_allowed_batchtags.insert("background_trans",-1);
  m_allowed_batchtags.insert("background_direct_beam",-1);
  m_allowed_batchtags.insert("output_as",6);

  //            detector info  
  // SANS2D det names/label map
    QHash<QString, QLabel*> labelsmap;
    labelsmap.insert("Front_Det_Z", m_uiForm.dist_smp_frontZ);
    labelsmap.insert("Front_Det_X", m_uiForm.dist_smp_frontX);
    labelsmap.insert("Front_Det_Rot", m_uiForm.smp_rot);
    labelsmap.insert("Rear_Det_X", m_uiForm.dist_smp_rearX);
    labelsmap.insert("Rear_Det_Z", m_uiForm.dist_smp_rearZ);
    m_s2d_detlabels.append(labelsmap);
  
    labelsmap.clear();
    labelsmap.insert("Front_Det_Z", m_uiForm.dist_can_frontZ);
    labelsmap.insert("Front_Det_X", m_uiForm.dist_can_frontX);
    labelsmap.insert("Front_Det_Rot", m_uiForm.can_rot);
    labelsmap.insert("Rear_Det_X", m_uiForm.dist_can_rearX);
    labelsmap.insert("Rear_Det_Z", m_uiForm.dist_can_rearZ);
    m_s2d_detlabels.append(labelsmap);

    labelsmap.clear();
    labelsmap.insert("Front_Det_Z", m_uiForm.dist_bkgd_frontZ);
    labelsmap.insert("Front_Det_X", m_uiForm.dist_bkgd_frontX);
    labelsmap.insert("Front_Det_Rot", m_uiForm.bkgd_rot);
    labelsmap.insert("Rear_Det_X", m_uiForm.dist_bkgd_rearX);
    labelsmap.insert("Rear_Det_Z", m_uiForm.dist_bkgd_rearZ);
    m_s2d_detlabels.append(labelsmap);

    //LOQ labels
    labelsmap.clear();
    labelsmap.insert("moderator-sample", m_uiForm.dist_sample_ms);
    labelsmap.insert("sample-main-detector-bank", m_uiForm.dist_smp_mdb);
    labelsmap.insert("sample-HAB",m_uiForm.dist_smp_hab);
    m_loq_detlabels.append(labelsmap);
  
    labelsmap.clear();
    labelsmap.insert("moderator-sample", m_uiForm.dist_can_ms);
    labelsmap.insert("sample-main-detector-bank", m_uiForm.dist_can_mdb);
    labelsmap.insert("sample-HAB",m_uiForm.dist_can_hab);
    m_loq_detlabels.append(labelsmap);

    labelsmap.clear();
    labelsmap.insert("moderator-sample", m_uiForm.dist_bkgd_ms);
    labelsmap.insert("sample-main-detector-bank", m_uiForm.dist_bkgd_mdb);
    labelsmap.insert("sample-HAB", m_uiForm.dist_bkgd_hab);
    m_loq_detlabels.append(labelsmap);

    // Full workspace names as they appear in the service

/**
 * Restore previous input
 */
void SANSRunWindow::readSettings()
{
  QSettings value_store;
  value_store.beginGroup("CustomInterfaces/SANSRunWindow");
  m_uiForm.userfile_edit->setText(value_store.value("user_file").toString());
  m_last_dir = value_store.value("last_dir", "").toString();

  int index = m_uiForm.inst_opt->findText(
                              value_store.value("instrum", "LOQ").toString());
  // if the saved instrument no longer exists set index to zero
  index = index < 0 ? 0 : index;
  m_uiForm.inst_opt->setCurrentIndex(index);
  int mode_flag = value_store.value("runmode", 0).toInt();
  if( mode_flag == SANSRunWindow::SingleMode )
  {
    m_uiForm.single_mode_btn->click();
  }
  else
  {
    m_uiForm.batch_mode_btn->click();
  }

  m_ins_defdir = QString::fromStdString(
    ConfigService::Instance().getString("instrumentDefinition.directory"));
  upDateDataDir();
  // Set allowed extensions
  m_uiForm.file_opt->clear();
  m_uiForm.file_opt->addItem("nexus", QVariant(".nxs"));
  m_uiForm.file_opt->addItem("raw", QVariant(".raw"));
  //Set old file extension
  m_uiForm.file_opt->setCurrentIndex(value_store.value("fileextension", 0).toInt());
  
  m_uiForm.allowPeriods_ck->setChecked(
                   value_store.value("allow_periods",false).toBool());
  int i = m_uiForm.wav_dw_opt->findText(
    value_store.value("wave_binning", "Linear").toString());
  i = i > -1 ? i : 0;
  m_uiForm.wav_dw_opt->setCurrentIndex(i);
  //ensure this is called once even if the index hadn't changed
  handleWavComboChange(i);

  g_log.debug() << "Found previous data directory " << "\nFound previous user mask file "
    << m_uiForm.userfile_edit->text().toStdString()
    << "\nFound instrument definition directory " << m_ins_defdir.toStdString() << std::endl;

}
/** Sets the states of the checkboxes in the save box using those
* in the passed QSettings object
*  @param valueStore :: where the settings will be stored
*/
void SANSRunWindow::readSaveSettings(QSettings & valueStore)
{
  valueStore.beginGroup("CustomInterfaces/SANSRunWindow/SaveOutput");
  m_uiForm.saveNex_check->setChecked(valueStore.value("nexus",false).toBool());
  m_uiForm.saveCan_check->setChecked(valueStore.value("canSAS",false).toBool());
  m_uiForm.saveRKH_check->setChecked(valueStore.value("RKH", false).toBool());
  m_uiForm.saveCSV_check->setChecked(valueStore.value("CSV", false).toBool());
 * Save input through QSettings (-> .mantidplot or -> windows registerary) for future use
 */
void SANSRunWindow::saveSettings()
{
  QSettings value_store;
  value_store.beginGroup("CustomInterfaces/SANSRunWindow");
  if( !m_uiForm.userfile_edit->text().isEmpty() ) 
  {
    value_store.setValue("user_file", m_uiForm.userfile_edit->text());
  }
  value_store.setValue("instrum", m_uiForm.inst_opt->currentText());
  value_store.setValue("fileextension", m_uiForm.file_opt->currentIndex());
  value_store.setValue("allow_periods", m_uiForm.allowPeriods_ck->isChecked());
  value_store.setValue("wave_binning", m_uiForm.wav_dw_opt->currentText());

  unsigned int mode_id(0);
  if( m_uiForm.single_mode_btn->isChecked() )
  {
    mode_id = SANSRunWindow::SingleMode;
  }
  else
  {
    mode_id = SANSRunWindow::BatchMode;
  }
  value_store.setValue("runmode",mode_id);
  saveSaveSettings(value_store);
}
/** Stores the state of the checkboxes in the save box with the
* passed QSettings object
*  @param valueStore :: where the settings will be stored
*/
void SANSRunWindow::saveSaveSettings(QSettings & valueStore)
{
  valueStore.beginGroup("CustomInterfaces/SANSRunWindow/SaveOutput");
  valueStore.setValue("nexus", m_uiForm.saveNex_check->isChecked());
  valueStore.setValue("canSAS", m_uiForm.saveCan_check->isChecked());
  valueStore.setValue("RKH", m_uiForm.saveRKH_check->isChecked());
  valueStore.setValue("CSV", m_uiForm.saveCSV_check->isChecked());
/**
 * Run a function from the SANS reduction script, ensuring that the first call imports the module
 * @returns A trimmed string containing the output of the code execution
 */
QString SANSRunWindow::runReduceScriptFunction(const QString & pycode)
{
  if( !m_have_reducemodule )
  {
  g_log.debug() << "Executing Python: " << pycode.toStdString() << std::endl;

  const static QString PYTHON_SEP("C++runReduceScriptFunctionC++");
  QString code_torun =  pycode + ";print '"+PYTHON_SEP+"p'";
  QString pythonOut = runPythonCode(code_torun).trimmed();
  
  QStringList allOutput = pythonOut.split(PYTHON_SEP);

  if ( allOutput.count() < 2 )
  {
    QMessageBox::critical(this, "Fatal error found during reduction", "Error reported by Python script, more information maybe found in the scripting console and results log");
}

/**
 * Trim off Python markers surrounding things like strings or lists that have been 
 * printed by Python
 */
void SANSRunWindow::trimPyMarkers(QString & txt)
{
 txt.remove(0,1);
 txt.chop(1);
}
/** Issues a Python command to load the user file and returns any output if
*  there are warnings or errors
*  @param[out] errors the output produced by the string
*  @return the output printed by the Python commands
*/
bool SANSRunWindow::loadUserFile()
{
  QString filetext = m_uiForm.userfile_edit->text().trimmed();
    QMessageBox::critical(this, "Error loading user file", "No user file has been specified");
  if( !user_file.open(QIODevice::ReadOnly) )
  {
    QMessageBox::critical(this, "Error loading user file", "Could not open user file \""+filetext+"\"");

  user_file.close();
  
  //Clear the def masking info table.
  int mask_table_count = m_uiForm.mask_table->rowCount();
  for( int i = mask_table_count - 1; i >= 0; --i )
  {
    m_uiForm.mask_table->removeRow(i);
  }
  
  QString pyCode = "i.ReductionSingleton.clean(isis_reducer.ISISReducer)";
  pyCode += "\ni.ReductionSingleton().set_instrument(isis_instrument.";
  pyCode += getInstrumentClass()+")";
  pyCode += "\ni.ReductionSingleton().user_settings =";
  // Use python function to read the settings file and then extract the fields
  pyCode += "isis_reduction_steps.UserFile(r'"+filetext+"')";
  QString errors = runReduceScriptFunction(
    "print i.ReductionSingleton().user_settings.execute(i.ReductionSingleton())").trimmed();
  // create a string list with a string for each line
  const QStringList allOutput = errors.split("\n");
  errors.clear();
  bool canContinue = false;
  for (int i = 0; i < allOutput.count(); ++i)
  {
    if ( i < allOutput.count()-1 )
    {
      errors += allOutput[i]+"\n";
    }
    else
    {
      canContinue = allOutput[i].trimmed() == "True";
    }
  }

  if ( ! canContinue )
  // Radius
  double dbl_param = runReduceScriptFunction(
      "print i.ReductionSingleton().mask.min_radius").toDouble();
  m_uiForm.rad_min->setText(QString::number(dbl_param*unit_conv));
  dbl_param = runReduceScriptFunction(
      "print i.ReductionSingleton().mask.max_radius").toDouble();
  m_uiForm.rad_max->setText(QString::number(dbl_param*unit_conv));
  //Wavelength
  m_uiForm.wav_min->setText(runReduceScriptFunction(
      "print i.ReductionSingleton().to_wavelen.wav_low"));
  m_uiForm.wav_max->setText(runReduceScriptFunction(
      "print i.ReductionSingleton().to_wavelen.wav_high").trimmed());
  const QString wav_step = runReduceScriptFunction(
      "print i.ReductionSingleton().to_wavelen.wav_step").trimmed();
  setLimitStepParameter("wavelength", wav_step, m_uiForm.wav_dw,
                        m_uiForm.wav_dw_opt);
  //Q
  QString text = runReduceScriptFunction(
      "print i.ReductionSingleton().Q_REBIN");
  QStringList values = text.split(",");
  if( values.count() == 3 )
  {
    m_uiForm.q_min->setText(values[0].trimmed());
    m_uiForm.q_max->setText(values[2].trimmed());
    setLimitStepParameter("Q", values[1].trimmed(), m_uiForm.q_dq,
        m_uiForm.q_dq_opt);
  }
  else
  {
    m_uiForm.q_rebin->setText(text.trimmed());
    m_uiForm.q_dq_opt->setCurrentIndex(2);
  }
  //Qxy
  m_uiForm.qy_max->setText(runReduceScriptFunction(
  setLimitStepParameter("Qxy", runReduceScriptFunction(
      "print i.ReductionSingleton().DQXY"), m_uiForm.qy_dqy,
  // The tramission line of the Limits section 
  QString transMin = runReduceScriptFunction(
      "print i.ReductionSingleton().transmission_calculator.lambda_min").trimmed();
  if (transMin == "None")
  {
    m_uiForm.transFit_ck->setChecked(false);
  }
  else
  {
    m_uiForm.transFit_ck->setChecked(true);
    m_uiForm.trans_min->setText(transMin);
    m_uiForm.trans_max->setText(runReduceScriptFunction(
      "print i.ReductionSingleton().transmission_calculator.lambda_max").trimmed());
  }
      "print i.ReductionSingleton().transmission_calculator.fit_method").trimmed();
  int index = m_uiForm.trans_opt->findText(text, Qt::MatchCaseSensitive);
  if( index >= 0 )
  {
    m_uiForm.trans_opt->setCurrentIndex(index);
  }

  //Monitor spectra
  m_uiForm.monitor_spec->setText(runReduceScriptFunction(
    "print i.ReductionSingleton().instrument.get_incident_mon()").trimmed());
  m_uiForm.trans_monitor->setText(runReduceScriptFunction(
    "print i.ReductionSingleton().instrument.incid_mon_4_trans_calc").trimmed());
  m_uiForm.monitor_interp->setChecked(runReduceScriptFunction(
    "print i.ReductionSingleton().instrument.is_interpolating_norm()").trimmed() == "True");
  m_uiForm.trans_interp->setChecked(runReduceScriptFunction(
    "print i.ReductionSingleton().transmission_calculator.interpolate"
    ).trimmed() == "True");

  //Direct efficiency correction
  m_uiForm.direct_file->setText(runReduceScriptFunction(
    "print i.ReductionSingleton().instrument.detector_file('rear')"));
  m_uiForm.front_direct_file->setText(runReduceScriptFunction(
    "print i.ReductionSingleton().instrument.detector_file('front')"));
    "print i.ReductionSingleton().flood_file.get_filename()");
  //Check if the file name is set to Python's None object and then adjust the controls if there is an empty entry
  m_uiForm.floodFile->setFileText(file == "None" ? "" : file);
  m_uiForm.enableFlood_ck->setChecked( ! m_uiForm.floodFile->isEmpty() );
  prepareFlood(m_uiForm.enableFlood_ck->checkState());

  //Scale factor
  dbl_param = runReduceScriptFunction(
    "print i.ReductionSingleton()._corr_and_scale.rescale").toDouble();
  m_uiForm.scale_factor->setText(QString::number(dbl_param/100.));

  //Sample offset if one has been specified
  dbl_param = runReduceScriptFunction(
    "print i.ReductionSingleton().instrument.SAMPLE_Z_CORR").toDouble();
  m_uiForm.smpl_offset->setText(QString::number(dbl_param*unit_conv));

  //Centre coordinates
  dbl_param = runReduceScriptFunction(
    "print i.ReductionSingleton()._beam_finder.get_beam_center()[0]").toDouble();
  m_uiForm.beam_x->setText(QString::number(dbl_param*1000.0));
  dbl_param = runReduceScriptFunction(
    "print i.ReductionSingleton()._beam_finder.get_beam_center()[1]").toDouble();
  m_uiForm.beam_y->setText(QString::number(dbl_param*1000.0));

  //Gravity switch
  QString param = runReduceScriptFunction(
    "print i.ReductionSingleton().to_Q.get_gravity()").trimmed();
  if( param == "True" )
  {
    m_uiForm.gravity_check->setChecked(true);
  }
  else
  {
    m_uiForm.gravity_check->setChecked(false);
  }
  
  ////Detector bank
  QString detName = runReduceScriptFunction(
    "print i.ReductionSingleton().instrument.cur_detector().name()").trimmed();
  index = m_uiForm.detbank_sel->findText(detName);  
  if( index >= 0 && index < 2 )
  {
    m_uiForm.detbank_sel->setCurrentIndex(index);
  }

  m_uiForm.phi_min->setText(runReduceScriptFunction(
    "print i.ReductionSingleton().mask.phi_min"));
  m_uiForm.phi_max->setText(runReduceScriptFunction(
    "print i.ReductionSingleton().mask.phi_max"));
    "print i.ReductionSingleton().mask.phi_mirror").trimmed() == "True" )
  {
    m_uiForm.mirror_phi->setChecked(true);
  }
  else
  {
    m_uiForm.mirror_phi->setChecked(false);
  }

  if ( ! errors.isEmpty() )
  {
    showInformationBox("User file opened with some warnings:\n"+errors);
  }

  m_cfg_loaded = true;
  m_uiForm.userfileBtn->setText("Reload");
  m_uiForm.tabWidget->setTabEnabled(m_uiForm.tabWidget->count() - 1, true);
  
  //Check for warnings
  checkLogFlags();

  m_cfg_loaded = true;
  emit userfileLoaded();
  m_uiForm.tabWidget->setTabEnabled(1, true);
  m_uiForm.tabWidget->setTabEnabled(2, true);
  m_uiForm.tabWidget->setTabEnabled(3, true);
  

/**
 * Load a CSV file specifying information run numbers and populate the batch mode grid
 */
bool SANSRunWindow::loadCSVFile()
{
  QString filename = m_uiForm.csv_filename->text(); 
  QFile csv_file(filename);
  if( !csv_file.open(QIODevice::ReadOnly | QIODevice::Text) )
  {
    showInformationBox("Error: Cannot open CSV file \"" + filename + "\"");
    return false;
  }
  
  //Clear the current table
  clearBatchTable();
  QTextStream file_in(&csv_file);
  int errors(0);
  while( !file_in.atEnd() )
  {
    QString line = file_in.readLine().simplified();
    if( !line.isEmpty() )
    {
      errors += addBatchLine(line, ",");
    }
  }
  if( errors > 0 )
  {
    showInformationBox("Warning: " + QString::number(errors) + " malformed lines detected in \"" + filename + "\". Lines skipped.");
  }
 * Set a pair of an QLineEdit field and type QComboBox using the parameter given
 * @param pname :: The name of the parameter
 * @param param :: A string representing a value that maybe prefixed with a minus to indicate a different step type
 * @param step_value :: The field to store the actual value
 * @param step_type :: The combo box with the type options
void SANSRunWindow::setLimitStepParameter(const QString& pname, QString param, QLineEdit* step_value, QComboBox* step_type)
    int index = step_type->findText("Logarithmic");
    if( index < 0 )
    {
     raiseOneTimeMessage("Warning: Unable to find logarithmic scale option for " + pname + ", setting as linear.", 1);
     index = step_type->findText("Linear");
    }
    step_type->setCurrentIndex(index);
    step_value->setText(param.remove(0,1));
    step_type->setCurrentIndex(step_type->findText("Linear"));
    step_value->setText(param);
  }
}

/**
 * Construct the mask table on the Mask tab 
 */
void SANSRunWindow::updateMaskTable()
{
  //Clear the current contents
  for( int i = m_uiForm.mask_table->rowCount() - 1; i >= 0; --i )
  {
	  m_uiForm.mask_table->removeRow(i);

  QString reardet_name("rear-detector"), frontdet_name("front-detector");
  if( m_uiForm.inst_opt->currentText() == "LOQ" )
  {
    reardet_name = "main-detector-bank";
    frontdet_name = "HAB";
  }
  
  // First create 2 default mask cylinders at min and max radius for the beam stop and 
  // corners
  m_uiForm.mask_table->insertRow(0);
  m_uiForm.mask_table->setItem(0, 0, new QTableWidgetItem("beam stop"));
  m_uiForm.mask_table->setItem(0, 1, new QTableWidgetItem(reardet_name));
  m_uiForm.mask_table->setItem(0, 2, new QTableWidgetItem("infinite-cylinder, r = rmin"));
  if( m_uiForm.rad_max->text() != "-1" )
  {  
    m_uiForm.mask_table->insertRow(1);
    m_uiForm.mask_table->setItem(1, 0, new QTableWidgetItem("corners"));
    m_uiForm.mask_table->setItem(1, 1, new QTableWidgetItem(reardet_name));
    m_uiForm.mask_table->setItem(1, 2, new QTableWidgetItem("infinite-cylinder, r = rmax"));
  //Spectrum mask, "Rear" det
  QString mask_string = runReduceScriptFunction(
      "print i.ReductionSingleton().mask.spec_mask_r");
  addSpectrumMasksToTable(mask_string, reardet_name);
  //"Front" det
      "print i.ReductionSingleton().mask.spec_mask_f");
  addSpectrumMasksToTable(mask_string, frontdet_name);

  //Time masks
      "print i.ReductionSingleton().mask.time_mask");
  addTimeMasksToTable(mask_string, "-");
  //Rear detector
      "print i.ReductionSingleton().mask.time_mask_r");
  addTimeMasksToTable(mask_string, reardet_name);
  //Front detectors
      "print i.ReductionSingleton().mask.time_mask_f");
  addTimeMasksToTable(mask_string, frontdet_name);
}

/**
 * Add a spectrum mask string to the mask table
 * @param mask_string :: The string of mask information
 * @param det_name :: The detector it relates to 
 */
void SANSRunWindow::addSpectrumMasksToTable(const QString & mask_string, const QString & det_name)
{
  QStringList elements = mask_string.split(",", QString::SkipEmptyParts);
  QStringListIterator sitr(elements);
  while(sitr.hasNext())
  {
    QString item = sitr.next().trimmed();
    QString col1_txt;
    if( item.startsWith('s', Qt::CaseInsensitive) )
    {
      col1_txt = "Spectrum";
    }
    else if( item.startsWith('h', Qt::CaseInsensitive) || item.startsWith('v', Qt::CaseInsensitive) )
    {
      if( item.contains('+') )
      {
        col1_txt = "Box";
      }
      else
      {
        col1_txt = "Strip";
      }
    }
    else continue;

    int row = m_uiForm.mask_table->rowCount();
    //Insert line after last row
    m_uiForm.mask_table->insertRow(row);
    m_uiForm.mask_table->setItem(row, 0, new QTableWidgetItem(col1_txt));
    m_uiForm.mask_table->setItem(row, 1, new QTableWidgetItem(det_name));
    m_uiForm.mask_table->setItem(row, 2, new QTableWidgetItem(item));
 * @param mask_string :: The string of mask information
 * @param det_name :: The detector it relates to 
 */
void SANSRunWindow::addTimeMasksToTable(const QString & mask_string, const QString & det_name)
{
  QStringList elements = mask_string.split(";",QString::SkipEmptyParts);
  QStringListIterator sitr(elements);
    int row = m_uiForm.mask_table->rowCount();
    m_uiForm.mask_table->insertRow(row);
    m_uiForm.mask_table->setItem(row, 0, new QTableWidgetItem("time"));
    m_uiForm.mask_table->setItem(row, 1, new QTableWidgetItem(det_name));
    const QString shape(sitr.next().trimmed());
    m_uiForm.mask_table->setItem(row, 2, new QTableWidgetItem(shape));
 * @param workspace :: The workspace pointer
 * @param lms :: The result of the moderator-sample distance
 * @param lsda :: The result of the sample-detector bank 1 distance
 * @param lsdb :: The result of the sample-detector bank 2 distance
void SANSRunWindow::componentLOQDistances(Mantid::API::MatrixWorkspace_sptr workspace, double & lms, double & lsda, double & lsdb)
  IInstrument_sptr instr = workspace->getInstrument();
  if( instr == boost::shared_ptr<IInstrument>() ) return;