Mantid
Loading...
Searching...
No Matches
LoadDialog.cpp
Go to the documentation of this file.
1// Mantid Repository : https://github.com/mantidproject/mantid
2//
3// Copyright © 2018 ISIS Rutherford Appleton Laboratory UKRI,
4// NScD Oak Ridge National Laboratory, European Spallation Source,
5// Institut Laue - Langevin & CSNS, Institute of High Energy Physics, CAS
6// SPDX - License - Identifier: GPL - 3.0 +
7//------------------------------------------------------------------------------
8// Includes
9//------------------------------------------------------------------------------
13// Qt
14#include <QCheckBox>
15#include <QComboBox>
16#include <QFileInfo>
17#include <QScreen>
18#include <QUrl>
19
20// Mantid
27
28using namespace Mantid::API;
29using namespace Mantid::Kernel;
31
33namespace {
36struct HoldFlag {
37 HoldFlag(bool &current, const bool holdValue) : initial(current), heldflag(current) { heldflag = holdValue; }
38 ~HoldFlag() { heldflag = initial; }
39 bool initial;
40 bool &heldflag;
41};
42} // namespace
43
44// Declare the dialog. Name must match the class name
45DECLARE_DIALOG(LoadDialog)
46
47//--------------------------------------------------------------------------
48// Public methods
49//---------------------------------------------------------------------------
50
51
52LoadDialog::LoadDialog(QWidget *parent)
53 : API::AlgorithmDialog(parent), m_form(), m_currentFiles(), m_initialHeight(0), m_populating(false),
54 m_userAccept(false) {
55 // We will handle parsing the input ourselves on startup
56 m_autoParseOnInit = false;
57}
58
59//--------------------------------------------------------------------------
60// Private methods (slot)
61//---------------------------------------------------------------------------
62
67 HoldFlag hold(m_populating, true);
68
69 m_form.fileWidget->blockSignals(true);
71 m_form.fileWidget->blockSignals(false);
72}
73
76 const auto loaderName = getAlgorithm()->getPropertyValue("LoaderName");
77 QString helpPage = (loaderName.empty()) ? QString("Load") : QString::fromStdString(loaderName);
79}
80
87 if (!m_form.workspaceEdit->isEnabled())
88 return;
89
90 // suggest ws name based on file name
91 QString fileSuggestion;
92 if (m_form.fileWidget->isValid()) {
93 if (m_form.fileWidget->getFilenames().size() == 1)
94 fileSuggestion = QFileInfo(m_form.fileWidget->getFirstFilename()).completeBaseName();
95 else
96 fileSuggestion = "MultiFiles";
97 }
98 m_form.workspaceEdit->setText(fileSuggestion);
99}
100
107 if (on) {
108 connect(m_form.fileWidget, SIGNAL(filesFound()), this, SLOT(suggestWSName()));
109 } else {
110 disconnect(m_form.fileWidget, SIGNAL(filesFound()), this, SLOT(suggestWSName()));
111 }
112}
113
118 // If the LoadDialog is already loading data, or is populating, then ignore the accept
119 if (m_form.fileWidget->isSearching() || m_populating) {
120 return;
121 }
122 m_userAccept = true;
123 m_form.fileWidget->findFiles();
124}
125
127 if (!m_userAccept) {
128 return;
129 }
130 m_userAccept = false;
131
132 // Makes it so the dialog is still resizable if it is kept open
133 m_form.propertyLayout->setEnabled(true);
134
135 // Check that the file still exists just incase it somehow got removed
136 std::string errMess = getAlgorithm()->getPointerToProperty("Filename")->isValid();
137 if (!errMess.empty()) {
138 m_currentFiles = "";
140 } else {
141 AlgorithmDialog::accept();
142 }
143}
144
145//--------------------------------------------------------------------------
146// Private methods (non-slot)
147//---------------------------------------------------------------------------
148
151 m_form.setupUi(this);
152
153 // Add the helpful summary message
154 if (isMessageAvailable())
155 m_form.instructions->setText(getOptionalMessage());
156
157 m_form.dialogLayout->addLayout(this->createDefaultButtonLayout());
158 m_form.fileWidget->readSettings("Mantid/Algorithms/Load");
159 m_initialHeight = this->height();
160
161 const std::string &outWsName = getAlgorithm()->getPropertyValue("OutputWorkspace");
162 if (!outWsName.empty()) {
163 // OutputWorkspace name suggestion received as parameter, just take it and
164 // don't change it
165 m_form.workspaceEdit->setText(QString::fromStdString(outWsName));
166 } else {
167 // Guess at an output workspace name but only if the user hasn't changed
168 // anything
170 connect(m_form.workspaceEdit, SIGNAL(textEdited(const QString &)), this, SLOT(enableNameSuggestion()));
171 }
172
173 // Connect the file finder's file found signal to the dynamic property create
174 // method.
175 // When the file text is set the Load algorithm finds the concrete loader and
176 // then we
177 // know what extra properties to create
178 connect(m_form.fileWidget, SIGNAL(filesFound()), this, SLOT(createDynamicWidgets()));
179 connect(m_form.fileWidget, SIGNAL(fileInspectionFinished()), this, SLOT(resultInspectionFinished()));
180
181 tieStaticWidgets(true);
182}
183
188 m_form.fileWidget->saveSettings("Mantid/Algorithms/Load");
189 AlgorithmDialog::saveInput();
190 // Ensure the filename is store as the full file
191 API::AlgorithmInputHistory::Instance().storeNewValue("Load", QPair<QString, QString>("Filename", m_currentFiles));
192}
193
198void LoadDialog::tieStaticWidgets(const bool readHistory) {
199 // If a workspace validator asterisk exists, remove it since the underlying
200 // AlgorithmDialog gets confused
201 if (m_form.workspaceLayout->count() == 3) {
202 QLayoutItem *validLbl = m_form.workspaceLayout->takeAt(2);
203 delete validLbl->widget();
204 delete validLbl;
205 }
206 tie(m_form.workspaceEdit, "OutputWorkspace", m_form.workspaceLayout, readHistory);
207 tie(m_form.fileWidget, "Filename", nullptr, readHistory);
208}
209
214void LoadDialog::removeOldInputWidgets(QVBoxLayout *layout) {
215 // Remove the old widgets if necessary
216 if (layout->count() > 2) {
217 int count = layout->count();
218 while (count > 2) {
219 QLayoutItem *child = layout->takeAt(count - 1);
220 if (QWidget *w = child->widget()) {
221 w->deleteLater();
222 } else if (QLayout *l = child->layout()) {
223 QLayoutItem *subChild(nullptr);
224 while ((subChild = l->takeAt(0)) != nullptr) {
225 subChild->widget()->deleteLater();
226 }
227 }
228 count = layout->count();
229 }
230 }
231}
232
237 // Disable the layout so that a widget cannot be interacted with while it may
238 // be being deleted
239 m_form.propertyLayout->setEnabled(false);
240
241 if (!m_form.fileWidget->isValid())
242 return;
243 // First step is the get the specific loader that is responsible
244 auto loadAlg = getAlgorithm();
245 const QString filenames = m_form.fileWidget->getUserInput().toString();
246 if (filenames == m_currentFiles)
247 return;
248 m_currentFiles = filenames;
249 removeOldInputWidgets(m_form.propertyLayout); // The new file might be invalid
250 try {
251 loadAlg->setPropertyValue("Filename", filenames.toStdString());
252 } catch (std::exception &exc) {
253 m_form.fileWidget->setFileProblem(QString::fromStdString(exc.what()));
254 m_form.propertyLayout->setEnabled(true);
255 m_form.propertyLayout->activate();
256 this->resize(this->width(), m_initialHeight + 15);
257
258 // Reset the algorithm pointer so that the base class re-reads the
259 // properties and drops links from
260 // old widgets meaning they are safe to remove
261 setAlgorithm(loadAlg);
262 tieStaticWidgets(false); // The ties are cleared when resetting the
263 // algorithm
264
265 return;
266 }
267 // Reset the algorithm pointer so that the base class re-reads the properties
268 // and drops links from
269 // old widgets meaning they are safe to remove
270 setAlgorithm(loadAlg);
271 tieStaticWidgets(false); // The ties are cleared when resetting the algorithm
272 // Add the new ones
273 const std::vector<Property *> &inputProps = loadAlg->getProperties();
274 int dialogHeight = m_initialHeight;
275 for (auto prop : inputProps) {
276 const QString propName = QString::fromStdString(prop->name());
277 if (propName == "OutputWorkspace" || propName == "Filename")
278 continue;
279 if (requiresUserInput(propName)) {
280 dialogHeight += createWidgetsForProperty(prop, m_form.propertyLayout, m_form.scrollAreaWidgetContents);
281 }
282 }
283 // Re-enable and recompute the size of the layout
284 m_form.propertyLayout->setEnabled(true);
285 m_form.propertyLayout->activate();
286
287 const auto screenSize = screen()->availableSize();
288 const auto screenGeometry = screen()->availableGeometry();
289 dialogHeight = std::min(dialogHeight, static_cast<int>(screenSize.height() * 0.65));
290 this->resize(this->width(), dialogHeight);
291 const auto xPos = screenGeometry.x() + (screenSize.width() - this->width()) / 2;
292 const auto yPos = screenGeometry.y() + (screenSize.height() - this->height()) / 2;
293 this->move(xPos, yPos);
294
295 // Make sure the OutputWorkspace value has been stored so that the validator
296 // is cleared appropriately
297 QString wsName(m_form.workspaceEdit->text());
298 if (!wsName.isEmpty())
299 storePropertyValue("OutputWorkspace", wsName);
300 setPropertyValues(QStringList("Filename"));
301}
302
309int LoadDialog::createWidgetsForProperty(const Mantid::Kernel::Property *prop, QVBoxLayout *propertyLayout,
310 QWidget *parent) {
311 QString propName = QString::fromStdString(prop->name());
312 QWidget *inputWidget(nullptr);
313 QHBoxLayout *widgetLayout(nullptr);
314 bool addValidator(true);
315
316 // Boolean properties use the name labels differently
317 if (const auto *fileType = dynamic_cast<const FileProperty *>(prop)) {
318 auto *fileFinder = new FileFinderWidget(parent);
319 inputWidget = fileFinder;
320 fileFinder->setLabelText(propName);
321 fileFinder->isForRunFiles(false);
322 fileFinder->isOptional(fileType->isOptional());
323 fileFinder->doMultiEntry(false);
324 addValidator = false;
325 propertyLayout->addWidget(inputWidget);
326 } else {
327 QLabel *nameLbl = new QLabel(propName, parent);
328 nameLbl->setToolTip(QString::fromStdString(prop->documentation()));
329 if (dynamic_cast<const PropertyWithValue<bool> *>(prop)) {
330 auto *checkBox = new QCheckBox(parent);
331 inputWidget = checkBox;
332 addValidator = false;
333 }
334 // Options box
335 else if (!prop->allowedValues().empty()) {
336 auto *optionsBox = new QComboBox(parent);
337 inputWidget = optionsBox;
338 std::vector<std::string> items = prop->allowedValues();
339 std::vector<std::string>::const_iterator vend = items.end();
340 for (std::vector<std::string>::const_iterator vitr = items.begin(); vitr != vend; ++vitr) {
341 optionsBox->addItem(QString::fromStdString(*vitr));
342 }
343 // Set current as visible
344 int index = optionsBox->findText(QString::fromStdString(prop->value()));
345 if (index >= 0)
346 optionsBox->setCurrentIndex(index);
347
348 addValidator = false;
349 }
350 // else render a text box
351 else {
352 auto *textBox = new QLineEdit(parent);
353 inputWidget = textBox;
354 if (dynamic_cast<const MaskedProperty<std::string> *>(prop)) {
355 textBox->setEchoMode(QLineEdit::Password);
356 }
357 }
358 nameLbl->setBuddy(inputWidget);
359 widgetLayout = new QHBoxLayout();
360 widgetLayout->addWidget(nameLbl);
361 widgetLayout->addWidget(inputWidget);
362 propertyLayout->addLayout(widgetLayout);
363 }
364
365 if (addValidator)
366 tie(inputWidget, propName, widgetLayout);
367 else
368 tie(inputWidget, propName, nullptr);
369
370 return inputWidget->geometry().height();
371}
372} // namespace MantidQt::CustomDialogs
#define DECLARE_DIALOG(classname)
double height
Definition GetAllEi.cpp:155
std::map< DeltaEMode::Type, std::string > index
bool initial
bool & heldflag
int count
counter
Definition Matrix.cpp:37
bool isMessageAvailable() const
Is there a message string available.
void setAlgorithm(const Mantid::API::IAlgorithm_sptr &)
The following methods were made public for testing in GenericDialogDemo.cpp.
bool setPropertyValues(const QStringList &skipList=QStringList())
Set properties on this algorithm by pulling values from the tied widgets.
bool requiresUserInput(const QString &propName) const
Return a true if the given property requires user input.
QLayout * createDefaultButtonLayout(const QString &helpText=QString("?"), const QString &loadText=QString("Run"), const QString &cancelText=QString("Close"), const QString &keepOpenText=QString("Keep Open"))
Create a row layout of buttons with specified text.
void storePropertyValue(const QString &name, const QString &value)
Adds a property (name,value) pair to the stored map.
QWidget * tie(QWidget *widget, const QString &property, QLayout *parent_layout=nullptr, bool readHistory=true)
Tie a widget to a property.
Mantid::API::IAlgorithm_sptr getAlgorithm() const
Get the algorithm pointer.
const QString & getOptionalMessage() const
Get the message string.
This class defines a widget for file searching.
static void showAlgorithm(const std::string &name=std::string(), const int version=-1)
This class gives specialised dialog for the Load algorithm.
Definition LoadDialog.h:47
void tieStaticWidgets(const bool readHistory)
Tie static widgets to their properties.
void resultInspectionFinished()
Accept the load dialog when user input is inspected and is valid.
void saveInput() override
Save the input history.
int m_initialHeight
The initial height.
Definition LoadDialog.h:90
int createWidgetsForProperty(const Mantid::Kernel::Property *prop, QVBoxLayout *propertyLayout, QWidget *parent)
Create the widgets for a given property.
void helpClicked() override
Override the help button clicked method.
void enableNameSuggestion(const bool on=false)
Connect/Disconnect the signal that updates the workspace name with a suggested value.
void accept() override
Override accept() slot.
bool m_userAccept
Flag to indicate the user accepted the load dialog.
Definition LoadDialog.h:94
void suggestWSName()
Suggest a workspace name from the file.
void initLayout() override
Initialize the layout.
bool m_populating
Flag to indicating if we are populating the dialog.
Definition LoadDialog.h:92
void createDynamicWidgets()
Create the widgets and layouts that are dynamic, i.e they depend on the specific load algorithm.
void removeOldInputWidgets(QVBoxLayout *layout)
Clears all of the widgets from the old layout.
QString m_currentFiles
The current file.
Definition LoadDialog.h:88
A specialized class for dealing with file properties.
A property class for masking the properties.
The concrete, templated class for properties.
Base class for properties.
Definition Property.h:94
const std::string & documentation() const
Get the property's documentation string.
Definition Property.cpp:78
const std::string & name() const
Get the property's name.
Definition Property.cpp:63
virtual std::vector< std::string > allowedValues() const
Returns the set of valid values for this property, if such a set exists.
Definition Property.cpp:155
virtual std::string value() const =0
Returns the value of the property as a string.