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 <QDesktopWidget>
17#include <QFileInfo>
18#include <QScreen>
19#include <QUrl>
20
21// Mantid
28
29using namespace Mantid::API;
30using namespace Mantid::Kernel;
32
34namespace {
37struct HoldFlag {
38 HoldFlag(bool &current, const bool holdValue) : initial(current), heldflag(current) { heldflag = holdValue; }
39 ~HoldFlag() { heldflag = initial; }
40 bool initial;
41 bool &heldflag;
42};
43} // namespace
44
45// Declare the dialog. Name must match the class name
46DECLARE_DIALOG(LoadDialog)
47
48//--------------------------------------------------------------------------
49// Public methods
50//---------------------------------------------------------------------------
51
52
53LoadDialog::LoadDialog(QWidget *parent)
54 : API::AlgorithmDialog(parent), m_form(), m_currentFiles(), m_initialHeight(0), m_populating(false),
55 m_userAccept(false) {
56 // We will handle parsing the input ourselves on startup
57 m_autoParseOnInit = false;
58}
59
60//--------------------------------------------------------------------------
61// Private methods (slot)
62//---------------------------------------------------------------------------
63
68 HoldFlag hold(m_populating, true);
69
70 m_form.fileWidget->blockSignals(true);
72 m_form.fileWidget->blockSignals(false);
73}
74
77 const auto loaderName = getAlgorithm()->getPropertyValue("LoaderName");
78 QString helpPage = (loaderName.empty()) ? QString("Load") : QString::fromStdString(loaderName);
80}
81
88 if (!m_form.workspaceEdit->isEnabled())
89 return;
90
91 // suggest ws name based on file name
92 QString fileSuggestion;
93 if (m_form.fileWidget->isValid()) {
94 if (m_form.fileWidget->getFilenames().size() == 1)
95 fileSuggestion = QFileInfo(m_form.fileWidget->getFirstFilename()).completeBaseName();
96 else
97 fileSuggestion = "MultiFiles";
98 }
99 m_form.workspaceEdit->setText(fileSuggestion);
100}
101
108 if (on) {
109 connect(m_form.fileWidget, SIGNAL(filesFound()), this, SLOT(suggestWSName()));
110 } else {
111 disconnect(m_form.fileWidget, SIGNAL(filesFound()), this, SLOT(suggestWSName()));
112 }
113}
114
119 // If the LoadDialog is already loading data, or is populating, then ignore the accept
120 if (m_form.fileWidget->isSearching() || m_populating) {
121 return;
122 }
123 m_userAccept = true;
124 m_form.fileWidget->findFiles();
125}
126
128 if (!m_userAccept) {
129 return;
130 }
131 m_userAccept = false;
132
133 // Makes it so the dialog is still resizable if it is kept open
134 m_form.propertyLayout->setEnabled(true);
135
136 // Check that the file still exists just incase it somehow got removed
137 std::string errMess = getAlgorithm()->getPointerToProperty("Filename")->isValid();
138 if (!errMess.empty()) {
139 m_currentFiles = "";
141 } else {
142 AlgorithmDialog::accept();
143 }
144}
145
146//--------------------------------------------------------------------------
147// Private methods (non-slot)
148//---------------------------------------------------------------------------
149
152 m_form.setupUi(this);
153
154 // Add the helpful summary message
155 if (isMessageAvailable())
156 m_form.instructions->setText(getOptionalMessage());
157
158 m_form.dialogLayout->addLayout(this->createDefaultButtonLayout());
159 m_form.fileWidget->readSettings("Mantid/Algorithms/Load");
160 m_initialHeight = this->height();
161
162 const std::string &outWsName = getAlgorithm()->getPropertyValue("OutputWorkspace");
163 if (!outWsName.empty()) {
164 // OutputWorkspace name suggestion received as parameter, just take it and
165 // don't change it
166 m_form.workspaceEdit->setText(QString::fromStdString(outWsName));
167 } else {
168 // Guess at an output workspace name but only if the user hasn't changed
169 // anything
171 connect(m_form.workspaceEdit, SIGNAL(textEdited(const QString &)), this, SLOT(enableNameSuggestion()));
172 }
173
174 // Connect the file finder's file found signal to the dynamic property create
175 // method.
176 // When the file text is set the Load algorithm finds the concrete loader and
177 // then we
178 // know what extra properties to create
179 connect(m_form.fileWidget, SIGNAL(filesFound()), this, SLOT(createDynamicWidgets()));
180 connect(m_form.fileWidget, SIGNAL(fileInspectionFinished()), this, SLOT(resultInspectionFinished()));
181
182 tieStaticWidgets(true);
183}
184
189 m_form.fileWidget->saveSettings("Mantid/Algorithms/Load");
190 AlgorithmDialog::saveInput();
191 // Ensure the filename is store as the full file
192 API::AlgorithmInputHistory::Instance().storeNewValue("Load", QPair<QString, QString>("Filename", m_currentFiles));
193}
194
199void LoadDialog::tieStaticWidgets(const bool readHistory) {
200 // If a workspace validator asterisk exists, remove it since the underlying
201 // AlgorithmDialog gets confused
202 if (m_form.workspaceLayout->count() == 3) {
203 QLayoutItem *validLbl = m_form.workspaceLayout->takeAt(2);
204 delete validLbl->widget();
205 delete validLbl;
206 }
207 tie(m_form.workspaceEdit, "OutputWorkspace", m_form.workspaceLayout, readHistory);
208 tie(m_form.fileWidget, "Filename", nullptr, readHistory);
209}
210
215void LoadDialog::removeOldInputWidgets(QVBoxLayout *layout) {
216 // Remove the old widgets if necessary
217 if (layout->count() > 2) {
218 int count = layout->count();
219 while (count > 2) {
220 QLayoutItem *child = layout->takeAt(count - 1);
221 if (QWidget *w = child->widget()) {
222 w->deleteLater();
223 } else if (QLayout *l = child->layout()) {
224 QLayoutItem *subChild(nullptr);
225 while ((subChild = l->takeAt(0)) != nullptr) {
226 subChild->widget()->deleteLater();
227 }
228 }
229 count = layout->count();
230 }
231 }
232}
233
238 // Disable the layout so that a widget cannot be interacted with while it may
239 // be being deleted
240 m_form.propertyLayout->setEnabled(false);
241
242 if (!m_form.fileWidget->isValid())
243 return;
244 // First step is the get the specific loader that is responsible
245 auto loadAlg = getAlgorithm();
246 const QString filenames = m_form.fileWidget->getUserInput().toString();
247 if (filenames == m_currentFiles)
248 return;
249 m_currentFiles = filenames;
250 removeOldInputWidgets(m_form.propertyLayout); // The new file might be invalid
251 try {
252 loadAlg->setPropertyValue("Filename", filenames.toStdString());
253 } catch (std::exception &exc) {
254 m_form.fileWidget->setFileProblem(QString::fromStdString(exc.what()));
255 m_form.propertyLayout->setEnabled(true);
256 m_form.propertyLayout->activate();
257 this->resize(this->width(), m_initialHeight + 15);
258
259 // Reset the algorithm pointer so that the base class re-reads the
260 // properties and drops links from
261 // old widgets meaning they are safe to remove
262 setAlgorithm(loadAlg);
263 tieStaticWidgets(false); // The ties are cleared when resetting the
264 // algorithm
265
266 return;
267 }
268 // Reset the algorithm pointer so that the base class re-reads the properties
269 // and drops links from
270 // old widgets meaning they are safe to remove
271 setAlgorithm(loadAlg);
272 tieStaticWidgets(false); // The ties are cleared when resetting the algorithm
273 // Add the new ones
274 const std::vector<Property *> &inputProps = loadAlg->getProperties();
275 int dialogHeight = m_initialHeight;
276 for (auto prop : inputProps) {
277 const QString propName = QString::fromStdString(prop->name());
278 if (propName == "OutputWorkspace" || propName == "Filename")
279 continue;
280 if (requiresUserInput(propName)) {
281 dialogHeight += createWidgetsForProperty(prop, m_form.propertyLayout, m_form.scrollAreaWidgetContents);
282 }
283 }
284 // Re-enable and recompute the size of the layout
285 m_form.propertyLayout->setEnabled(true);
286 m_form.propertyLayout->activate();
287
288 const auto screenSize = screen()->availableSize();
289 const auto screenGeometry = screen()->availableGeometry();
290 dialogHeight = std::min(dialogHeight, static_cast<int>(screenSize.height() * 0.65));
291 this->resize(this->width(), dialogHeight);
292 const auto xPos = screenGeometry.x() + (screenSize.width() - this->width()) / 2;
293 const auto yPos = screenGeometry.y() + (screenSize.height() - this->height()) / 2;
294 this->move(xPos, yPos);
295
296 // Make sure the OutputWorkspace value has been stored so that the validator
297 // is cleared appropriately
298 QString wsName(m_form.workspaceEdit->text());
299 if (!wsName.isEmpty())
300 storePropertyValue("OutputWorkspace", wsName);
301 setPropertyValues(QStringList("Filename"));
302}
303
310int LoadDialog::createWidgetsForProperty(const Mantid::Kernel::Property *prop, QVBoxLayout *propertyLayout,
311 QWidget *parent) {
312 QString propName = QString::fromStdString(prop->name());
313 QWidget *inputWidget(nullptr);
314 QHBoxLayout *widgetLayout(nullptr);
315 bool addValidator(true);
316
317 // Boolean properties use the name labels differently
318 if (const auto *fileType = dynamic_cast<const FileProperty *>(prop)) {
319 auto *fileFinder = new FileFinderWidget(parent);
320 inputWidget = fileFinder;
321 fileFinder->setLabelText(propName);
322 fileFinder->isForRunFiles(false);
323 fileFinder->isOptional(fileType->isOptional());
324 fileFinder->doMultiEntry(false);
325 addValidator = false;
326 propertyLayout->addWidget(inputWidget);
327 } else {
328 QLabel *nameLbl = new QLabel(propName, parent);
329 nameLbl->setToolTip(QString::fromStdString(prop->documentation()));
330 if (dynamic_cast<const PropertyWithValue<bool> *>(prop)) {
331 auto *checkBox = new QCheckBox(parent);
332 inputWidget = checkBox;
333 addValidator = false;
334 }
335 // Options box
336 else if (!prop->allowedValues().empty()) {
337 auto *optionsBox = new QComboBox(parent);
338 inputWidget = optionsBox;
339 std::vector<std::string> items = prop->allowedValues();
340 std::vector<std::string>::const_iterator vend = items.end();
341 for (std::vector<std::string>::const_iterator vitr = items.begin(); vitr != vend; ++vitr) {
342 optionsBox->addItem(QString::fromStdString(*vitr));
343 }
344 // Set current as visible
345 int index = optionsBox->findText(QString::fromStdString(prop->value()));
346 if (index >= 0)
347 optionsBox->setCurrentIndex(index);
348
349 addValidator = false;
350 }
351 // else render a text box
352 else {
353 auto *textBox = new QLineEdit(parent);
354 inputWidget = textBox;
355 if (dynamic_cast<const MaskedProperty<std::string> *>(prop)) {
356 textBox->setEchoMode(QLineEdit::Password);
357 }
358 }
359 nameLbl->setBuddy(inputWidget);
360 widgetLayout = new QHBoxLayout();
361 widgetLayout->addWidget(nameLbl);
362 widgetLayout->addWidget(inputWidget);
363 propertyLayout->addLayout(widgetLayout);
364 }
365
366 if (addValidator)
367 tie(inputWidget, propName, widgetLayout);
368 else
369 tie(inputWidget, propName, nullptr);
370
371 return inputWidget->geometry().height();
372}
373} // 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:76
const std::string & name() const
Get the property's name.
Definition Property.cpp:61
virtual std::vector< std::string > allowedValues() const
Returns the set of valid values for this property, if such a set exists.
Definition Property.cpp:152
virtual std::string value() const =0
Returns the value of the property as a string.